%% ---------------------------------------------------------------------------
%% @doc 跨服多人副本大厅进程
%% @author zengzy
%% @since  2019-03-26
%% ---------------------------------------------------------------------------
-module(mod_dun_multi_hall_cluster).

-behaviour(gen_server).

%% API
-export([
    start_link/2                %% 启动跨服多人副本大厅进程
    ,call/3                     %% call跨服多人副本大厅进程
    ,cast/2                     %% cast跨服多人副本大厅进程
    ,clear_multi_team/3
    ]).

%% gen_server callbacks
-export([
    init/1
    ,handle_call/3
    ,handle_cast/2
    ,handle_info/2
    ,terminate/2
    ,code_change/3
]).

-export([
    join_team/2
    ,dun_multi_vote/3
    ,team_mate_vote/4
    ,join_team_request/2
    ,reply_to_req_roles/3
    ,change_approve_state/4
    ,change_team_target/6
    ,team_target_changed/4
    ,change_help_type/4
    ,change_merge_type/5
    ]).

-include("dungeon.hrl").
-include("dungeon_multi.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("predefine.hrl").
-include("def_fun.hrl").
-include("fake_role.hrl").
-include("team.hrl").
-include("server.hrl").
-include("transform.hrl").

%% ---------------------------------------------------------------------------
%% @doc call跨服多人副本大厅进程
-spec call(Pid, Msg, Time) -> term() when
    Pid     :: pid(),
    Msg     :: term(),
    Time    :: integer().
%% ---------------------------------------------------------------------------
call(Pid, Msg, Time) ->
    gen_server:call(Pid, Msg, Time).


%% ---------------------------------------------------------------------------
%% @doc cast跨服多人副本大厅进程
-spec cast(Pid, Msg) -> ok when
    Pid     :: pid(),
    Msg     :: term().
%% ---------------------------------------------------------------------------
cast(Pid, Msg) ->
    gen_server:cast(Pid, Msg).


%% ---------------------------------------------------------------------------
%% @doc Starts the server
-spec start_link(DunId, DunType) -> {ok, Pid} | ignore | {error, Error} when
    DunId   :: integer(),
    DunType :: integer(),
    Pid     :: pid(),
    Error   :: term().
%% ---------------------------------------------------------------------------
start_link(DunId, DunType) ->
    gen_server:start_link({global, {?MODULE, DunId}}, ?MODULE, [DunId, DunType], []).


%% ---------------------------------------------------------------------------
%% @doc Initializes the server
-spec init(Args) ->
    {ok, State}
    | {ok, State, Timeout}
    | ignore
    | {stop, Reason} when
    Args    :: term() ,
    State   :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason  :: term().
%% ---------------------------------------------------------------------------
init([Id, DunType]) ->
    process_flag(trap_exit, true),
    DunPidInfo = #dun_multi_hall_pid{id = Id, dun_type = DunType, pid = self()},
    ets:insert(?DUN_MULTI_HALL_PID_ETS, DunPidInfo),
    Ref = case lists:member(DunType, ?MATCH_DUNGEON) of
        true -> erlang:send_after(?MATCH_TIME, self(), {match_dummy});
        false -> undefined
    end,
    {ok, #state{id = Id, match_ref = Ref}}.


%% ---------------------------------------------------------------------------
%% @doc Handling call messages
-spec handle_call(Request, From, State) ->
    {reply, Reply, State}
    | {reply, Reply, State, Timeout}
    | {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, Reply, State}
    | {stop, Reason, State} when
    Request :: term(),
    From :: pid() | {pid(), Tag},
    Tag :: term(),
    State :: #state{},
    Reply :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity.
%% ---------------------------------------------------------------------------
handle_call(Request, From, State) ->
    case catch do_handle_call(Request, From, State) of
        {reply, Reply, NewState} ->
            {reply, Reply, NewState};
        Reason ->
            ?ERR("handle_call Request: ~p, Reason=~p~n", [Request, Reason]),
            {reply, error, State}
    end.

%% 创建组队
do_handle_call({create_team, MultiTeam, NewMember, TeamHandle, IsFirst}, _From, State) ->
    Reply = create_team(MultiTeam, NewMember, TeamHandle, IsFirst),
    {reply, Reply, State};
%% 加入多人副本组队
do_handle_call({join_team, Member, TeamId}, _From, State) ->
    Reply = join_team(Member, TeamId),
    {reply, Reply, State};
%% 匹配加入队伍
do_handle_call({match_join_team, DunId, Member, IsFirst}, _From, State) ->
    Reply = match_join_team(DunId, Member, IsFirst),
    {reply, Reply, State};
%% 连续讨伐匹配
do_handle_call({match_join_crusade_team, SubType, Member, IsFirst}, _, State) ->
    Reply = match_join_crusade_team(SubType, Member, IsFirst),
    {reply, Reply, State};
do_handle_call({apply_call, Mod, Func, Args}, _From, State) ->
    Reply = Mod:Func(Args),
    {reply, Reply, State};
do_handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.


%% ---------------------------------------------------------------------------
%% @doc Handling cast messages
-spec handle_cast(Msg, State) ->
    {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, State} when
    Msg :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason :: term().
%% ---------------------------------------------------------------------------
handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State)of
        {noreply, NewState} ->
            {noreply, NewState};
        Reason ->
            ?ERR("handle_cast Msg: ~p~n, Reason: ~p~n",[Msg, Reason]),
            {noreply, State}
    end.

%% 查询多人副本队伍列表
do_handle_cast({send_dun_teams, Node, RoleSid, DunId}, State) ->
    TeamSubL = case ets:lookup(?DUN_MULTI_HALL_ETS, State#state.id) of
        [#dun_multi_room{teams = Teams}] -> Teams;
        _ -> []
    end,
    TeamL = ets:tab2list(?DUN_MULTI_TEAM_ETS),
    TeamSubList = pack_dun_teams(DunId, TeamSubL, TeamL),
    % ?PRINT("~p~n",[TeamSubList]),
    {ok, Bin} = pt_215:write(21501, [DunId, TeamSubList]),
    lib_server_send:send_to_sid(Node, RoleSid, Bin),
    {noreply, State};
%% 离开多人副本组队
do_handle_cast({leave_team, RoleKey, TeamId}, State) ->
    leave_team_logic(RoleKey, TeamId),
    {noreply, State};
%% 踢出成员
do_handle_cast({kick_out, RoleKey, RoleSid, MemberKey, TeamId}, State) ->
    kick_out_logic(RoleKey, RoleSid, MemberKey, TeamId),
    {noreply, State};
%% 切换准备状态
do_handle_cast({change_ready_status, RoleKey, RoleSid, TeamId, IsReady}, State) ->
    change_ready_status_logic(RoleKey, RoleSid, TeamId, IsReady),
    {noreply, State};
%% 开启多人副本
do_handle_cast({start_dun_multi, RoleKey, RoleSid, TeamId}, State) ->
    start_dun_multi(RoleKey, RoleSid, TeamId),
    {noreply, State};
%% 同步次数和状态
do_handle_cast({sync_times, RoleKey, TeamId, HelpType, AddNum, DailyNum, HelpNum}, State) ->
    sync_times(RoleKey, TeamId, HelpType, AddNum, DailyNum, HelpNum),
    {noreply, State};
%% 同步队伍状态
do_handle_cast({change_team_state, TeamId, DunId, Type}, State) ->
    change_team_state(TeamId, DunId, Type),
    {noreply, State};
%% 队伍修改匹配状态
do_handle_cast({match_handle_team, TeamId, RoleId, Node, Type, IsFirst}, State) ->
    match_handle_team(TeamId, RoleId, Node, Type, IsFirst),
    {noreply, State};
%% 切回游戏服
% do_handle_cast({to_server_target, {RoleId}, Node, TeamId, ActivityId, SubTypeId, SceneId, LvMin, LvMax, Power}, State) ->
%     to_server_target(RoleId, Node, TeamId, ActivityId, SubTypeId, SceneId, LvMin, LvMax, Power),
%     {noreply, State};
%% 修改设置
do_handle_cast({update_set_info, {RoleId}, Node, TeamId, MinLv, Power, Password}, State) ->
    update_set_info(RoleId, Node, TeamId, MinLv, Power, Password),
    {noreply, State};
%% 委任队长
do_handle_cast({change_leader, {RoleId}, Node, TeamId, ToId}, State) ->
    change_leader(RoleId, Node, TeamId, ToId),
    {noreply, State};
%% 催促队长
do_handle_cast({prompt_enter, {RoleId}, Node, TeamId}, State) ->
    prompt_enter(RoleId, Node, TeamId),
    {noreply, State};
%% 婚姻改变修改伴侣id
do_handle_cast({update_role_attr, TeamId, RoleId, KeyList}, State) ->
    update_role_attr(TeamId, RoleId, KeyList),
    {noreply, State};
%% 检测重复队伍
do_handle_cast({check_team, DunId}, State) ->
    check_team(DunId),
    {noreply, State};
%% 加入队伍请求超时失败操作
do_handle_cast({team_fail_handle, _DunId, Node, RoleId}, State) ->
    team_fail_handle(State#state.id, Node, RoleId),
    {noreply, State};
%% 进入队伍成功后去掉同目标老队伍
do_handle_cast({del_old_team, Member, TeamId}, State) ->
    del_old_team(Member, TeamId, State#state.id),
    {noreply, State};
do_handle_cast({del_old_req_from_team, TeamId, RoleId}, State) ->
    del_old_req(TeamId, RoleId),
    {noreply, State};
do_handle_cast({update_team_mate_action_lock, TeamId, RoleId, ActionLock}, State) ->
    update_team_mate_action_lock(TeamId, RoleId, ActionLock),
    {noreply, State};
do_handle_cast({apply_cast, Mod, Func, Args}, State) ->
    apply(Mod, Func, Args),
    {noreply, State};
do_handle_cast(_Msg, State) ->
    {noreply, State}.

%% ---------------------------------------------------------------------------
%% @doc Handling all non call/cast messages
-spec handle_info(Info, State) ->
    {noreply, State}
    | {noreply, State, Timeout}
    | {stop, Reason, State} when
    Info :: term(),
    State :: #state{},
    Timeout :: non_neg_integer() | infinity,
    Reason :: term().
%% ---------------------------------------------------------------------------
handle_info(Info, State) ->
    case catch do_handle_info(Info, State)of
        {noreply, NewState} ->
            {noreply, NewState};
        Reason ->
            ?ERR("handle_info error: ~p, Reason:=~p~n",[Info, Reason]),
            {noreply, State}
    end.

do_handle_info({match_dummy}, State) ->
    #state{id = DunId, match_ref = Ref} = State,
    match_dummy(DunId),
    NewRef = util:send_after(Ref, ?MATCH_TIME, self(), {match_dummy}),
    {noreply, State#state{match_ref = NewRef}};
do_handle_info({first_match_dummy, TeamId}, State) ->
    first_match_dummy(TeamId),
    {noreply, State};
do_handle_info({vote_end, TeamId, RoleKey}, State) ->
    vote_end_logic(TeamId, RoleKey),
    {noreply, State};
do_handle_info(_Info, State) ->
    {noreply, State}.


%% ---------------------------------------------------------------------------
%% @doc called by a gen_server when it is about to terminate
-spec terminate(Reason, State) -> ok when
    Reason :: term(),
    State :: #state{}.
%% ---------------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.


%% ---------------------------------------------------------------------------
%% @doc Convert process state when code is changed
-spec code_change(OldVsn, State, Extra) -> {ok, NewState} when
    OldVsn :: term(),
    State :: #state{},
    Extra :: term(),
    NewState :: #state{}.
%% ---------------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%% -------------------创建队伍-----------------
create_team(MultiTeam, Member, TeamHandle, IsFirst) ->
    TeamId = mod_dun_multi_mgr_cluster:get_team_id(),
    MaxNum = lib_dun_multi:get_max_num(MultiTeam#dun_multi_team.dun_id),
    case IsFirst == 1 of
        true ->
            IsMatch = 1,
            MatchTime = utime:unixtime(),
            Ref = erlang:send_after(?FIRST_TIME * 1000, self(), {first_match_dummy, TeamId});
        false ->
            IsMatch = MultiTeam#dun_multi_team.is_match,
            MatchTime = MultiTeam#dun_multi_team.match_time,
            Ref = undefined
    end,
    NewMultiTeam = MultiTeam#dun_multi_team{
        id = TeamId, members = [Member], handle_mb = TeamHandle,
        max_num = MaxNum, first_ref = Ref, is_match = IsMatch,
        match_time = MatchTime
    },
    update_team_to_ets(MultiTeam, NewMultiTeam),
    lib_dun_multi_cluster:broadcast_team_info(NewMultiTeam),
    cast(self(), {del_old_team, Member, TeamId}),
    {ok, TeamId}.

%% -------------------加入组队-------------------
join_team(Member, TeamId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members, dun_id = DunId, handle_mb = {AllowIds, Time}, is_match = IsMatch, 
        max_num = MaxNum, vote_ref = VoteRef, req_list = ReqList}] ->
            case length(Members) >= MaxNum of
                false ->
                    util:cancel_timer(VoteRef),
                    #dun_multi_member{id = RoleId, is_dummy = IsDummy} = Member,
                    NewMembers = [Member | Members],
                    NewTeamHandle = {lists:delete(RoleId, AllowIds), Time},
                    NewMemberLen = length(NewMembers),
                    if NewMemberLen >= MaxNum ->
                            NewIsMatch = 0,
                            delete_team_req(TeamId, ReqList),
                            NewTeam = Team#dun_multi_team{
                                members = NewMembers, handle_mb = NewTeamHandle, req_list = [], is_match = NewIsMatch, vote_ref = undefined, vote_list = {[], []}};
                        true ->
                            NewIsMatch = IsMatch,
                            NewTeam = Team#dun_multi_team{members = NewMembers, handle_mb = NewTeamHandle, is_match = IsMatch, vote_ref = undefined, vote_list = {[], []}}
                    end,
                    update_team_to_ets(Team, NewTeam),
                    lib_dun_multi_cluster:broadcast_team_info(NewTeam),
                    % auto_start_dun_multi(NewTeam),
                    NewIsMatch =/= IsMatch andalso  [lib_player:apply_cast(MemberNode, MemberId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, update_team_match, [NewIsMatch]) 
                        || #dun_multi_member{id = MemberId, node = MemberNode} <- NewMembers],
                    %% 只有真人加入才需要退出旧队伍
                    IsDummy == ?DUN_REAL andalso cast(self(), {del_old_team, Member, TeamId}),
                    case data_dun_multi_team:get_dun_act_type(DunId) of
                        ?ACT_TYPE_CRUSADE ->
                            {ok, DunId, NewIsMatch};
                        _ ->
                            {ok, NewIsMatch}
                    end;
                true ->
                    {false, ?ERRCODE(err215_team_max_member)}
            end;
        _ ->
            {false, ?ERRCODE(err215_no_team)}
    end.

%% ---------------------投票相关-------------------------
%% 发起投票
dun_multi_vote(DunMultiTeam, RoleNode, RoleId) ->
    #dun_multi_team{id = TeamId, members = Members, dun_id = DunId} = DunMultiTeam,
    DunType = data_dungeon:get_dun_type(DunId),
    VoteTime = data_dungeon_special:get(DunType, vote_time),
    lib_server_send:send_to_uid(RoleNode, RoleId, pt_215, 21530, [?SUCCESS, TeamId]),
    lists:map(fun(#dun_multi_member{node = Node, id = MemberId, is_dummy = IsDummy}) ->
        IsDummy == ?DUN_REAL andalso clusters_center:apply_cast(Node, lib_dun_multi, dun_multi_vote_broad, [MemberId, TeamId, VoteTime])
    end, Members),
    spawn(fun() -> 
        timer:sleep(600),
        {DummyVotes, RealMembers} =
        lists:foldl(fun(#dun_multi_member{node = NodeX, id = MemberIdX, is_dummy = IsDummy}, {Dummys, Reals}) -> 
            if IsDummy == ?DUN_REAL -> {Dummys, [{NodeX, MemberIdX}|Reals]};
                true -> {ok, BinData} = pt_215:write(21533, [MemberIdX, 1]), {[BinData|Dummys], Reals}
            end
        end, {[], []}, Members),
        lists:map(fun(BinData1) -> 
            [lib_server_send:send_to_uid(NodeX1, RoleIdX1, BinData1) || {NodeX1, RoleIdX1} <- RealMembers]
        end, DummyVotes)
         end),
    VoteRef = erlang:send_after(VoteTime*1000, self(), {vote_end, TeamId, RoleId}),
    NewDunMultiTeam = DunMultiTeam#dun_multi_team{vote_ref = VoteRef, is_match = 0},
    update_team_to_ets(DunMultiTeam, NewDunMultiTeam),
    ok.

%% 队员投票
team_mate_vote(DunMultiTeam, _Node, RoleId, VoteRet) ->
    #dun_multi_team{vote_list = {AgreeList, DisAgreeList}, vote_ref = VoteRef, members = MemberList} = DunMultiTeam,
    {ok, BinData} = pt_215:write(21533, [RoleId, VoteRet]),
    lib_dun_multi_cluster:send_to_team(MemberList, BinData),
    if VoteRet == 0 -> %% 有人反对取消投票进副本
            util:cancel_timer(VoteRef),
            NewDunMultiTeam = DunMultiTeam#dun_multi_team{vote_ref = undefined, vote_list = {[], []}},
            {ok, BinData1} = pt_215:write(21535, []),
            lib_dun_multi_cluster:send_to_team(MemberList, BinData1),
            update_team_to_ets(DunMultiTeam, NewDunMultiTeam);
        true -> %% 投赞成票检查投票情况
            NewAgreeList = [RoleId|AgreeList],
            NewDunMultiTeam = DunMultiTeam#dun_multi_team{vote_list = {NewAgreeList, DisAgreeList}},
            DummyLen = length([1 || #dun_multi_member{is_dummy = IsDummy} <- MemberList, IsDummy == 1 orelse IsDummy == 2]),
            AgreeLen = length(NewAgreeList) + DummyLen,
            MemberLen = length(MemberList),
            if 
                AgreeLen >= MemberLen ->
                    util:cancel_timer(VoteRef),
                    NewDunMultiTeam1 = NewDunMultiTeam#dun_multi_team{is_match = 0, vote_ref = undefined},
                    update_team_to_ets(DunMultiTeam, NewDunMultiTeam1),
                    start_dun_multi_do(NewDunMultiTeam1, {}, 0);
                true ->
                    update_team_to_ets(DunMultiTeam, NewDunMultiTeam)
            end
    end,
    ok.

%% 投票超时,强制开启
vote_end_logic(TeamId, RoleKey) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{vote_ref = VoteRef}|_] ->
            util:cancel_timer(VoteRef),
            NewTeam = Team#dun_multi_team{is_match = 0, vote_ref = undefined},
            update_team_to_ets(Team, NewTeam),
            start_dun_multi_do(NewTeam, RoleKey, 0);
        _ -> %% 找不到队伍
            ok
    end.

%% 队伍变更广播投票取消
team_change_vote_notice(Members) ->
    {ok, BinData} = pt_215:write(21535, []),
    lib_dun_multi_cluster:send_to_team(Members, BinData),
    ok.

is_in_vote(VoteRef) ->
    if VoteRef == undefined -> false;
        true -> 
            LastTime = erlang:read_timer(VoteRef),
            if LastTime > 0 -> true;
                true -> false
            end
    end.

%% -------------------队员下线取消申请列表---------------------
del_old_req(TeamId, RoleId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{req_list = ReqList}|_] ->
            NewReqList = lists:keydelete(RoleId, #dun_multi_member.id, ReqList),
            NewTeam = Team#dun_multi_team{req_list = NewReqList},
            update_team_to_ets(Team, NewTeam);
        _ ->
            ok
    end.

%% -------------------队长回应申请操作----------------------
reply_to_req_roles(Team, ReqList, _RoleId) ->
    #dun_multi_team{id = TeamId, sub_type_dun = EnterDunId, dun_id = DunId, req_list = AllReqList, 
        max_num = MaxNum, vote_ref = VoteRef, is_match = IsMatch} = Team,
    IsInVote = is_in_vote(VoteRef),
    if 
        IsInVote ->
            Team;
        true ->
            {NewJoin, DisAgreeList, NewReqList} = 
            lists:foldl(fun({AgreeOperation, RoleIdX}, {Join, Del, TempReqList}) -> 
                case lists:keyfind(RoleIdX, #dun_multi_member.id, TempReqList) of
                    Member = #dun_multi_member{node = DisAgreeNode} ->
                        NewTempReqList = lists:keydelete(RoleIdX, #dun_multi_member.id, TempReqList),
                        if AgreeOperation == 1 -> %% 同意申请
                                {[Member|Join], Del, NewTempReqList};
                            true -> %% 拒绝申请
                                {Join, [{AgreeOperation, DisAgreeNode, RoleIdX}|Del], NewTempReqList}
                        end;
                    _ ->
                        {Join, [{AgreeOperation, undefined, RoleIdX}|Del], TempReqList}
                end
            end, {[], [], AllReqList}, ReqList),
            {NewTeam, NewHaveJoined} = lists:foldl(fun(MemberX, {TempTeamData, HaveJoined}) ->
                #dun_multi_team{handle_mb = {AllowIds, Time}, members = Members} = TempTeamData,
                MemberLen = length(Members),
                if MemberLen >= MaxNum ->
                        {TempTeamData, HaveJoined};
                    true ->
                        #dun_multi_member{id = RoleIdX1, is_dummy = IsDummy1} = MemberX,
                        NewMembers = [MemberX | Members],
                        NewTeamHandle = {lists:delete(RoleIdX1, AllowIds), Time},
                        NewIsMatch = ?IF(length(NewMembers) >= MaxNum, 0, TempTeamData#dun_multi_team.is_match),
                        NewTempTeamData = TempTeamData#dun_multi_team{
                            members = NewMembers, handle_mb = NewTeamHandle, is_match = NewIsMatch},
                        IsDummy1 == ?DUN_REAL andalso cast(self(), {del_old_team, MemberX, TeamId}),
                        {NewTempTeamData, [MemberX|HaveJoined]}
                end
            end, {Team, []}, NewJoin),
            #dun_multi_team{is_match = NewIsMatch1} = NewTeam,
            %% 通知队员更新队伍状态
            [lib_player:apply_cast(RoleNodeX2, RoleIdX2, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE,
                lib_dun_multi, role_approved_join_team, [TeamId, EnterDunId, DunId, NewIsMatch1, HelpTypeX])
             || #dun_multi_member{id = RoleIdX2, node = RoleNodeX2, is_dummy = IsDummyX, help_type = HelpTypeX} <- NewHaveJoined, IsDummyX == ?DUN_REAL],
            [lib_player:apply_cast(DisAgreeNode1, DisAgreeRoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_deleted_req_list, [TeamId]) || {_, DisAgreeNode1, DisAgreeRoleId} <- DisAgreeList, DisAgreeNode1 =/= undefined],
            util:cancel_timer(VoteRef),
            NewTeam1 = NewTeam#dun_multi_team{vote_ref = undefined, vote_list = {[], []}, req_list = NewReqList},
            NewIsMatch1 =/= IsMatch andalso
                [lib_player:apply_cast(MemberNode, MemberId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, update_team_match, [NewIsMatch1]) 
                || #dun_multi_member{id = MemberId, node = MemberNode, is_dummy = IsDummyX1} <- NewTeam1#dun_multi_team.members, IsDummyX1 == ?DUN_REAL],
            update_team_to_ets(Team, NewTeam1),
            ApproveList1 = [{1, JoinRoleId} || #dun_multi_member{id = JoinRoleId} <- NewHaveJoined],
            ApproveList2 = [{0, DisAgreeRoleId1} || {_, _, DisAgreeRoleId1} <- DisAgreeList],
            {ok, BinData} = pt_215:write(21537, [?SUCCESS, ApproveList1 ++ ApproveList2]),
            lib_dun_multi_cluster:send_to_team(NewTeam1#dun_multi_team.members, BinData),
            lib_dun_multi_cluster:broadcast_team_info(NewTeam1)
    end,
    ok.

%% -------------------队长修改审批状态-----------------
change_approve_state(DunMultiTeam, Node, RoleId, Approve) ->
    NewDunMultiTeam = DunMultiTeam#dun_multi_team{need_approve = Approve},
    update_team_to_ets(DunMultiTeam, NewDunMultiTeam),
    {ok, BinData} = pt_215:write(21538, [?SUCCESS, Approve]),
    lib_server_send:send_to_uid(Node, RoleId, BinData),
    ok.

%% -------------------队长切换队伍目标------------------
change_team_target(DunMultiTeam, _Node, RoleId, EnterDunId, DunId, Approve) ->
    #dun_multi_team{id = TeamId, members = Members, is_match = OldIsMatch, first_ref = FirstRef, vote_ref = VoteRef} = DunMultiTeam,
    util:cancel_timer(VoteRef),
    util:cancel_timer(FirstRef),
    NewIsMatch = 0,
    NewDunMultiTeam = DunMultiTeam#dun_multi_team{sub_type_dun = EnterDunId, is_match = NewIsMatch, dun_id = DunId, vote_ref = undefined, vote_list = {[], []}},
    NewIsMatch =/= OldIsMatch andalso begin
        lib_dun_multi_cluster:team_broadcast_notify(0, Members, {RoleId}, ?DUNMULTITEAM_NOTIFY_MATCH, NewIsMatch),
        [lib_player:apply_cast(MemberNode, MemberId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, update_team_match, [NewIsMatch]) 
        || #dun_multi_member{id = MemberId, node = MemberNode, is_dummy = IsDummyX1} <- Members, IsDummyX1 == ?DUN_REAL] end,
    %% 修改ETS的数据
    change_team_to_ets(DunMultiTeam, NewDunMultiTeam),
    {ok, BinData} = pt_215:write(21534, [?SUCCESS, EnterDunId, Approve]),
    % ProData = lib_dun_multi_cluster:pack_team_info(NewDunMultiTeam),
    % {ok, BinData1} = pt_215:write(21504, ProData),
    lib_dun_multi_cluster:send_to_team(Members, BinData),
    change_team_target_notice(Members, TeamId, DunId),
    {ok, DunId}.

change_team_target_notice(Members, TeamId, DunId) ->
    lists:map(fun(#dun_multi_member{id = MemberId, server_id = SvrId, is_leader = IsLeader}) ->
        if IsLeader == 0 -> 
                clusters_center:apply_cast(SvrId, ?MODULE, team_target_changed, [TeamId, DunId, IsLeader, MemberId]);
            true ->
                skip
        end
    end, Members),
    ok.

team_target_changed(TeamId, DunId, IsLeader, MemberId) ->
    % lib_player:apply_cast(MemberId, ?APPLY_CAST_STATUS, ?MODULE, role_team_target_changed, [TeamId, DunId, IsLeader]),
    lib_player:apply_cast(MemberId, ?APPLY_CAST_STATUS, lib_dun_multi, role_change_team_target, [TeamId, DunId, IsLeader]),
    ok.

%% -------------------队员状态行为变更----------------------
update_team_mate_action_lock(TeamId, RoleId, ActionLock) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members}] ->
            case lists:keytake(RoleId, #dun_multi_member.id, Members) of
                {value, Member = #dun_multi_member{}, LessMembers} ->
                    ActionLock1 = if ActionLock == free -> 0; 
                        true -> ActionLock 
                    end,
                    NewMembers = [Member#dun_multi_member{action_lock = ActionLock1}|LessMembers],
                    update_team_to_ets(Team, Team#dun_multi_team{members = NewMembers}),
                    ok;
                false ->
                    ok
            end;
        _ -> ok
    end.

%% -------------------修改助战状态------------------------
change_help_type(DunMultiTeam, _Node, RoleId, HelpType) ->
    #dun_multi_team{members = Members} = DunMultiTeam,
    case lists:keytake(RoleId, #dun_multi_member.id, Members) of
        {value, Member = #dun_multi_member{}, LessMembers} ->
            NewMembers = [Member#dun_multi_member{help_type = HelpType}|LessMembers],
            update_team_to_ets(DunMultiTeam, DunMultiTeam#dun_multi_team{members = NewMembers}),
            ok;
        _ ->
            ok
    end.

%% -------------------修改合并次数状态----------------------
change_merge_type(DunMultiTeam, _Node, RoleId, MergeType, RestTime) ->
    #dun_multi_team{members = Members} = DunMultiTeam,
    case lists:keytake(RoleId, #dun_multi_member.id, Members) of
        {value, Member = #dun_multi_member{typical_data = TypicalData}, LessMembers} ->
            TypicalData1 = maps:put(?DUN_ROLE_COUNT_MERGE, MergeType, TypicalData),
            if MergeType =< 0 ->
                    TypicalData2 = maps:put(?DUN_ROLE_DAILY_ENTER_COUNT, 1, TypicalData1);
                true ->
                    TypicalData2 = maps:put(?DUN_ROLE_DAILY_ENTER_COUNT, RestTime, TypicalData1)
            end,
            NewMembers = [Member#dun_multi_member{typical_data = TypicalData2}|LessMembers],
            update_team_to_ets(DunMultiTeam, DunMultiTeam#dun_multi_team{members = NewMembers}),
            ok;
        _ ->
            ok
    end.

%% -------------------队员离开组队------------------
leave_team_logic({RoleId} = RoleKey, TeamId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members, dun_id = DunId}] ->
            case lists:keytake(RoleId, #dun_multi_member.id, Members) of
                {value, #dun_multi_member{}, []} -> %% 最后一个队员离开
                    team_change_vote_notice(Members),
                    dismiss_team(TeamId, DunId);
                {value, #dun_multi_member{is_leader = IsLeader}, LessMembers} ->
                    team_change_vote_notice(Members),
                    do_leave_team_logic(DunId, Team, RoleKey, IsLeader, LessMembers);
                false ->
                    ok
            end;
        _ ->
            ok
    end.

do_leave_team_logic(DunId, Team, RoleKey, IsLeader, LessMembers) ->
    #dun_multi_team{id = TeamId, is_start = IsStart, vote_ref = VoteRef} = Team,
    NewMembers = case IsLeader of
        1 -> leave_select_leader(TeamId, DunId, LessMembers);
        _ -> LessMembers
    end,
    util:cancel_timer(VoteRef),
    case NewMembers of
        [] -> %% 无人符合条件或者没人 
            dismiss_team(TeamId, DunId),
            DunType = data_dungeon:get_dun_type(DunId),
            [begin
                Member#dun_multi_member.is_dummy == ?DUN_MIRROR andalso IsStart == 0 andalso
                    clusters_center:apply_cast(
                        Member#dun_multi_member.server_id, lib_dungeon_guard, local_increment_guard_assist_count, [Member#dun_multi_member.id, DunType]),
                member_quit_team(TeamId, Member) 
            end || Member <- LessMembers],
            {ok, BinData} = pt_215:write(21506, [1]),
            lib_dun_multi_cluster:send_to_team(LessMembers, BinData);
        LeftMembers ->
            % NewMemberNum = length(LeftMembers),
            NewTeam = Team#dun_multi_team{members = LeftMembers, vote_ref = undefined, vote_list = {[], []}},
            update_team_to_ets(Team, NewTeam),
            lib_dun_multi_cluster:team_broadcast_notify(DunId, NewMembers, RoleKey, ?DUNMULTITEAM_NOTIFY_LEAVE, 0)
    end.

% leave_select_leader(DunId, Members) ->
%     case lists:keytake(0, #dun_multi_member.is_dummy, Members) of
%         {value, #dun_multi_member{id = RoleId} = Member, LessMembers} ->
%             lib_dun_multi_cluster:team_broadcast_notify(0, Members, {RoleId}, ?DUNMULTITEAM_NOTIFY_CHANGE_LEADER, 0),
%             NewMember = Member#dun_multi_member{is_leader = 1, is_ready = 1},
%             [NewMember | LessMembers];
%         false -> []
%     end.

leave_select_leader(TeamId, DunId, Members) ->
    #dun_cfg{type = DunType, count_cond = CountCond} = data_dungeon:get_dun(DunId),
    case lists:keyfind(?DUN_COUNT_COND_DAILY, 1, CountCond) of
        {_, MaxDailyCount} -> ok;
        _                  -> MaxDailyCount = 0
    end,
    % case lists:keyfind(?DUN_COUNT_COND_DAILY_HELP, 1, CountCond) of
    %     {_, MaxHelpCount} -> ok;
    %     _                 -> MaxHelpCount
    % end,
    case do_select_leader_logic(Members, MaxDailyCount) of
        NewMember = #dun_multi_member{node = Node, id = RoleId} ->
            lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_team_rela_change, [TeamId, DunId, 1]),
            lists:keystore(RoleId, #dun_multi_member.id, Members, NewMember);
        _ ->
            case lists:filter(fun(#dun_multi_member{help_type = HelpTypeX, daily_times = DailyCountX}) -> 
                HelpTypeX == ?DUN_TEAM_HELP_YES andalso DailyCountX < MaxDailyCount
            end, Members) of
                [Member = #dun_multi_member{node = RoleNode, id = RoleId1}|_] ->
                    NewMember = Member#dun_multi_member{is_leader = 1, is_ready = 1, help_type = ?DUN_TEAM_HELP_NO},
                    lib_player:apply_cast(RoleNode, RoleId1, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_team_rela_change, [TeamId, DunId, 1]),
                    lib_server_send:send_to_uid(RoleNode, RoleId1, pt_215, 21540, [?SUCCESS, DunType, ?DUN_TEAM_HELP_NO]),
                    lists:keystore(RoleId1, #dun_multi_member.id, Members, NewMember);
                _ ->
                    []
            end
    end.

do_select_leader_logic([], _) -> [];
do_select_leader_logic([#dun_multi_member{daily_times = DailyCount, is_dummy = IsDummy, help_type = HelpType} = Member|Rest], MaxDailyCount) ->
    if DailyCount >= MaxDailyCount orelse IsDummy =/= ?DUN_REAL orelse HelpType == ?DUN_TEAM_HELP_YES ->
            do_select_leader_logic(Rest, MaxDailyCount);
        true ->
            Member#dun_multi_member{is_leader = 1, is_ready = 1}
    end.

%% ---------------------踢出队员----------------------
kick_out_logic({RoleId}, RoleSid, {MemberId} = MemberKey, TeamId) ->
    {_, Code} = case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{is_start = 1}] -> {false, ?ERRCODE(err215_is_on_dungeon)};
        [Team = #dun_multi_team{members = Members, vote_ref = VoteRef}] ->
            Leader = lists:keyfind(RoleId, #dun_multi_member.id, Members),
            Member = lists:keyfind(MemberId, #dun_multi_member.id, Members),
            if
                Leader =:= false ->
                    {false, ?ERRCODE(err215_not_leader)};
                Member =:= false ->
                    {false, ?ERRCODE(err215_not_in_team)};
                Leader#dun_multi_member.is_leader =:= 0 ->
                    {false, ?ERRCODE(err215_not_leader)};
                true ->
                    NewMembers = lists:keydelete(
                        MemberId, #dun_multi_member.id, Members
                    ),
                    % NewLen = length(NewMembers),
                    % NewIsMatch = ?IF(NewLen < MaxNum, 1, 0),
                    NewTeam = Team#dun_multi_team{members = NewMembers, vote_ref = undefined, vote_list = {[], []}},
                    update_team_to_ets(Team, NewTeam),
                    member_quit_team(TeamId, Member),
                    util:cancel_timer(VoteRef),
                    Member#dun_multi_member.is_dummy == ?DUN_MIRROR andalso
                        clusters_center:apply_cast(Member#dun_multi_member.server_id, lib_dungeon_guard, local_increment_guard_assist_count, [Member#dun_multi_member.id, ?DUNGEON_TYPE_GUARD]),
                    lib_dun_multi_cluster:team_broadcast_notify(0, Members, MemberKey, ?DUNMULTITEAM_NOTIFY_KICK_OUT, 0),
                    % NewIsMatch =/= IsMatch andalso
                    %     lib_dun_multi_cluster:team_broadcast_notify(0, Members, MemberKey, ?DUNMULTITEAM_NOTIFY_MATCH, NewIsMatch),
                    team_change_vote_notice(Members),
                    {ok, ?SUCCESS}
            end;
        _ ->
            {false, ?ERRCODE(err215_no_team)}
    end,
    ProData = [Code, MemberId],
    lib_server_send:send_to_sid(RoleSid, pt_215, 21505, ProData),
    ok.

member_quit_team(_, #dun_multi_member{is_dummy = ?DUN_REAL} = Member) ->
    #dun_multi_member{id = RoleId, server_num = _ServerNum, node = Node} = Member,
    lib_dun_multi_cluster:apply_to_local_role(Node, lib_dun_multi, role_quit_multi_team, [RoleId]);
member_quit_team(TeamId, #dun_multi_member{is_dummy = ?DUN_MIRROR} = Member) ->
    #dun_multi_member{id = RoleId, node = Node} = Member,
    lib_dun_multi_cluster:apply_to_local_role(Node, lib_dun_multi, role_mirror_multi_team, [RoleId, TeamId]);
member_quit_team(_, _) -> ok.

%% ----------------------切换准备状态---------------------
change_ready_status_logic({RoleId} = RoleKey, RoleSid, TeamId, IsReady) ->
    {_, Code} = case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members}] ->
            case lists:keytake(RoleId, #dun_multi_member.id, Members) of
                {value, Member = #dun_multi_member{}, LessMembers} ->
                    NewMember = Member#dun_multi_member{is_ready = IsReady},
                    NewMembers = [NewMember | LessMembers],
                    NewTeam = Team#dun_multi_team{members = NewMembers},
                    update_team_to_ets(Team, NewTeam),
                    lib_dun_multi_cluster:team_broadcast_notify(0, NewMembers, RoleKey, ?DUNMULTITEAM_NOTIFY_IS_READY, IsReady),
                    % auto_start_dun_multi(NewTeam),
                    {ok, 1};
                false ->
                    {false, ?ERRCODE(err215_not_in_team)}
            end;
        _ ->
            {false, ?ERRCODE(err215_no_team)}
    end,
    {ok, Bin} = pt_215:write(21507, [Code, IsReady]),
    lib_server_send:send_to_sid(RoleSid, Bin),
    ok.

%% ---------------------入队申请---------------------------
join_team_request(Member, TeamId) ->
    [#dun_multi_team{dun_id = DunId, req_list = ReqList} = DunMultiTeam] = ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId),
    NewDunMultiTeam = DunMultiTeam#dun_multi_team{req_list = [Member|lists:keydelete(Member#dun_multi_member.id, #dun_multi_member.id, ReqList)]},
    lib_player:apply_cast(Member#dun_multi_member.node, Member#dun_multi_member.id,
     ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_update_req_list, [DunId, TeamId]),
    update_team_to_ets(DunMultiTeam, NewDunMultiTeam),
    ok.

%% ---------------------手动开启多人副本-------------------------
start_dun_multi({RoleId} = RoleKey, RoleSid, TeamId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team] -> ok;
        _ -> Team = false
    end,
    case check_start_dun_multi(Team, RoleId) of
        true ->
            NewTeam = Team#dun_multi_team{is_match = 0},
            update_team_to_ets(Team, NewTeam),
            start_dun_multi_do(NewTeam, RoleKey, 0);
        {false, ErrCode} ->
            {ok, Bin} = pt_215:write(21508, [ErrCode]),
            lib_server_send:send_to_sid(RoleSid, Bin);
        {false, _, ErrCode} ->
            {ok, Bin} = pt_215:write(21508, [ErrCode]),
            lib_server_send:send_to_sid(RoleSid, Bin)
    end,
    ok.

%%手动开启副本检测
check_start_dun_multi(#dun_multi_team{members = MemberList} = Team, RoleId) ->
    case lists:keyfind(RoleId, #dun_multi_member.id, MemberList) of
        #dun_multi_member{is_leader = 1} ->
            check_start_dun_multi_common(Team);
        _ -> {false, ?ERRCODE(err215_not_leader)}
    end;
check_start_dun_multi(_, _) -> {false, ?ERRCODE(err215_no_team)}.

%% 检查是否可以开启多人副本
% auto_start_dun_multi(Team) ->
%     #dun_multi_team{members = Members} = Team,
%     LeaderKey = case lists:keyfind(1, #dun_multi_member.is_leader, Members) of
%         #dun_multi_member{id = RoleId} -> {RoleId};
%         _ -> {0}
%     end,
%     case check_auto_start_dun_multi(Team) of
%         true ->
%             start_dun_multi_do(Team, LeaderKey, 500);
%         {false, _, ErrCode} ->
%             {ok, BinData} = pt_215:write(21513, [ErrCode]),
%             lib_dun_multi_cluster:send_to_team(Members, BinData);
%         _ -> ok
%     end.

%% 自动开始副本检测
% check_auto_start_dun_multi(Team) ->
%     #dun_multi_team{members = Members, is_auto_start = IsAuto, max_num = MaxNum} = Team,
%     IsFull = length(Members) >= MaxNum,
%     case {IsAuto, IsFull} of
%         {1, true} ->
%             check_start_dun_multi_common(Team);
%         {0, _} -> false;
%         {_, false} -> false
%     end.

%% 开启副本
start_dun_multi_do(Team, _LeaderKey, DelayTime) ->
    #dun_multi_team{id = TeamId, members = Members, dun_id = DunId, req_list = ReqList, 
        single_mode = SingleMode, power = PowerNeed} = Team,
    [begin 
        {ok, BinData} = pt_215:write(21509, [RoleId, ?DUNMULTITEAM_NOTIFY_MATCH, 0]),
        {ok, BinData1} = pt_215:write(21509, [RoleId, ?DUNMULTITEAM_NOTIFY_START_DUN, 1]),
        lib_server_send:send_to_uid(Node, RoleId, <<BinData/binary, BinData1/binary>>)
    end ||  #dun_multi_member{id = RoleId, node = Node, is_dummy = IsDummy} <- Members, IsDummy == 0],
    spawn(fun() -> start_dungeon([DelayTime, DunId, TeamId, Members, SingleMode, PowerNeed]) end),
    lib_dun_multi:delete_role_req_list(TeamId, ReqList),
    ets:insert(?DUN_MULTI_TEAM_ETS, Team#dun_multi_team{req_list = []}),
    ok.

start_dungeon([DelayTime, DunId, TeamId, TeamMembers0, SingleMode, PowerNeed|_]) ->
    timer:sleep(DelayTime),
    TeamMembers = leader_sort(TeamMembers0),
    F = fun(Member, {Index, TmpDummy, TmpRoles})->
        #dun_multi_member{is_dummy = IsDummy} = Member,
        case IsDummy == ?DUN_REAL of
            true ->  %% 真人
                Roles = lib_dun_multi:multi_member_to_dungeon_role(Member, DunId),
                {Index+1, TmpDummy, [Roles#dungeon_role{team_position = Index} | TmpRoles]};
            false -> %% 1假人|2玩家镜像
                {Index+1, [{Index, Member} | TmpDummy], TmpRoles}
        end
    end,
    {_, DummyList, DunRoles} = lists:foldl(F, {1, [], []}, TeamMembers),
    case data_dungeon:get_dun(DunId) of
        #dun_cfg{type = DunType} -> ok;
        _ -> DunType = 0
    end,
    TaFormatArgs = get_multi_dun_ta_args(DunType, [SingleMode, DummyList, DunRoles, PowerNeed]),
    Args = get_start_args(DunType, DunId, DummyList),
    Args1 = lists:append(TaFormatArgs, Args),
    mod_dungeon:start(TeamId, 0, DunId, DunRoles, Args1),
    ok.

%% 队长排序
leader_sort(Members) ->
    case lists:keytake(1, #dun_multi_member.is_leader, Members) of
        {value, Leader, LessMembers} ->
            [Leader|LessMembers];
        _ -> Members
    end.

%%获取副本假人参数
get_start_args(DunType, DunId, []) ->
    Args = lib_dungeon_distribute:get_start_dun_args(0, 0, #dun_cfg{id = DunId, type = DunType}, 0),
    Args;
get_start_args(DunType, DunId, DummyList) ->
    MatchType = lists:member(DunType, ?MATCH_DUNGEON),
    if
        MatchType ->
            Args = lib_dungeon_distribute:get_start_dun_args(0, 0, #dun_cfg{id = DunId, type = DunType}, 0),
            Mod = lib_dungeon_distribute:mod_dungeon_type_map(DunType),
            [{typical_data, [{?DUN_STATE_SPECIAL_KEY_HANDLE_MFA, {Mod, create_dummy, [DunId, DummyList]}}]}] ++ Args;
        true -> []
    end.

%% 获取TA数据上报参数
get_multi_dun_ta_args(?DUNGEON_TYPE_CRUSADE, [SingleMode, DummyList, DunRoles|_]) ->
    [{typical_data, [
        {is_single_mode, SingleMode}, {player_num, length(DunRoles)}, {robot_num, length(DummyList)},
        {assist_num, length([DMember || DMember = #dun_multi_member{help_type = HelpType} <- DunRoles, HelpType == 1])}
        ]
    }];
get_multi_dun_ta_args(?DUNGEON_TYPE_GUARD, [_SingleMode, DummyList, DunRoles, PowerNeed]) ->
    [{typical_data, [
        {player_num, length(DunRoles)}, {robot_num, length(DummyList)},
        {power_need, PowerNeed}, {rec_role_power, 0}
    ]}];
get_multi_dun_ta_args(_, _) ->
    [].

%%开启副本的公共检测
check_start_dun_multi_common(Team) when is_record(Team, dun_multi_team) ->
    #dun_multi_team{dun_id = DunId, members = Members,  handle_mb = HandleMb, is_start = IsStart} = Team,
    %%队员准备状态
    NotReadyList = [M || M = #dun_multi_member{is_ready = 0} <- Members],
    AllReady = NotReadyList == [],
    %%所有队员检测
    AllMemberCheck = lib_dun_multi:check_all_member(Members, DunId),
    {MemberIds, HandleTime} = HandleMb,
    Now = utime:unixtime(),
    %%队伍正在操作缓冲中
    AllHandle = MemberIds == [] orelse (MemberIds =/=[] andalso Now >= HandleTime),
    % TeamLen = length(Members),
    % IsSingleMergeType = lists:any(fun(#dun_multi_member{typical_data = TypicalData}) -> 
    %     MergeType = maps:get(?DUN_ROLE_COUNT_MERGE, TypicalData, 0),
    %     MergeType == 1
    % end, Members),
    %% 判断合并次数相关
    % MergeTypeCheck =
    % if TeamLen > 1 ->
    %         if IsSingleMergeType == true -> false;
    %             true -> true
    %         end;
    %     true ->
    %         true
    % end,
    case {IsStart, AllReady, AllMemberCheck, AllHandle} of
        {0, true, true, true} ->
            true;
        {1, _, _, _} ->
            {false, ?ERRCODE(err215_is_on_dungeon)};
        {_, false, _, _} ->
            {false, ?ERRCODE(err215_not_all_ready)};
        {_, _, {false, ErrCode}, _} ->
            {false, member, ErrCode};
        {_, _, _, false} ->
            {false, ?ERRCODE(err215_quick_handle)};
        % {_, _, _, _, false} ->
        %     {false, ?ERRCODE(err215_merge_count_error)};
        _ ->
            {false, ?FAIL}
    end;
check_start_dun_multi_common(_Team)-> {false, ?ERRCODE(err215_no_team)}.

%% --------------------切换队伍的副本状态------------------------
change_team_state(TeamId, _DunId, Type) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{} = Team] ->
            NewTeam = Team#dun_multi_team{is_start = Type, is_match = 0, is_auto_start = 0},
            dungeon_end_handle(Type, Team, NewTeam);
        _ -> ok
    end,
    ok.

%%副本结束处理
dungeon_end_handle(0, _Team, NewTeam) ->
    #dun_multi_team{id = TeamId, dun_id = DunId, members = MemberList} = NewTeam,
    {ok, BinData} = pt_215:write(21506, [1]),
    lib_dun_multi_cluster:send_to_team(MemberList, BinData),
    [ member_quit_team(TeamId, Member) || Member <- MemberList],
    dismiss_team(TeamId, DunId);
dungeon_end_handle(1, Team, NewTeam) ->
    update_team_to_ets(Team, NewTeam).

%% --------------------同步玩家的每日次数和助战状态------------------
sync_times({RoleId}, TeamId, HelpType, AddNum, DailyNum, HelpNum) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members, handle_mb = {AllowIds, Time}}] ->
            case lists:keyfind(RoleId, #dun_multi_member.id, Members) of
                #dun_multi_member{} = Member ->
                    NewMember = Member#dun_multi_member{help_type = HelpType, add_times = AddNum, daily_times = DailyNum, help_times = HelpNum},
                    NewMembers = lists:keystore(RoleId, #dun_multi_member.id, Members, NewMember),
                    NewTeam = Team#dun_multi_team{members = NewMembers, handle_mb = {lists:delete(RoleId, AllowIds), Time}},
                    update_team_to_ets(Team, NewTeam),
                    lib_dun_multi_cluster:broadcast_team_info(NewTeam);
                _ -> ok
            end;
        _ -> ok
    end.

%% --------------------队伍进入，退出匹配状态-----------------------
match_handle_team(TeamId, RoleId, Node, Type, IsFirst) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{is_start = 1}|_] -> ErrCode = ?ERRCODE(err215_is_on_dungeon);
        [Team = #dun_multi_team{members = Members, max_num = MaxNum, first_ref = FirstRef, is_match = OldType}|_] ->
            if OldType =/= Type ->
                    Length = length(Members),
                    case lists:keyfind(RoleId, #dun_multi_member.id, Members) of
                        #dun_multi_member{is_leader = 1} when Length < MaxNum ->
                            ErrCode = ?SUCCESS,
                            case IsFirst == 1 andalso Type == 1 of
                                true -> Ref = util:send_after(FirstRef, ?FIRST_TIME * 1000, self(), {first_match_dummy, TeamId});
                                false -> Ref = util:cancel_timer(FirstRef)
                            end,
                            % NewReqList = lists:map(fun(ReqRole) -> ReqRole#dun_multi_member{} end, ReqList),
                            NewTeam = Team#dun_multi_team{is_match = Type, first_ref = Ref, match_time = utime:unixtime()},
                            lib_dun_multi_cluster:team_broadcast_notify(0, Members, {0}, ?DUNMULTITEAM_NOTIFY_MATCH, Type),
                            {ok, BinData} = pt_215:write(21529, [Type]),
                            lib_dun_multi_cluster:send_to_team(Members, BinData),
                            [lib_player:apply_cast(MemberNode, MemberId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, update_team_match, [Type]) 
                            || #dun_multi_member{id = MemberId, node = MemberNode} <- Members],
                            update_team_to_ets(Team, NewTeam);
                        #dun_multi_member{is_leader = 1} ->
                            ErrCode = ?ERRCODE(err215_team_max_member);
                        _ ->
                            ErrCode = ?ERRCODE(err215_not_leader)
                    end;
                true ->
                    ErrCode = ?ERRCODE(err215_repeat_match_state)
            end;
        _ -> ErrCode = ?ERRCODE(err215_not_in_team)
    end,
    {ok, BinData1} = pt_215:write(21524, [ErrCode, Type]),
    lib_server_send:send_to_uid(Node, RoleId, BinData1).

%%---------------------匹配加入队伍----------------------------------
match_join_team(DunId, Member, IsFirst) ->
    TeamL = ets:tab2list(?DUN_MULTI_TEAM_ETS),
    TeamSubL = case ets:lookup(?DUN_MULTI_HALL_ETS, DunId) of
        [#dun_multi_room{teams = Teams}] -> Teams;
        _ -> []
    end,
    FilterList = find_can_join_team(DunId, Member, TeamL, TeamSubL),
    match_join_team_core(DunId, Member, FilterList, IsFirst).

%% ------------------- 连续讨伐匹配 ------------------------
match_join_crusade_team(SubType, Member, IsFirst) ->
    TeamL = ets:tab2list(?DUN_MULTI_TEAM_ETS),
    [DunId1|_] = data_dun_multi_team:get_type_duns(?ACT_TYPE_CRUSADE, SubType),
    TeamSubL = case ets:lookup(?DUN_MULTI_HALL_ETS, SubType) of
        [#dun_multi_room{teams = Teams}|_] -> Teams;
        _ -> []
    end,
    FilterList = find_can_join_team(DunId1, Member, TeamL, TeamSubL),
    match_join_team_core(DunId1, Member, FilterList, IsFirst).

%%获取可加入的队伍
find_can_join_team(DunId, Member, TeamL, TeamSubL) ->
    #dun_multi_member{id = RoleId, figure = #figure{sex = Sex}} = Member,
    Now = utime:unixtime(),
    case data_dungeon:get_dun(DunId) of
        #dun_cfg{type = DunType} -> ok;
        _ -> DunType = 0
    end,
    MaxNum = lib_dun_multi:get_max_num(DunId),
    Fun = fun(SubTeam, TmpList) ->
        #dun_multi_team_sub{id = Id, member_num = MemberNum, is_start = IsStart} = SubTeam,
        IsFilter = MemberNum < MaxNum andalso IsStart == 0,
        case lists:keyfind(Id, #dun_multi_team.id, TeamL) of
            #dun_multi_team{members = Members, handle_mb = {AllowIds, Time}, need_approve = Approve, dun_id = TeamDunId, password = Password} when IsFilter ->
                IsSex = DunType == ?DUNGEON_TYPE_COUPLE andalso is_same_sex(Sex, Members),
                IsHandle = AllowIds == [] orelse (AllowIds =/= [] andalso Now > Time),
                TeamDunType = data_dungeon:get_dun_type(TeamDunId),
                IsAlreadyInTeam = lists:keyfind(RoleId, #dun_multi_member.id, Members),
                if not IsHandle ->
                        TmpList;
                    IsSex ->
                        TmpList;
                    TeamDunType == ?DUNGEON_TYPE_GUARD andalso Password =/= 0 ->
                        TmpList;
                    Approve == 1 ->
                        TmpList;
                    IsAlreadyInTeam =/= false ->
                        TmpList;
                    true ->
                        [Id | TmpList]
                end;
                % ?IF(IsHandle andalso IsSex == false, [Id | TmpList], TmpList);
            _ -> TmpList
        end
    end,
    FilterList = lists:foldl(Fun, [], TeamSubL),
    lists:sort(FilterList).


%%是否同性
is_same_sex(Sex, Members) ->
    Fun = fun(#dun_multi_member{figure = #figure{sex = TmpSex}}) ->
        TmpSex == Sex
    end,
    lists:any(Fun, Members).

%%加入可加入队伍
match_join_team_core(DunId, Member, [], IsFirst) ->
    %%没有可加入则创建队伍
    match_create_team(DunId, Member, IsFirst);
match_join_team_core(DunId, Member, [TeamId | T], IsFirst) ->
    case join_team(Member, TeamId) of
        {ok, IsMatch} ->
            {ok, TeamId, 0, IsMatch};
        {ok, DunId1, IsMatch} ->
            {ok, TeamId, DunId1, 0, IsMatch};
        _ ->
            match_join_team_core(DunId, Member, T, IsFirst)
    end.

%%自动匹配创建队伍
match_create_team(DunId0, Member = #dun_multi_member{help_type = ?DUN_TEAM_HELP_NO}, IsFirst) ->
    DunId = lib_dun_multi_cluster:get_real_dun_id(DunId0),
    #dun_multi_member{node = Node, id = RoleId} = Member,
    MaxNum = lib_dun_multi:get_max_num(DunId),
    NewMember = Member#dun_multi_member{is_leader = 1},
    MinLv = get_min_lv(DunId),
    IsMatch = 1,
    MultiTeam = #dun_multi_team{dun_id = DunId, sub_type_dun = DunId0, min_lv = MinLv, is_auto_start = 1, 
        is_match = IsMatch, match_time = utime:unixtime(), max_num = MaxNum},
    {ok, TeamId} = create_team(MultiTeam, NewMember, {[], 0}, IsFirst),
    % ReturnId = lib_dun_multi_cluster:get_return_dun_id(DunId),
    {ok, BinData} = pt_215:write(21502, [?SUCCESS, DunId0, TeamId, 0, 0, 2]),
    % {ok, BinData1} = pt_215:write(21529, [1]),
    lib_server_send:send_to_uid(Node, RoleId, BinData),
    case data_dun_multi_team:get_dun_act_type(DunId) of
        ?ACT_TYPE_CRUSADE ->
            {ok, TeamId, DunId, NewMember#dun_multi_member.is_leader, IsMatch};
        _ ->
            {ok, TeamId, NewMember#dun_multi_member.is_leader, IsMatch}
    end;
match_create_team(_DunId, _, _) ->
    {false, ?ERRCODE(err215_help_can_not_create_team)}.


get_min_lv(DunId) ->
    case data_team_ui:get_act_key(DunId) of
        [{ActId, SubId}|_T] ->
            case data_team_ui:get(ActId, SubId) of
                #team_enlist_cfg{default_lv_min = MinLv} -> MinLv;
                _ -> 0
            end;
        _ -> 0
    end.

%%---------------------修改设置-------------------------------------
update_set_info(RoleId, Node, TeamId, MinLv, Power, Password) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members}] ->
            case lists:keyfind(RoleId, #dun_multi_member.id, Members) of
                #dun_multi_member{is_leader = 1} ->
                    ErrCode = ?SUCCESS,
                    NewTeam = Team#dun_multi_team{min_lv = MinLv, power = Power, password = Password},
                    update_team_to_ets(Team, NewTeam),
                    lib_dun_multi_cluster:broadcast_team_info(NewTeam);
                    % ?IF(OldIsAuto =/= IsAuto andalso IsAuto == 1, auto_start_dun_multi(NewTeam), ok);
                _ ->
                    ErrCode = ?ERRCODE(err215_not_leader)
            end;
        _ -> ErrCode = ?ERRCODE(err215_not_in_team)
    end,
    {ok, BinData} = pt_215:write(21515, [ErrCode, MinLv, Power, Password]),
    lib_server_send:send_to_uid(Node, RoleId, BinData).

%%---------------------委任队长--------------------------------------
change_leader(RoleId, Node, TeamId, ToId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team = #dun_multi_team{members = Members, dun_id = DunId, vote_ref = VoteRef}] ->
            case check_change_leader(Members, RoleId, ToId, TeamId, DunId) of
                {true, NewMembers} ->
                    ErrCode = ?SUCCESS,
                    util:cancel_timer(VoteRef),
                    NewTeam = Team#dun_multi_team{members = NewMembers, is_match = 0, vote_ref = undefined, vote_list = {[], []}},
                    update_team_to_ets(Team, NewTeam),
                    team_change_vote_notice(Members),
                    lib_dun_multi_cluster:team_broadcast_notify(0, NewMembers, {ToId}, ?DUNMULTITEAM_NOTIFY_CHANGE_LEADER, 0),
                    lib_dun_multi_cluster:team_broadcast_notify(0, NewMembers, {0}, ?DUNMULTITEAM_NOTIFY_MATCH, 0),
                    {ok, BinData} = pt_215:write(21529, [0]),
                    lib_dun_multi_cluster:send_to_team(NewMembers, BinData);
                {false, ErrCode} -> ok
            end;
        _ -> ErrCode = ?ERRCODE(err215_not_in_team)
    end,
    {ok, BinData1} = pt_215:write(21516, [ErrCode]),
    lib_server_send:send_to_uid(Node, RoleId, BinData1).

check_change_leader(Members, RoleId, ToId, TeamId, DunId) ->
    OldLeader = lists:keyfind(RoleId, #dun_multi_member.id, Members),
    Member = lists:keyfind(ToId, #dun_multi_member.id, Members),
    if
        is_record(OldLeader, dun_multi_member) == false -> {false, ?ERRCODE(err215_not_leader)};
        is_record(Member, dun_multi_member) == false -> {false, ?ERRCODE(err215_member_not_exit)};
        OldLeader#dun_multi_member.is_leader =/= 1 -> {false, ?ERRCODE(err215_not_leader)};
        Member#dun_multi_member.is_dummy =/= ?DUN_REAL -> {false, ?ERRCODE(err215_not_to_dummy)};
        true ->
            NewOldLeader = OldLeader#dun_multi_member{is_leader = 0},
            NewMember = Member#dun_multi_member{is_leader = 1, is_ready = 1},
            lib_player:apply_cast(NewMember#dun_multi_member.node, ToId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_team_rela_change, [TeamId, DunId, 1]),
            lib_player:apply_cast(NewOldLeader#dun_multi_member.node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_team_rela_change, [TeamId, DunId, 0]),
            Members1 = lists:keystore(RoleId, #dun_multi_member.id, Members, NewOldLeader),
            Members2 = lists:keystore(ToId, #dun_multi_member.id, Members1, NewMember),
            {true, Members2}
    end.

%%---------------------催促队长--------------------------------------
prompt_enter(RoleId, Node, TeamId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{members = Members}] ->
            IsMember = lists:keymember(RoleId, #dun_multi_member.id, Members),
            case lists:keyfind(1, #dun_multi_member.is_leader, Members) of
                #dun_multi_member{id = RoleId} ->
                    ErrCode = ?ERRCODE(err215_not_prompt_self);
                #dun_multi_member{id = LeaderId, node = LeaderNode} when IsMember->
                    ErrCode = ?SUCCESS,
                    {ok, BinData1} = pt_215:write(21518, []),
                    lib_server_send:send_to_uid(LeaderNode, LeaderId, BinData1);
                _ -> ErrCode = ?ERRCODE(err215_not_in_team)
            end;
        _ -> ErrCode = ?ERRCODE(err215_not_in_team)
    end,
    {ok, BinData} = pt_215:write(21517, [ErrCode]),
    lib_server_send:send_to_uid(Node, RoleId, BinData).

%%---------------------假人匹配---------------------------------------
%%副本首次匹配
first_match_dummy(TeamId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [Team|_] ->
            #dun_multi_team{members = Members, is_start = IsStart, is_match = IsMatch, max_num = MaxNum, vote_ref = VoteRef} = Team,
            MemberNum = length(Members),
            IsInVote = is_in_vote(VoteRef),
            case MemberNum < MaxNum andalso IsStart == 0 andalso IsMatch == 1 andalso not IsInVote of
                true ->
                    do_first_match_dummy(Team);
                false -> ok
            end;
        _ ->
            ok
    end.

do_first_match_dummy(Team) ->
    #dun_multi_team{dun_id = DunId, id = TeamId, max_num = MaxNum, members = Members, first_ref = Ref} = Team,
    Length = length(Members),
    case Length + 1 >= MaxNum of
        false ->
            NewRef = util:send_after(Ref, ?FIRST_TIME * 1000, self(), {first_match_dummy, TeamId}),
            NewTeam = Team#dun_multi_team{first_ref = NewRef};
        _ ->
            NewTeam = Team
    end,
    ServerNum = clusters_api:get_all_server_num(),
    do_match_dummy(DunId, ServerNum, [NewTeam]).

match_dummy(DunId) ->
    TeamL = ets:tab2list(?DUN_MULTI_TEAM_ETS),
    TeamSubL = case ets:lookup(?DUN_MULTI_HALL_ETS, DunId) of
        [#dun_multi_room{teams = Teams}] -> Teams;
        _ -> []
    end,
    Now = utime:unixtime(),
    Fun = fun(#dun_multi_team_sub{id = TeamId, member_num = MemberNum}, TmpNeedMatch)->
        case lists:keyfind(TeamId, #dun_multi_team.id, TeamL) of
            #dun_multi_team{is_start = IsStart, match_time = MatchTime, is_match = IsMatch, 
             max_num = MaxNum, password = Password, vote_ref = VoteRef, single_mode = SingleMode,
             members = Members} = Team when MemberNum < MaxNum andalso IsStart == 0 
             andalso IsMatch == 1 andalso Password == 0 andalso SingleMode == 0 ->
                MemberLen = length([1 || #dun_multi_member{is_dummy = IsDummy}<-Members, IsDummy == 1]),
                if MemberLen < 1 -> MatchTimeLimit = ?MATCH_ONE;
                    true -> MatchTimeLimit = ?MATCH_TWO
                end,
                case Now - MatchTime >= MatchTimeLimit of %% 自动匹配后一定时间后才开始匹配假人
                    true ->
                        IsInVote = is_in_vote(VoteRef),
                        if 
                            not IsInVote ->  
                                [Team | TmpNeedMatch];
                            true ->
                                TmpNeedMatch
                        end;
                    false -> TmpNeedMatch
                end;
            _A -> TmpNeedMatch
        end
    end,
    NeedMatch = lists:foldl(Fun, [], TeamSubL),
    ServerNum = clusters_api:get_all_server_num(),
    do_match_dummy(DunId, ServerNum, NeedMatch).

do_match_dummy(_DunId0, _ServerNum, []) -> ok;
do_match_dummy(DunId0, ServerNum, [Team | T]) ->
    #dun_multi_team{id = TeamId, dun_id = DunId, min_lv = Minlv, is_match = IsMatch,
        power = Power, members = MemberList, max_num = MaxNum, req_list = ReqList} = Team,
    DummyMember = select_dummy(DunId, TeamId, MemberList, Minlv, Power, ServerNum),
    NewMemberList = [DummyMember | MemberList],
    if 
        length(NewMemberList) >= MaxNum ->
            NewIsMatch = 0,
            delete_team_req(TeamId, ReqList),
            NewTeam = Team#dun_multi_team{members = NewMemberList, match_time = utime:unixtime(), is_match = NewIsMatch, req_list = []};
        true ->
            NewIsMatch = IsMatch,
            NewTeam = Team#dun_multi_team{members = NewMemberList, match_time = utime:unixtime()}
    end,
    update_team_to_ets(Team, NewTeam),
    lib_dun_multi_cluster:broadcast_team_info(NewTeam),
    NewIsMatch =/= IsMatch andalso 
    [lib_player:apply_cast(MemberNode, MemberId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, update_team_match, [NewIsMatch]) 
        || #dun_multi_member{id = MemberId, node = MemberNode, is_dummy = IsDummy} <- MemberList, IsDummy == ?DUN_REAL],
    % auto_start_dun_multi(NewTeam),
    % ?PRINT("aa~n",[]),
    do_match_dummy(DunId0, ServerNum, T).

%% 假人属性取队长属性*0.8
%% 假人战力取队长战力0.8
%% 假人等级取队长等级+-5
select_dummy(DunId, TeamId, MemberList, _MinLv, Power, ServerNum) ->
    OpenLv = lib_dun_multi:get_dun_open_lv(DunId),
    OldId = case lists:keyfind(1, #dun_multi_member.is_dummy, MemberList) of
        #dun_multi_member{id = Id} -> Id;
        false -> 0
    end,
    {InitDummyLv, InitPower, InitAttrList, InitHpLim} =
    case lists:keyfind(1, #dun_multi_member.is_leader, MemberList) of
        #dun_multi_member{figure = #figure{lv = LeaderLv}, power = LeaderPower, attr_list = AttrList, hp_lim = HpLim} -> 
            {LeaderLv, LeaderPower, AttrList, HpLim};
        _ -> 
            {OpenLv, Power, [], 200}
    end,
    DummyLv = InitDummyLv+urand:rand(-5,5),
    DummyPower = round(InitPower*urand:rand(75, 85)/100),
    DummyAttrList = [{AttrId, round(Val*0.8)} || {AttrId, Val} <- InitAttrList],
    % DummyLv = InitDummyLv,
    % AveragePower = get_real_role_power(MemberList),
    % DummyPower = case data_fake_role:get_fake_role(DummyLv) of
    %     #fake_role_cfg{combat = Combat} ->
    %         Ratio = max(1, AveragePower/ Combat * 0.85),
    %         Rand = urand:rand(95, 105) / 100,
    %         round(Combat * Ratio * Rand);
    %     _ -> Power
    %  end,
    %  DummyAttrList = []
    DummyId = case OldId == 0 of
        true -> TeamId * 10 + 1;
        false -> OldId + 1
    end,
    CareerList = get_career_list(DunId, MemberList),
    create_dummy(DummyId, DummyLv, DummyPower, InitHpLim, DummyAttrList, CareerList, ServerNum).

create_dummy(Id, Lv, Power, HpLim, AttrList, CareerList, ServerNum) ->
    {Career, Sex} = urand:list_rand(CareerList),
    Turn = urand:list_rand(lists:seq(0, ?MAX_TURN)),
    Group = data_vsn:calc_name_group(),
    FirstName = urand:list_rand(data_role_name:first_name_list(Group, Sex)),
    LastName = urand:list_rand(data_role_name:last_name_list(Group)),
    Name = LastName++FirstName,
    LvModel = lib_player:get_model_list(Career, Sex, Turn, Lv),
    MonFigure = #figure{id = Id, name = Name, lv = Lv, career = Career, sex = Sex,  turn = Turn, lv_model = LvModel},
    RandServerNum = ?IF(ServerNum > 0, urand:rand(1, ServerNum), urand:rand(10, 20)),
    #dun_multi_member{
        node = node(), server_num = RandServerNum, id = Id, figure = MonFigure, 
        power = Power, is_dummy = ?DUN_DUMMY, is_ready = 1, attr_list = AttrList,
        hp_lim = HpLim}.

%%获取队伍真实玩家平均战力
% get_real_role_power(MemberList) ->
%     SumPower = lists:sum([Power || #dun_multi_member{power = Power, is_dummy = IsDummy} <- MemberList, IsDummy == 0 ]),
%     Num = length([1 || #dun_multi_member{is_dummy = IsDummy} <- MemberList, IsDummy == 0 ]),
%     round(SumPower/Num).

%% 获取假人职业性别
%% 暂时排除职业1&2
get_career_list(DunId, MemberList) ->
    CareerList = data_career:get_all_career(),
    CareerList1 = lists:filter(fun({Career, _Sex}) -> 
        if Career == 1 orelse Career == 2 ->
                false;
            true ->
                true
        end end, CareerList),
    case data_dungeon:get_dun(DunId) of
        #dun_cfg{type = DunType} -> ok;
        _ -> DunType = 0
    end,
    case DunType == ?DUNGEON_TYPE_COUPLE of
        true -> get_other_sex_career(CareerList1, MemberList);
        false -> CareerList1
    end.

%%情侣副本获取异性
get_other_sex_career(CareerList, []) -> CareerList;
get_other_sex_career(CareerList, [#dun_multi_member{figure = #figure{sex = Sex}}| _T]) ->
    NeedSex = ?IF(Sex == ?MALE, ?FEMALE, ?MALE),
    Fun = fun({_Career, TmpSex})-> TmpSex == NeedSex end,
    case lists:filter(Fun, CareerList) of
        [] -> CareerList;
        FilterList -> FilterList
    end.
%% --------------------更新多人副本组队信息到ets -------------------------------
update_team_to_ets(MultiTeam, NewMultiTeam) ->
    ets:insert(?DUN_MULTI_TEAM_ETS, NewMultiTeam),
    #dun_multi_team{dun_id = DunId, id = TeamId} = NewMultiTeam,
    MultiTeamSub = multi_team_to_sub(MultiTeam),
    NewMultiTeamSub = multi_team_to_sub(NewMultiTeam),
    %% 更新到多人副本大厅房间
    case NewMultiTeamSub of
        MultiTeamSub ->
            ok;
        _ -> %% 数据有变化时才更新
            HallId = lib_dun_multi_cluster:get_act_pid_map_id(DunId),
            NewRoom =
            case ets:lookup(?DUN_MULTI_HALL_ETS, HallId) of
                [Room = #dun_multi_room{teams = Teams}] ->
                    NewTeams = lists:keystore(
                        TeamId, #dun_multi_team_sub.id, Teams, NewMultiTeamSub
                    ),
                    Room#dun_multi_room{teams = NewTeams};
                [] ->
                    #dun_multi_room{id = HallId, teams = [NewMultiTeamSub]}
            end,
            ets:insert(?DUN_MULTI_HALL_ETS, NewRoom)
    end,
    ok.

change_team_to_ets(MultiTeam, NewMultiTeam) ->
    ets:insert(?DUN_MULTI_TEAM_ETS, NewMultiTeam),
    #dun_multi_team{dun_id = OldDunId} = MultiTeam,
    #dun_multi_team{dun_id = DunId, id = TeamId} = NewMultiTeam,
    if OldDunId == DunId ->
            ok;
        true ->
            OldHallId = lib_dun_multi_cluster:get_act_pid_map_id(OldDunId),
            case ets:lookup(?DUN_MULTI_HALL_ETS, OldHallId) of
                [Room = #dun_multi_room{teams = Teams1}|_] ->
                    NewTeams1 = lists:keydelete(TeamId, #dun_multi_team_sub.id, Teams1),
                    ets:insert(?DUN_MULTI_HALL_ETS, Room#dun_multi_room{teams = NewTeams1});
                _ -> skip
            end,
            HallId = lib_dun_multi_cluster:get_act_pid_map_id(DunId),
            case ets:lookup(?DUN_MULTI_HALL_ETS, HallId) of
                [NewRoom = #dun_multi_room{teams = Teams2}|_] ->
                    NewMultiTeamSub = multi_team_to_sub(NewMultiTeam),
                    NewTeams2 = lists:keystore(TeamId, #dun_multi_team_sub.id, Teams2, NewMultiTeamSub),
                    ets:insert(?DUN_MULTI_HALL_ETS, NewRoom#dun_multi_room{teams = NewTeams2});
                [] ->
                    NewMultiTeamSub = multi_team_to_sub(NewMultiTeam),
                    NewRoom = #dun_multi_room{id = HallId, teams = [NewMultiTeamSub]},
                    ets:insert(?DUN_MULTI_HALL_ETS, NewRoom)
            end
    end.

multi_team_to_sub(MultiTeam) ->
    #dun_multi_team{
        id = Id, power = Power, password = Password, is_auto_start = IsAuto, members = Members, min_lv = MinLv, is_start = IsStart, dun_id = DunId
    } = MultiTeam,
    {LeaderId, LeaderName, ServerId, ServerNum, LeftNum} =
    case lists:keyfind(1, #dun_multi_member.is_leader, Members) of
        #dun_multi_member{
            id = RoleId, server_id = ServerId0,
            server_num = ServerNum0, figure = #figure{name = Name},
            daily_times = DailyNum, add_times = AddTimes
        } ->
            MaxTimes = lib_dun_multi:get_max_times(DunId),
            {RoleId, Name, ServerId0, ServerNum0, max(MaxTimes + AddTimes - DailyNum, 0)};
        _ ->
            {0, <<>>, 0, 0, 0}
    end,
    MemberNum = length(Members),
    #dun_multi_team_sub{
        id = Id, power = Power, password = Password, is_auto_start = IsAuto, is_start = IsStart
        ,member_num = MemberNum,leader_id = LeaderId, leader_name = LeaderName,
        min_lv = MinLv, server_id = ServerId, server_num = ServerNum,
        leader_num = LeftNum
    }.

%% -------------------------删除组队信息-------------------------
dismiss_team(TeamId, DunId) ->
    HallId = lib_dun_multi_cluster:get_act_pid_map_id(DunId),
    case ets:lookup(?DUN_MULTI_HALL_ETS, HallId) of
        [DunRoom = #dun_multi_room{teams = Teams}] ->
            NewTeams = lists:keydelete(TeamId, #dun_multi_team_sub.id, Teams),
            NewDunRoom = DunRoom#dun_multi_room{teams = NewTeams},
            ets:insert(?DUN_MULTI_HALL_ETS, NewDunRoom),
            ok;
        _ ->
            ok
    end,
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{first_ref = Ref, vote_ref = VoteRef}] ->
            ets:delete(?DUN_MULTI_TEAM_ETS, TeamId),
            util:cancel_timer(Ref),
            util:cancel_timer(VoteRef);
        _ ->
            ok
    end,
    ok.

%% -----------------打包副本房间的所有组队 -------------------
pack_dun_teams(DunId, TeamSubList, TeamL) ->
    MaxNum = lib_dun_multi:get_max_num(DunId),
    Fun = fun(TL, TmpList) ->
        #dun_multi_team_sub{
            id = Id, power = Power, password = Password
            ,is_auto_start = IsAuto
            ,min_lv = MinLv
            ,member_num = MemberNum
            ,leader_id = LeaderId
            ,leader_name = LeaderName
            ,server_num = ServerNum
            ,leader_num = LeftNum
            ,is_start = IsStart
        } = TL,
        Team = lists:keyfind(Id, #dun_multi_team.id, TeamL),
        if
            MemberNum >= MaxNum orelse IsStart > 0 ->
                TmpList;
            not is_record(Team, dun_multi_team) ->
                TmpList;
            true ->
                #dun_multi_team{members = Members, dun_id = RealDun} = Team,
                MemberInfoL = [begin
                #figure{lv = Lv, career = Career, sex = Sex, turn = Turn, picture_ver = PictureVer, picture = PicId,
                    profile_photo_id = PhotoId, dress_list = DressList} = Figure,
                PictureFrame =
                case lists:keyfind(2, 1, DressList) of
                    {_DType, DId}  -> DId;
                    _ -> 0
                end,
                {RoleId, Lv, Career, Sex, Turn, PictureVer, PicId, PhotoId, PictureFrame}
                end ||#dun_multi_member{id = RoleId, figure = Figure}<-Members],
                NeedPassword = ?IF(Password =/= 0, 1, Password),
                Info = {Id, RealDun, LeaderId, LeaderName, ServerNum, LeftNum, IsAuto, MinLv, Power, IsStart, NeedPassword, MemberInfoL},
                [Info | TmpList]
        end
    end,
    lists:foldl(Fun, [], TeamSubList).

%% -----------------更改玩家相关属性 -------------------
update_role_attr(TeamId, RoleId, KeyList) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{members = Members} = Team] ->
            case lists:keyfind(RoleId, #dun_multi_member.id, Members) of
                #dun_multi_member{} = Member ->
                    NewMember = do_update_role_attr(Member, KeyList),
                    NewMembers = lists:keystore(RoleId, #dun_multi_member.id, Members, NewMember),
                    NewTeam = Team#dun_multi_team{members = NewMembers},
                    update_team_to_ets(Team, NewTeam),
                    lib_dun_multi_cluster:broadcast_team_info(NewTeam);
                _ -> ok
            end;
        _ -> ok
    end.

do_update_role_attr(Member, []) -> Member;
do_update_role_attr(Member, [H | T]) ->
    #dun_multi_member{figure = Figure} = Member,
    case H of
        {lv, Lv} ->
            NewFigure = Figure#figure{lv = Lv},
            NewMember = Member#dun_multi_member{figure = NewFigure};
        {combat_power, CombatPower} ->
            NewMember = Member#dun_multi_member{power = CombatPower};
        {is_first, IsFirst} ->
            NewMember = Member#dun_multi_member{is_first = IsFirst};
        _ -> NewMember = Member
    end,
    do_update_role_attr(NewMember, T).

%% -----------------检测队伍 -------------------
check_team(DunId) ->
    HallId = lib_dun_multi_cluster:get_act_pid_map_id(DunId),
    case ets:lookup(?DUN_MULTI_HALL_ETS, HallId) of
        [#dun_multi_room{teams = Teams}] ->
            MulTeamList = get_multi_team(Teams, [], []);
        _ ->
            MulTeamList = []
    end,
    Fun = fun({TeamId, LeaderId, Node}) ->
        leave_team_logic({LeaderId}, TeamId),
        Args = [TeamId, DunId],
        ApplyArgs = [LeaderId, ?APPLY_CAST_STATUS, ?MODULE, clear_multi_team, Args],
        lib_dun_multi_cluster:apply_to_local_role(Node, lib_player, apply_cast, ApplyArgs)
    end,
    case MulTeamList =/= [] of
        true -> ?INFO("check_team~p~n",[MulTeamList]);
        false -> ok
    end,
    lists:map(Fun, MulTeamList).

get_multi_team([], _HandleList, MulTeamList) -> MulTeamList;
get_multi_team([#dun_multi_team_sub{id = TeamId, leader_id = LeaderId} | T], HandleList, MulTeamList) ->
    case lists:keyfind(LeaderId, 1, HandleList) of
        {_, TeamId1} ->
            case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
                [#dun_multi_team{members = Members, is_start = IsStart}] ->
                    Length = length(Members),
                    case lists:keyfind(LeaderId, #dun_multi_member.id, Members) of
                        #dun_multi_member{node = Node} when Length =< 1 andalso IsStart == 0 ->
                           get_multi_team(T, HandleList, [{TeamId1, LeaderId, Node}, {TeamId, LeaderId, Node} | MulTeamList]);
                        _ -> get_multi_team(T, HandleList, MulTeamList)
                    end;
                _ ->
                    get_multi_team(T, HandleList, MulTeamList)
            end;
        _ -> get_multi_team(T, [{LeaderId, TeamId} | HandleList], MulTeamList)
    end.

clear_multi_team(PS, TeamId, DunId) ->
    #player_status{sid = Sid, dun_multi = DunMulti, id = RoleId} = PS,
    case DunMulti of
        #role_dun_multi{team_id = TeamId, dun_id = DunId} ->
            ets:delete(?DUN_MULTI_ROLE_ETS, RoleId),
            NewDunMulti = #role_dun_multi{team_id = 0, dun_id = 0},
            NewPS = PS#player_status{dun_multi = NewDunMulti},
            mod_scene_agent:update(NewPS, [{dun_multi, {0, 0}}]),
            {ok, BinData} = pt_215:write(21506, [1]),
            lib_server_send:send_to_sid(Sid, BinData),
            lib_player:break_action_lock(NewPS, ?ERRCODE(err215_on_multi_team));
        _ -> PS
    end.

delete_team_req(TeamId, ReqList) ->
        [lib_player:apply_cast(ReqNode, ReqId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_dun_multi, role_deleted_req_list, [TeamId]) 
        || #dun_multi_member{node = ReqNode, id = ReqId} <- ReqList],
        ok.

%% -----------------加入队伍失败操作 -------------------
team_fail_handle(Key, Node, RoleId) ->
    ?ERR("team_fail_handle,~p~n",[{Key, RoleId}]),
    case ets:lookup(?DUN_MULTI_HALL_ETS, Key) of
        [#dun_multi_room{teams = Teams}] ->
            team_fail_handle_do(Teams, Node, RoleId);
        _ ->
            ok
    end.

team_fail_handle_do([], _Node, _RoleId) -> ok;
team_fail_handle_do([#dun_multi_team_sub{id = TeamId} | T], Node, RoleId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId) of
        [#dun_multi_team{members = Members}] ->
            case lists:keyfind(RoleId, #dun_multi_member.id, Members) of
                #dun_multi_member{} ->
                    ?ERR("team_fail_handle_do,~p~n",[{TeamId, RoleId}]),
                    leave_team_logic({RoleId}, TeamId),
                    {ok, BinData} = pt_215:write(21506, [1]),
                    lib_server_send:send_to_uid(Node, RoleId, BinData),
                    team_fail_handle_do(T, Node, RoleId);
                _ ->
                    team_fail_handle_do(T, Node, RoleId)
            end;
        _ ->
            team_fail_handle_do(T, Node, RoleId)
    end.

%% -----------------加入队伍后检查去掉同目标重复老队伍 -------------------
del_old_team(Member, TeamId, Key) ->
    #dun_multi_member{id = RoleId} = Member,
    case ets:lookup(?DUN_MULTI_HALL_ETS, Key) of
        [#dun_multi_room{teams = Teams}]->
            del_old_team_do(Teams, TeamId, RoleId),
            ok;
        _ ->
            ok
    end.

del_old_team_do([], _TeamId, _RoleId) -> ok;
del_old_team_do([#dun_multi_team_sub{id = TeamId} | T], TeamId, RoleId) ->
    del_old_team_do(T, TeamId, RoleId);
del_old_team_do([#dun_multi_team_sub{id = TeamId1} | T], TeamId, RoleId) ->
    case ets:lookup(?DUN_MULTI_TEAM_ETS, TeamId1) of
        [#dun_multi_team{members = Members}] ->
            case lists:keyfind(RoleId, #dun_multi_member.id, Members) of
                #dun_multi_member{is_dummy = ?DUN_REAL} ->
                    ?ERR("del_old_team_do,~p~n",[{TeamId1, RoleId}]),
                    leave_team_logic({RoleId}, TeamId1);
                _ -> ok
            end;
        _ -> ok
    end,
    del_old_team_do(T, TeamId, RoleId).