%%%===================================================================
%%% @author zmh
%%% @doc 跨服 擂台赛 (钻石争霸战)
%%% 跨服中心管理进程
%%% @end
%%% @update by zzy 2017-11-08
%%%===================================================================
-module(mod_drumwar_mgr).
-behavior(gen_server).
-compile(export_all).
-include("drumwar.hrl").
-include("server.hrl").
-include("predefine.hrl").
-include("chat.hrl").
-include("def_module.hrl").
-include("scene.hrl").
-include("figure.hrl").
-include("attr.hrl").
-include("common.hrl").
-include("def_fun.hrl").
-include("skill.hrl").
-include("errcode.hrl").
-include("goods.hrl").
-include("def_goods.hrl").
-export([
	start_link/0
	,init/1
	,handle_call/3
	,handle_cast/2
	,handle_info/2
	,terminate/2
	,code_change/3
]).

-export([
	call_mgr/1
	,cast_mgr/1
    ,cast_center/1
    ,call_center/1
]).

start_link() ->
	gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) ->
	process_flag(trap_exit, true),
    {Msg,S,TimeOut} = calc_state(),
    {Ref,Snow,Etime} = case S of
        ?IDLE -> {erlang:send_after(TimeOut*1000,self(),sign),S,utime:unixtime()+TimeOut}; %%闲
        ?SIGN -> {erlang:send_after(TimeOut*1000,self(),Msg),S,utime:unixtime()+TimeOut}; %%报名期
        ?CLOSE -> {erlang:send_after(TimeOut*1000,self(),Msg),S,utime:unixtime()+TimeOut}; %%已结束
        _->
            % {_NMsg,NS,NtimeOut} = next_calc_state(),
            {erlang:send_after(TimeOut*1000, self(), sign), S, utime:unixtime()+TimeOut}
    end,
    History = load_history(),
    Signs   = case Snow of
        ?SIGN -> %%启动时在报名期才需要加载数据
            load_signs(get_id());
        _->%%其他时候清表
            db:execute("TRUNCATE TABLE `drumwar_sign`"),
            []
    end,
    Choose = load_choose(),
    spawn(fun() -> brocast_msg(13700,[Snow, Etime]) end),
	{ok, #drumwar_mgr{state=Snow,ref=Ref,etime=Etime,signs=Signs,history=History,choose=Choose}}.

%%本地->跨服中心 Msg = [{start,args}]
cast_center(Msg)->
    clusters_node:apply_cast(?MODULE, cast_mgr, Msg).
call_center(Msg)->
    clusters_node:apply_call(?MODULE, call_mgr, Msg).

%%跨服中心分发到管理进程
call_mgr(Msg) ->
	gen_server:call(?MODULE, Msg, 3000).
cast_mgr(Msg) ->
	gen_server:cast(?MODULE, Msg).

handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State)of
        {noreply, NewState} ->
            {noreply, NewState};
        _Reason ->
            ?ERR("handle_cast Msg: ~p, Reason:=~p~n",[Msg, _Reason]),
            {noreply, State}
    end.

%%Gm开启 进入报名期 Time之后进入预备期
do_handle_cast({gm_start,Time},State)->
    clusters_center:apply_to_all_node(?MODULE, end_act_handle, [1], 100),
    #drumwar_mgr{ref=ORef, history = History}=State,
    util:cancel_timer(get(summon_enter_ref)),
    util:cancel_timer(ORef),
    erase({?MODULE, zone_win}),
    erase(summon_enter_ref),
    Ref = erlang:send_after(Time*1000,self(),ready),
    Etime = utime:unixtime()+Time,
    clusters_center:apply_to_all_node(?MODULE, start_act_handle, [], 100),
    brocast_msg(13700,[?SIGN,Etime]),
    clear_all_role(),
    db:execute("TRUNCATE TABLE `drumwar_sign`"),
    db:execute("TRUNCATE TABLE `drumwar_result`"),
    ?PRINT("gm start ok~n",[]),
    {noreply, #drumwar_mgr{state = ?SIGN, action=1, ref = Ref, etime = Etime, history = History}};

do_handle_cast({gm_startrank},State)->
    #drumwar_mgr{ref=OldRef,signs=Signs,action=Act}=State,
    util:cancel_timer(get(summon_enter_ref)),
    util:cancel_timer(OldRef),
    Now = utime:unixtime(),
    {NSigns,_} = account_war(Act,Signs,mod_drumwar_mgr:get_kv(?WAR_SCENE),[],[]),
    {Signs0, _ZoneNum} = calc_zones(NSigns),
    clear_all_mons(mod_drumwar_mgr:get_kv(?WAR_SCENE)),
    [RelaxT] = data_drumwar:get_rank_ready(),
    [RankPre] = data_drumwar:get_rank_prepare(),
    [RankEnter] = data_drumwar:get_rank_enter(),
    [RankWar] = data_drumwar:get_rank_war(),
    RankAll = RelaxT + 4 *(RankPre + RankWar + RankEnter) + 10,
    NEtime = Now + RankAll,
    SubTime = Now + RelaxT,
    % ?PRINT("~p~n",[Signs0]),
    spawn(fun()->brocast_act_msg(9,Signs0,13703,[?TYPE_RANK_START, SubTime]) end),
    Ref = erlang:send_after(RelaxT * 1000, self(), rank_war),
    {noreply, State#drumwar_mgr{action=9, state = ?RANKWAR, signs=gm_change_act(Signs0,[]), ref = Ref, etime = NEtime, sub_state = ?TYPE_RANK_START, sub_time = SubTime}};

do_handle_cast({gm_close}, State) ->
    #drumwar_mgr{ref=OldRef,signs=Signs,action=Act}=State,
    util:cancel_timer(get(summon_enter_ref)),
    util:cancel_timer(OldRef),
    {NSigns,_} = account_war(Act,Signs,mod_drumwar_mgr:get_kv(?WAR_SCENE),[],[]),
    Ref = erlang:send_after(10, self(), close),
    {noreply, State#drumwar_mgr{state = ?CLOSE, ref = Ref, signs = NSigns}};

%%模拟分析
do_handle_cast({analyse,Num,Time},State)->
    #drumwar_mgr{ref=ORef,signs=Signs}=State,
    util:cancel_timer(get(summon_enter_ref)),
    util:cancel_timer(ORef),
    Signs = make_signs(Num,[]),
    Ref = erlang:send_after(Time*1000,self(),ready),
    Etime = utime:unixtime()+Time,
    brocast_msg(13700,[?SIGN,Etime]),
    clear_all_role(),
    db:execute("TRUNCATE TABLE `drumwar_sign`"),
    db:execute("TRUNCATE TABLE `drumwar_result`"),
    {noreply, State#drumwar_mgr{state=?SIGN,action=1,signs=Signs,ref=Ref,etime=Etime}};

%%打印当前数据
do_handle_cast(print, State) ->
    % #drumwar_mgr{history=History}=State,
    % [insert_rank(R)||{_D,R}<-History],
    ?PRINT("State:~p~n", [State#drumwar_mgr.signs]),
    {noreply, State};

%%假人AI部分 激活假人
do_handle_cast({active_mon,Uid}, State) ->
    #drumwar_mgr{signs=Signs,mons=Mons} = State,
    case lists:keyfind(Uid,#drum_role.rid,Signs) of
        #drum_role{group=Group}->
            case lists:keyfind(Group,1,Mons) of
                {_,MonAi} when is_pid(MonAi)->
                    erlang:send_after(10, MonAi, {'change_attr', [{find_target, 0}]});
                    % {X, Y} = lib_role_drum:right_pos(),
                    % lib_role_drum:mon_move(MonAi, X, Y),
                    % NeedTime = max(lib_role_drum:calc_move_time({X, Y}, {X - 200, Y}, 280) - 110, 10),
                    % erlang:send_after(NeedTime, self(), {mon_rush,Uid});
                _->
                    %%居然找不到怪物AI
                    ignore
            end;
        _->
            %%居然找不到人
            ignore
    end,
    {noreply, State};

%%战斗结果
%%被假人击杀 惨 没有命数的时候离场
do_handle_cast({war_result,lose,Uid},State)->
    #drumwar_mgr{action=Act,signs=Signs, tip_info = TipInfo} = State,
    NSigns =  case lists:keyfind(Uid,#drum_role.rid,Signs) of
        DrumRole when is_record(DrumRole,drum_role) andalso DrumRole#drum_role.calc_type =< 0->
            #drum_role{
                live = Life,
                node = Node,
                rid  = RoleID,
                zid  = Zone,
                lose = L,
                scene = Scene,
                group = Group
            }=DrumRole,
            Nlife = max(Life-1,0),
            NDrumRole = DrumRole#drum_role{live=Nlife},
            {ok,Bin} = pt_137:write(13708,[is_over(Nlife),2,Act]),
            lib_role_drum:send_to_role(Node,RoleID,Bin),
            case Nlife =< 0 of
                true->
                    Nlose = L+1,
                    LNDrumRole = NDrumRole#drum_role{calc_type = 1, lose = Nlose},
                    {TipType, TipEndTime} = TipInfo,
                    {ok,Bin1} = pt_137:write(13705,[Act,LNDrumRole]),
                    {ok,Bin2} = pt_137:write(13717,[Act, TipType, TipEndTime]),
                    Bin3 = << Bin1/binary, Bin2/binary >>,
                    lib_role_drum:send_to_role(Node,RoleID,Bin3),
                    [{_,Award}] = data_drumwar:get_war(Zone,Act),
                    lib_role_drum:war_award(Node, Act, 0, RoleID, Award),
                    lib_role_drum:update_role_drum(Node,RoleID,Zone,Act),
                    lib_scene:clear_scene_room(Scene, 0, Group),
                    spawn(fun()->
                        timer:sleep(5000),
                        clusters_center:apply_cast(Node,?MODULE,enter_ready_local,[RoleID])
                    end);
                false->
                    LNDrumRole = NDrumRole
            end,
            %%日志
            log_drum_war(?LOG_LOSE, NDrumRole),
            lists:keyreplace(Uid,#drum_role.rid,Signs,LNDrumRole);
        _->
            Signs
    end,
    brocast_live(none,Uid,NSigns),
    {noreply,State#drumwar_mgr{signs=NSigns}};
%%击杀假人 不武 离场
do_handle_cast({war_result,win,Uid},State)->
    #drumwar_mgr{action=Act,signs=Signs, sub_time = ResultTime} = State,
    NSigns =  case lists:keyfind(Uid,#drum_role.rid,Signs) of
        DrumRole when is_record(DrumRole,drum_role) andalso DrumRole#drum_role.calc_type =< 0->
            #drum_role{
                rid  = RoleID,
                node = Node,
                zid  = Zone,
                scene = Scene,
                group = Group,
                win  = W
            }=DrumRole,
            Nwin = W+1,
            NDrumRole = DrumRole#drum_role{action=Act+1,win=Nwin,calc_type=1},
            {ok,Bin} = pt_137:write(13708,[1,1,Act]),
            {ok,Bin1} = pt_137:write(13705,[Act,NDrumRole#drum_role{action=Act}]),
            {ok,Bin2} = pt_137:write(13703,[?TYPE_SUCCESS,ResultTime]),
            BinData = << Bin/binary, Bin1/binary, Bin2/binary >>,
            lib_role_drum:send_to_role(Node, RoleID, BinData),
            [{Award,_}] = data_drumwar:get_war(Zone,Act),
            lib_role_drum:war_award(Node, Act, 1, RoleID, Award),
            lib_role_drum:update_role_drum(Node,RoleID,Zone,Act),
            lib_scene:clear_scene_room(Scene, 0, Group),
            spawn(fun()->
                timer:sleep(5000),
                clusters_center:apply_cast(Node,?MODULE,enter_ready_local,[RoleID])
            end),
            %%日志
            log_drum_war(?LOG_WIN, NDrumRole#drum_role{action=Act}),
            lists:keyreplace(Uid,#drum_role.rid,Signs,NDrumRole);
        _->
            Signs
    end,
    brocast_live(win,Uid,NSigns),
    {noreply,State#drumwar_mgr{signs=NSigns}};
%%真人击杀 先处理失败一方  才知道要不要清场  排位赛只走这里
do_handle_cast({war_result,WUid,LUid},State)->
    #drumwar_mgr{action=Act,signs=Signs,choice=Choice,choose=Choose, sub_time = ResultTime, tip_info = TipInfo} = State,
    {IsLeave,NSigns0,_LName, LCalc} =  case lists:keyfind(LUid,#drum_role.rid,Signs) of
        LDrum when is_record(LDrum,drum_role) andalso LDrum#drum_role.calc_type =< 0->
            #drum_role{
                live = Life,
                rid  = LRoleID,
                figure = #figure{name = LName0},
                node = LNode,
                zid  = LZone,
                lose = L
            }=LDrum,
            Nlife = max(Life-1,0),
            NLDrum = LDrum#drum_role{live=Nlife},
            {ok,LBin} = pt_137:write(13708,[is_over(Nlife),2,Act]),
            lib_role_drum:send_to_role(LNode,LRoleID,LBin),
            case Nlife =< 0 of
                true->
                    Nlose = L+1,
                    LNLDrum = NLDrum#drum_role{calc_type = 1, lose = Nlose},
                    {TipType, TipEndTime} = TipInfo,
                    {ok,LBin1} = pt_137:write(13705,[Act,LNLDrum]),
                    {ok,LBin2} = pt_137:write(13717,[Act, TipType, TipEndTime]),
                    LBin3 = << LBin1/binary, LBin2/binary >>,
                    lib_role_drum:send_to_role(LNode,LRoleID,LBin3),
                    [{_,LAward}] = data_drumwar:get_war(LZone,Act),
                    lib_role_drum:war_award(LNode, Act, 0, LRoleID, LAward),
                    lib_role_drum:update_role_drum(LNode,LRoleID,LZone,Act),
                    spawn(fun()->
                        timer:sleep(5000),
                        clusters_center:apply_cast(LNode,?MODULE,enter_ready_local,[LRoleID])
                    end);
                false->
                    LNLDrum = NLDrum
            end,
            {Nlife,lists:keyreplace(LUid,#drum_role.rid,Signs,LNLDrum),LName0, 1};
        _->
            {0,Signs,"", 0}
    end,
    {NSigns,Zone,WName, WCalc} =  case lists:keyfind(WUid,#drum_role.rid,NSigns0) of
        WDrum when is_record(WDrum,drum_role) andalso WDrum#drum_role.calc_type =< 0->
            #drum_role{
                rid  = WRoleID,
                node = WNode,
                figure = #figure{name = WName0},
                zid  = WZone,
                scene = Scene,
                group = Group,
                win  = W
            }=WDrum,
            Nwin = W+1,
            NWDrum = case IsLeave=<0 of
                true->
                    WDrum#drum_role{action=Act+1,win=Nwin,calc_type=1};
                _->
                    WDrum#drum_role{win=W}
            end,
            {ok,WBin} = pt_137:write(13708,[is_over(IsLeave),1,Act]),
            lib_role_drum:send_to_role(WNode,WRoleID,WBin),
            IsLeave=<0 andalso begin
                {ok,WBin1} = pt_137:write(13705,[Act,NWDrum#drum_role{action=Act}]),
                {ok,WBin2} = pt_137:write(13703,[?TYPE_SUCCESS,ResultTime]),
                BinData = << WBin1/binary, WBin2/binary >>,
                lib_role_drum:send_to_role(WNode, WRoleID, BinData),
                [{WAward,_}] = data_drumwar:get_war(WZone,Act),
                lib_role_drum:war_award(WNode, Act, 1, WRoleID, WAward),
                lib_role_drum:update_role_drum(WNode, WRoleID, WZone, Act),
                lib_scene:clear_scene_room(Scene, 0, Group),
                spawn(fun()->
                    timer:sleep(5000),
                    clusters_center:apply_cast(WNode,?MODULE,enter_ready_local,[WRoleID])
                end)
            end,
            {lists:keyreplace(WUid,#drum_role.rid,NSigns0,NWDrum),WZone,WName0, 1};
        WDrum when is_record(WDrum,drum_role) ->
            #drum_role{figure = #figure{name = RName}, zid = RZone}=WDrum,
            {NSigns0, RZone, RName, 0};
        _->
            {NSigns0, 1, "", 0}
    end,
    %%排位赛 在人员退场的时候 做一次检测  是否直接进入下一轮
    % Act >= 9 andalso IsLeave=<0 andalso
    % erlang:send_after(5000,self(),{enter_next_rank_war,Act+1}),
    Act >= 12 andalso IsLeave=<0 andalso begin
        TypeId = lib_role_drum:get_zone(Zone),
        OpenLv = data_drumwar:get_kv(?DRUMLV),
        clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv,{OpenLv, 9999}},137,TypeId,[WName]], 600),
        {ok,Bin} = pt_137:write(13712,[WUid, Zone,WName]),
        add_zone_win(Zone, WUid, WName),
        spawn(fun()->show_champion(Bin,Zone,NSigns) end) %%广播给同战区的玩家
    end,
    %%第九场之后的真人对决有效
    IsCalc = LCalc + WCalc, %%结算标志，防止临界状态，竞猜奖励二发
    Act >= 9 andalso IsLeave=< 0 andalso IsCalc == 2 andalso begin
        spawn(fun()->account_guess_result(Zone,Act,WUid,WName,LUid,Choice) end) %%海选赛后计算竞猜结果
    end,
    NChoose = case  Act >= 12 andalso IsLeave=<0 of
        true->%%决胜局 追加冠军
            Choose0 = add_results([WUid],NSigns,Choose),
            brocast_guess_msg(0,Choose0),
            Choose0;
        _->
            Choose
    end,
    %%命数广播一次
    brocast_live(WUid,LUid,NSigns),
    %%日志
    IsLeave=<0 andalso log_drum_war(WUid,LUid,Signs),
    {noreply,State#drumwar_mgr{signs=NSigns,choose=NChoose}};


%%通用回调
do_handle_cast({mod,Module,Method,Args},State)->
    NState = Module:Method(Args,State),
    {noreply, NState};

do_handle_cast(_Msg, State) ->
    % util:errlog("M:~p, Msg:~p~n", [?MODULE, Msg]),
	{noreply, State}.

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.

%%idle结束 进入报名
do_handle_info(sign,State)->
    #drumwar_mgr{history = History} = State,
    [SignT] = data_drumwar:get_sign(),
    %%开始再清次进程字典
    util:cancel_timer(get(summon_enter_ref)),
    erase({?MODULE, zone_win}),
    erase(summon_enter_ref),
    %%预告
    erlang:send_after( max( 1, (SignT-300) ) *1000, self(), tip),
    Ref = erlang:send_after(SignT*1000,self(),ready),
    Etime = utime:unixtime()+SignT,
    clusters_center:apply_to_all_node(?MODULE, start_act_handle, [], 100),
    brocast_msg(13700,[?SIGN,Etime]),
    {noreply, #drumwar_mgr{state = ?SIGN, ref = Ref, etime = Etime, history = History}};

%%报名结束 进入准备期 謝絕2048之後的玩家 玩家入场
do_handle_info(ready,State)->
    ?PRINT("ready~n",[]),
    db:execute("TRUNCATE TABLE `drumwar_sign`"),
    db:execute("TRUNCATE TABLE `drumwar_result`"),
    #drumwar_mgr{signs=Signs}=State,
    NeedLimit = case get_kv(?LIMIT_NUM) of
        Num when is_integer(Num) -> Num;
        _ -> 0
    end,
    case length(Signs)>= NeedLimit of
        false->
            OpenLv = data_drumwar:get_kv(?DRUMLV),
            clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv, {OpenLv, 9999}},137,8,[]], 300),
            {_Msg,_S,TimeOut} = cancel_next_calc_state(),
            Ref = erlang:send_after(TimeOut*1000,self(),sign),
            Etime = utime:unixtime() + TimeOut,
            clusters_center:apply_to_all_node(lib_activitycalen_api, success_end_activity, [?MOD_DRUMWAR], 100),
            brocast_msg(13700,[?IDLE,Etime]),
            {noreply, State#drumwar_mgr{state=?IDLE,signs=[],ref=Ref,etime=Etime}};
        true->
            {NSigns,ReadyOut} = ready_check(Signs),
            [ReadyT] = data_drumwar:get_sea_ready(),
            Ref = erlang:send_after(ReadyT*1000,self(),sea_war),
            Etime = utime:unixtime()+ReadyT,
            brocast_msg(13700,[?READY,Etime]),
            OpenLv = data_drumwar:get_kv(?DRUMLV),
            clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv, {OpenLv, 9999}},137,1,[]], 300),
            NewState = State#drumwar_mgr{
                state = ?READY, action = 1, signs = NSigns, cstate = 0,
                choose = [], ref = Ref, etime = Etime, ready_out = ReadyOut,
                sub_state = ?TYPE_SEA_START, sub_time = Etime
            },
            {noreply, NewState}
    end;

%%准备结束  进入海选 60s召唤人之前分划擂台
%%两两随机  单人补机器人  种子选手不相遇
%%循环这个阶段 直到剩余人数符合16强  进入16强争夺
do_handle_info(sea_war,State)->
    #drumwar_mgr{action = Act, signs = Signs, etime = OEtime}=State,
    Now = utime:unixtime(),
    [SeaPreT] = data_drumwar:get_sea_prepare(),
    [SeaEnterT] = data_drumwar:get_sea_enter(),
    [SeaWarT] = data_drumwar:get_sea_war(),
    [Etime, Signs1] = case Act == 1 of
        true-> %%首场 要分组
            AllT = (SeaWarT + SeaPreT + SeaEnterT + 1) * 8,
            EndTime = Now + AllT,
            brocast_msg(13700, [?SEAWAR, EndTime]),  %%海选32min
            {Signs0, _ZoneNum} = calc_zones(Signs),
            [EndTime, Signs0];
        _->
            [OEtime, Signs]
    end,
    if
        Act =< 8 -> %%海选8场
            %%10后拉人入场 所有人进入10s倒计时
            SubTime = Now + SeaPreT,
            TipEndTime = Now + SeaPreT + SeaEnterT + SeaWarT + 1,
            spawn(fun()-> brocast_act_msg(Act, Signs1, 13703, [?TYPE_FIGHT_START, SubTime]), brocast_act_tip(Act, 1, TipEndTime) end),
            Ref = erlang:send_after(SeaPreT * 1000, self(), summon_enter_notify),
            NewState = State#drumwar_mgr{
                state = ?SEAWAR, ref = Ref, cstate = 0, signs = Signs1, etime = Etime,
                sub_state = ?TYPE_FIGHT_START, sub_time = SubTime, tip_info = {1, TipEndTime}
            },
            {noreply, NewState};
        true->%%120s间隙 之后进入16强赛
            [RelaxT] = data_drumwar:get_rank_ready(),
            [RankPre] = data_drumwar:get_rank_prepare(),
            [RankEnter] = data_drumwar:get_rank_enter(),
            [RankWar] = data_drumwar:get_rank_war(),
            RankAll = RelaxT + 4 *(RankPre + RankWar + RankEnter + 1) + 10,
            NEtime = Now + RankAll,
            SubTime = Now + RelaxT,
            TipEndTime = Now + RelaxT,
            spawn(fun()->brocast_act_msg(Act, Signs1, 13703, [?TYPE_RANK_START, SubTime]), brocast_act_tip(Act, 2, TipEndTime) end),
            % brocast_msg(13700,[?RANKWAR,NEtime]),  %%排位赛26min
            Ref = erlang:send_after(RelaxT * 1000, self(), rank_war),
            NewState = State#drumwar_mgr{
                state = ?RANKWAR, ref = Ref, etime = NEtime, sub_state = ?TYPE_RANK_START,
                sub_time = SubTime, tip_info = {2, TipEndTime}
            },
            {noreply, NewState}
    end;

%%海选通知玩家入场倒计时
do_handle_info(summon_enter_notify, State)->
    #drumwar_mgr{action = Act, signs = Signs} = State,
    [SeaEnterT] = data_drumwar:get_sea_enter(),
    [SeaWarT] = data_drumwar:get_sea_war(),
    SRef = erlang:send_after(SeaEnterT * 1000, self(), summon_enter),
    put(summon_enter_ref, SRef),
    Now = utime:unixtime(),
    SubTime = Now + SeaEnterT,
    spawn(fun()-> brocast_act_msg(Act, Signs, 13703, [?TYPE_FIGHT_ENTER, SubTime]) end),
    %%4分钟后强制结算 战斗三分钟
    Ref = erlang:send_after((SeaEnterT + SeaWarT + 1) * 1000, self(), sea_war_result),
    NSigns = calc_group(Signs, Act),
    % ?PRINT("~p~n",[[Signs, NSigns]]),
    NewState = State#drumwar_mgr{ref = Ref, signs = NSigns, sub_state = ?TYPE_FIGHT_ENTER, sub_time = SubTime},
    {noreply, NewState};

%%海选召唤玩家入场 有机器人
do_handle_info(summon_enter,State)->
    % ?PRINT("summon_enter~n",[]),
    #drumwar_mgr{action = Act, signs = Signs}=State,
    [SeaWarT] = data_drumwar:get_sea_war(),
    Now = utime:unixtime(),
    FitghtEndTime = Now + SeaWarT + 1,
    spawn(fun()->brocast_act_msg(Act, Signs, 13703, [?TYPE_FIGHT_END, FitghtEndTime]) end),
    Mons = summon_role_enter(Act, Signs, Signs, Now, []),
    NewState = State#drumwar_mgr{cstate = 0, mons = Mons, sub_state = ?TYPE_SUCCESS, sub_time = FitghtEndTime},
    {noreply, NewState};

%%中场结算(强制结算还在场内战斗的) 把人踢回准备场景 进入下一场
do_handle_info(sea_war_result,State)->
    #drumwar_mgr{action=Act,signs=Signs}=State,
    {NSigns,_} = account_war(Act,Signs,mod_drumwar_mgr:get_kv(?WAR_SCENE),[],[]),
    %%推送各战区传闻
    spawn(fun()-> lib_role_drum:send_tv(Act,Signs), brocast_refresh_act_info(Act + 1, get_zone_win(), NSigns) end),
    clear_all_mons(mod_drumwar_mgr:get_kv(?WAR_SCENE)),
    self() ! sea_war,
    {noreply, State#drumwar_mgr{signs = NSigns, mons = [], action = Act + 1}};

%% 海选赛间隙完毕 进入排位赛 循环
%% 小于等于1时 不进入下一场 有轮空情况
do_handle_info(rank_war,State)->
    #drumwar_mgr{action = Act, signs = Signs, choose = Guess, etime = Etime}=State,
    %%给16强排序 只剩一人的组 直接冠军
    Now = utime:unixtime(),
    %%刚进入排位赛推送
    case Act == 9 of
        true->
            brocast_msg(13700, [?RANKWAR, Etime]);  %%排位赛26min
        false-> ok
    end,
    case Act =< 12 of  %%继续排名赛
        true->
            %%15s后拉人入场
            [RankPre] = data_drumwar:get_rank_prepare(),
            [RankEnter] = data_drumwar:get_rank_enter(),
            [RankWar] = data_drumwar:get_rank_war(),
            SubTime = Now + RankPre,
            TipEndTime = Now + RankPre + RankEnter + RankWar + 1,
            spawn(fun()-> brocast_act_msg(Act, Signs, 13703, [?TYPE_FIGHT_START, SubTime]), brocast_act_tip(Act, 1, TipEndTime) end),
            Ref = erlang:send_after(RankPre * 1000, self(), summon_rank_enter_notify),
            {NSigns, NGuess} = calc_rank_group(Signs, Act, Guess),
            CTime = Now + RankPre + RankEnter,
            %%冠军直接提示
            {LNsigns, LNGuess} = calc_champion(NSigns, NGuess, []),
            brocast_guess_msg(CTime, LNGuess),
            NewState = State#drumwar_mgr{
                state = ?RANKWAR, cstate = 1, choose = LNGuess, signs = LNsigns, ref = Ref,
                ctime = CTime, sub_state = ?TYPE_FIGHT_START, sub_time = SubTime,
                tip_info = {1, TipEndTime}
            },
            {noreply, NewState};
        _->%%进入结束
            Ref = erlang:send_after(1000, self(), close),
            {noreply, State#drumwar_mgr{state = ?CLOSE, ref = Ref}}
    end;

%%排位赛通知玩家入场倒计时
do_handle_info(summon_rank_enter_notify, State)->
    #drumwar_mgr{action = Act, signs = Signs} = State,
    [RankEnter] = data_drumwar:get_rank_enter(),
    [RankWar] = data_drumwar:get_rank_war(),
    Now = utime:unixtime(),
    SubTime = Now + RankEnter,
    spawn(fun()-> brocast_act_msg(Act, Signs, 13703, [?TYPE_FIGHT_ENTER, SubTime]) end),
    SRef = erlang:send_after(RankEnter * 1000, self(), summon_rank_enter),
    put(summon_enter_ref, SRef),
    Ref = erlang:send_after((RankEnter + RankWar + 1) * 1000, self(), {rank_war_result, Act}),
    {noreply, State#drumwar_mgr{ref = Ref, sub_state = ?TYPE_FIGHT_ENTER, sub_time = SubTime}};

%%排位赛召唤玩家入场  有轮空
do_handle_info(summon_rank_enter,State)->
    #drumwar_mgr{action = Act, signs = Signs, choose = Choose}=State,
    [RankWar] = data_drumwar:get_rank_war(),
    Now = utime:unixtime(),
    FitghtEndTime = Now + RankWar + 1,
    spawn(fun()-> brocast_act_msg(Act, Signs, 13703, [?TYPE_FIGHT_END, FitghtEndTime]) end),
    {NSigns, Wins} = summon_rank_enter(Act, Signs, [], Now, FitghtEndTime, []),
    %%之前calc_champion()已处理冠军事件，这里保留旧代码兼容
    NChoose = add_results(Wins, NSigns, Choose),
    {noreply, State#drumwar_mgr{cstate = 0, sub_state = ?TYPE_SUCCESS, sub_time = FitghtEndTime, signs = NSigns, choose = NChoose}};

%%排名赛 超时 结算
do_handle_info({rank_war_result,CurAct},State)->
    #drumwar_mgr{action = Act, signs = Signs, choice = Choice, choose = Choose}=State,
    case CurAct =< Act of
        true->
            %%排位赛 人少 取8组人时的场景
            {NSigns, Wins} = account_war(Act, Signs, [lib_role_drum:get_war(8)], Choice, []),
            NChoose = case CurAct >= 12 of
                true->
                    add_results(Wins, NSigns, Choose);
                _->
                    Choose
            end,
            self() ! rank_war,
            clear_all_mons(mod_drumwar_mgr:get_kv(?WAR_SCENE)),
            brocast_refresh_act_info(Act + 1, get_zone_win(), NSigns),
            {noreply, State#drumwar_mgr{action = Act+1, choice = [], choose = NChoose, signs = NSigns}};
        _->
            Ref = erlang:send_after(1000, self(), close),
            %%提前结算掉了
            {noreply, State#drumwar_mgr{ref = Ref}}
    end;

%%活动结束 做最终各区16强排序 先分区
%%在各区有上至下排序  冠军有标记  无标记的 正常排
%%按照排名发奖励
do_handle_info(close,State)->
    #drumwar_mgr{signs=Signs,history=History}=State,
    brocast_msg(13700,[?CLOSE,0]),
    NSigns = final_account(Signs,4),
    Ref = erlang:send_after(5000,self(),kict_role),
    DrumID = get_id(),
    SignsR = [begin
        #drum_role{
            zid = Zone,
            rid = Rid,
            figure = #figure{name=Name,guild_name=GName,vip=Vip,career=Career},
            platform = PForm,
            server_id = ServerId,
            server_num = Snum,
            rank = Rank,
            power = Pow
        }=Sign,
        #rank_role{
            drum = DrumID,
            zone = Zone,
            rid  = Rid,
            name = Name,
            gname = GName,
            server_id = ServerId,
            platform = PForm,
            servernum = Snum,
            rank = Rank,
            vip = Vip,
            power = Pow,
            career = Career
        }
    end ||Sign<-NSigns,Sign#drum_role.action>=9],
    NHistory = delete_overdue(DrumID,SignsR,History),
    close_handle(State),
    {noreply, State#drumwar_mgr{state = ?CLOSE, signs = NSigns, ref = Ref, history = NHistory}};

%%踢人
do_handle_info(kict_role,State)->
    #drumwar_mgr{choose = _Choose, history = History}=State,
    util:cancel_timer(get(summon_enter_ref)),
    erase({?MODULE, zone_win}),
    erase(summon_enter_ref),
    clear_all_role(),
    clusters_center:apply_to_all_node(?MODULE, end_act_handle, [0], 100),
    {_Msg,S,TimeOut} = calc_state(),
    brocast_msg(13700,[?IDLE,utime:unixtime()+TimeOut]),
    Ref = erlang:send_after(TimeOut*1000,self(),sign),
    {noreply, #drumwar_mgr{history = History, state = S, etime = utime:unixtime() + TimeOut, ref = Ref}};
%%闲置循环
do_handle_info(idle,State)->
    % io:format("~p~n",[{idle,util:now_to_date()}]),
    {Msg,S,TimeOut} = calc_state(),
    Ref = erlang:send_after(TimeOut*1000,self(),Msg),
    {noreply, State#drumwar_mgr{state=S,signs=[],etime=utime:unixtime()+TimeOut,ref=Ref}};
%%闲置预告
do_handle_info(tip,State)->
    %%5分钟预告
    OpenLv = data_drumwar:get_kv(?DRUMLV),
    clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv, {OpenLv, 9999}},137,4,[]], 600),
    {noreply, State};

%%冲刺
do_handle_info({mon_rush,Uid}, State) ->
    #drumwar_mgr{signs=Signs,mons=Mons} = State,
    case lists:keyfind(Uid,#drum_role.rid,Signs) of
        #drum_role{group=Group}->
            case lists:keyfind(Group,1,Mons) of
                {_,MonAi}->
                    {X, Y} = lib_role_drum:right_pos(),
                    lib_role_drum:mon_rush(MonAi, X, Y),
                    NeedTime = max(lib_role_drum:calc_move_time({X-200, Y}, {X - 500, Y}, 600) - 110, 10),
                    %io:format("~p~n",[{X, Y,NeedTime}]),
                    erlang:send_after(NeedTime, self(), {mon_battle,Uid});
               _->
                    %%居然找不到怪物AI
                    ignore
            end;
        _->
            %%居然找不到人
            ignore
    end,
    {noreply, State};

%%战斗
do_handle_info({mon_battle,Uid}, State) ->
    #drumwar_mgr{signs=Signs,mons=Mons} = State,
    case lists:keyfind(Uid,#drum_role.rid,Signs) of
        #drum_role{group=Group}->
            case lists:keyfind(Group,1,Mons) of
                {_,MonAi}->
                    lib_role_drum:mon_battle(MonAi,Group);
                _->
                    %%居然找不到怪物AI
                    ignore
            end;
        _->
            %%居然找不到人
            ignore
    end,
    {noreply, State};

%%判断是否直接进入下一场 排位赛只有一个场景  16*4人用不上太多
do_handle_info({enter_next_rank_war,NAct},State)->
    #drumwar_mgr{action=Act}=State,
    case NAct > Act of
        true->
            Scene = lib_role_drum:get_war(8),
            case catch mod_scene_agent:apply_call(Scene,0,lib_scene_agent,get_scene_user,[]) of
                []-> %%战斗场无人  直接进入下一轮
                    self() ! rank_war,
                    {noreply,State#drumwar_mgr{action=Act+1}};
                _->
                    {noreply,State}
            end;
        _->
            {noreply,State}
    end;

do_handle_info(_Msg, State) ->
	% util:errlog("M:~p, Msg:~p~n", [?MODULE, Msg]),
	{noreply, State}.

%% ---------------------------------------------------------------------------
handle_call(Msg, From, State) ->
    case catch do_handle_call(Msg, From, State) of
        {reply, Reply, NewState} ->
            {reply, Reply, NewState};
        _Reason ->
            ?ERR("handle_call Request: ~p, Reason=~p~n", [Msg, _Reason]),
            {reply, ok, State}
    end.

%%通用回调
do_handle_call({mod, Module, Method, Args},_From,State)->
    Result = Module:Method(Args, State),
    {reply, Result, State};
do_handle_call(_Msg, _From, State) ->
    {reply, ok, State}.

terminate(_Reason, _State) ->
	_Reason /= normal andalso ?ERR("terminate Request: ~p, Reason=~p~n", [over, _Reason]),
    ok.
code_change(_OldVsn, State, _Extra) ->
	{ok, State}.

%%战区划分
calc_zones(Signs)->
    calc_zones(Signs,[],[]).

calc_zones([],Signs,ZoneNum)->
    {Signs,ZoneNum};
calc_zones([DrumRole|OSigns],Signs,ZoneNum)->
    #drum_role{figure = Figure}=DrumRole,
    ZoneID = trans_zone(Figure),
    NDrumRole = DrumRole#drum_role{zid=ZoneID},
    NSigns = [NDrumRole|Signs],
    %%计算战区人数
    NZoneNum = case lists:keyfind(ZoneID,1,ZoneNum) of
        false->[{ZoneID,1}|ZoneNum];
        {_,ONum}-> lists:keyreplace(ZoneID,1,ZoneNum,{ZoneID,ONum+1})
    end,
    calc_zones(OSigns,NSigns,NZoneNum).

%%等级转战区
trans_zone(Figure) ->
    #figure{lv = RoleLv} = Figure,
    % LegendLv = lib_player:get_legend_lv(Figure),
    % {IsLegend, Lv} = case LegendLv > 0 of
    %     true-> {?LEGEND_TYPE, LegendLv};
    %     false-> {?NOT_LEGEND_TYPE, RoleLv}
    % end,
    ZoneId = data_drumwar:lv_to_zone(0, RoleLv),
    ?IF(ZoneId > 1, 1, ZoneId).

%%海选分组 要先分战区
calc_group(Signs, Act)->
    calc_group(Signs, 4, [], 1, Act).

calc_group(LeftSigns, Z, Signs , _, _) when Z =< 0->
    Signs ++ LeftSigns;
calc_group(LeftSigns, Zone, Signs, Group, Act)->
    {Total, NLeftSigns} = calc_online_and_live(LeftSigns, Zone, Act, [], []),
    All = length(Total),
    {NGroup, NSubSigns} = case All =< ideal_value(Act) of
        true->%%人数不足  大家打AI
            match_ai(Total, Group, []);
        _->
            case All > 2 * ideal_value(Act) of
                true->%%异常 人数超标 互相PK  多余的人 不管了
                    %%有足够的玩家 执行真人对决
                    Num = 2 * ideal_value(Act),
                    {SignsPk, _R} = lists:split(Num, compare_data(Total)), %%多的人放弃了
                    calc_sub_group(ulists:list_shuffle(SignsPk), [], Group, []);
                _->
                    %%有足够的玩家 部分人真人PK淘汰
                    Num = All - 2 * (All - ideal_value(Act)),  %%这部分人打AI
                    {SignAi, SignsPk} = lists:split(Num, compare_data(Total)),
                    {Group0, NSignsAi} = match_ai(SignAi, Group, []),
                    %%筛选种子选手
                    {SeedSigns, SubSigns, _} = calc_seed(SignsPk),%%把排名前16筛选出来SeedSigns，剩下的Subsigns
                    calc_sub_group(ulists:list_shuffle(SubSigns), SeedSigns, Group0, NSignsAi)
            end
    end,
    calc_group(NLeftSigns, Zone-1, NSubSigns++Signs, NGroup, Act).

%%区分在线并且晋级的和不在线或者淘汰的
calc_online_and_live([], _Zone, _Act, Signs, LeftSigns) -> {Signs, LeftSigns};
calc_online_and_live([#drum_role{node = Node, rid = Uid, zid = Zone, action = Act, online = 0, lose = Lose} = DrumRole | T], Zone, Act, Signs, LeftSigns) -> %%匹配不在线的算输
    case Lose >= 1 of
        false->
            [{_, Award}] =  data_drumwar:get_war(Zone, Act),
            lib_role_drum:war_award(Node, Act, 0, Uid, Award),
            lib_role_drum:update_role_drum(Node, Uid, Zone, Act),
            log_drum_war(6, DrumRole#drum_role{live = 0, lose = 1});
        true -> ok
    end,
    calc_online_and_live(T, Zone, Act, Signs, [DrumRole#drum_role{live = 0, lose = 1}|LeftSigns]);
calc_online_and_live([#drum_role{zid = Zone, action = Act, online = 1, live = Live} = DrumRole | T], Zone, Act, Signs, LeftSigns)
    when Live > 0-> calc_online_and_live(T, Zone, Act, [DrumRole|Signs], LeftSigns);
calc_online_and_live([DrumRole |T], Zone, Act, Signs, LeftSigns) ->
    calc_online_and_live(T, Zone, Act, Signs, [DrumRole| LeftSigns]).

%%战区分组 种子选手不遇 210人一个场景 即105组 10*210
calc_sub_group([], [], Group, Signs)->
    {Group, Signs};
%%低阶玩家被匹配玩 你们只能自己打
calc_sub_group([], SeedSigns, Group, Signs)->
    case SeedSigns of
        [A0,B0|T]->
            A = A0#drum_role{group=Group,ai=0,pos=1,ruid=B0#drum_role.rid,calc_type=0},
            B = B0#drum_role{group=Group,ai=0,pos=0,ruid=A0#drum_role.rid,calc_type=0},
            calc_sub_group([], T, Group+1, [A,B|Signs]);
        [A0]->
            A = A0#drum_role{group=Group,ai=1,pos=1,ruid=0,calc_type=0},
            calc_sub_group([], [], Group+1, [A|Signs]);
        _->
            calc_sub_group([], [], Group, Signs)
    end;
%%没有种子选手  低阶玩家自己打
calc_sub_group(OSigns, [], Group, Signs)->
    case OSigns of
        [A0,B0|T]->
            A = A0#drum_role{group=Group,ai=0,pos=1,ruid=B0#drum_role.rid,calc_type=0},
            B = B0#drum_role{group=Group,ai=0,pos=0,ruid=A0#drum_role.rid,calc_type=0},
            calc_sub_group(T, [], Group+1, [A,B|Signs]);
        [A0]->
            A = A0#drum_role{group=Group,ai=1,pos=1,ruid=0,calc_type=0},
            calc_sub_group([], [], Group+1, [A|Signs]);
        _->
            calc_sub_group([], [], Group, Signs)
    end;
%%优先给种子匹配低阶对手
calc_sub_group(OSigns, [Seed|SeedSigns], Group, Signs)->
    case OSigns of
        [B0|T]->
            Nseed = Seed#drum_role{group=Group,ai=0,pos=1,ruid=B0#drum_role.rid,calc_type=0},
            B = B0#drum_role{group=Group,ai=0,pos=0,ruid=Seed#drum_role.rid,calc_type=0},
            calc_sub_group(T, SeedSigns, Group+1, [Nseed,B|Signs]);
        _->
            Nseed = Seed#drum_role{group=Group,ai=1,pos=1,ruid=0,calc_type=0},
            calc_sub_group(OSigns, SeedSigns, Group+1, [Nseed|Signs])
    end.


%%排位赛分组 先获取晋级玩家 再划分分区  再配对(这里要对group重新赋值)
calc_rank_group(Signs,Act,Guess)->
    Signs0 = [DrumR||DrumR<-Signs,DrumR#drum_role.action == Act],
    SignsL = [DrumR||DrumR<-Signs,DrumR#drum_role.action /= Act],
    case Act == 9 of
        true-> NSign0 = ulists:list_shuffle(Signs0);
        false-> NSign0 = Signs0
    end,
    {NSigns,NGuess} = calc_sub_rank_group(NSign0,Guess),
    {NSigns++SignsL,NGuess}.

calc_sub_rank_group([], Guess) -> {[], Guess};
calc_sub_rank_group(Signs,Guess)->
    calc_sub_rank_group(Signs,4,1,[],Guess).

calc_sub_rank_group(_,0,_,NSigns,Guess)->
    {NSigns,Guess};
calc_sub_rank_group(Signs,Zone,Group,NSigns,Guess)->
    Signs0 = [DrumR||DrumR<-Signs,DrumR#drum_role.zid==Zone],
    [NGroup,Signs1,NGuess] = case Signs0 of
        [] -> %%该区无人
            [Group,Signs0,Guess];
        [Win]->%%只剩冠军 不予分组 标识冠军
            Nwin = Win#drum_role{one=1,group=0,calc_type=0},
            #drum_role{action=Act}=Nwin,
            NewGuess = empty_add_guess(Zone,Act,{Nwin},Guess),
            [Group,[Nwin],NewGuess];
        _R->
            match_group(Signs0,Group,[],Guess)
    end,
    calc_sub_rank_group(Signs,Zone-1,NGroup,Signs1++NSigns,NGuess).

%%轮空竞猜填补
empty_add_guess(_Zone,13,_Value,Guess) -> Guess;
empty_add_guess(Zone,Act,Value,Guess) ->
    NGuess = add_guess(Zone,Act,Value,Guess),
    empty_add_guess(Zone,Act+1,Value,NGuess).

%%对手匹配
match_group([],Group,NSigns,NGuess)->
    [Group,NSigns,NGuess];
match_group(Signs,Group,NSigns,Guess)->
    case Signs of
        [A,B|T]->
            Na = A#drum_role{group=Group,ai=0,pos=1,ruid=B#drum_role.rid,calc_type=0},
            Nb = B#drum_role{group=Group,ai=0,pos=0,ruid=A#drum_role.rid,calc_type=0},
            #drum_role{zid=Zid,action=Act}=Na,
            NGuess = add_guess(Zid,Act,{Na,Nb},Guess),
            match_group(T,Group+1,[Na,Nb|NSigns],NGuess);
        [C]->%%一个人
            Nc = C#drum_role{group=Group,ai=1,pos=1,ruid=0,calc_type=0},
            #drum_role{zid=Zid,action=Act}=Nc,
            match_group([],Group+1,[Nc|NSigns],add_guess(Zid,Act,{Nc},Guess))
    end.

%%打完直接算冠军
calc_champion([],Guess,NSigns)->{lists:reverse(NSigns),Guess};
calc_champion([#drum_role{one=1,group=0}=DrumRole|T] = OSigns,Guess,NSigns)->
    #drum_role{node=Node,rid=RoleID,zid=Zid,figure=Figure,action=Act} = DrumRole,
    Name = Figure#figure.name,
    {ok,Bin1} = pt_137:write(13708,[1,5,Act]),
    {ok,Bin2} = pt_137:write(13705,[Act,DrumRole#drum_role{win = 12, action=Act}]),
    {ok,Bin0} = pt_137:write(13712,[RoleID, Zid,Name]),
    BinData = << Bin0/binary, Bin1/binary, Bin2/binary >>,
    lib_role_drum:send_to_role(Node, RoleID, BinData),
    lib_role_drum:update_role_drum(Node,RoleID,Zid,12),
    TypeId = lib_role_drum:get_zone(Zid),
    OpenLv = data_drumwar:get_kv(?DRUMLV),
    clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv, {OpenLv, 9999}},137,TypeId,[Name]], 600),
    spawn(fun()->show_champion(Bin0,Zid,NSigns++OSigns) end),
    calc_empty_champion_reward(Node, RoleID, Zid, Act),
    NewDrumRole = DrumRole#drum_role{action = 13, one = 0, win = 12, calc_type = 1},
    LNsigns = [NewDrumRole|NSigns],
    add_zone_win(Zid, RoleID, Name),
    NGuess = add_results([RoleID],LNsigns,Guess),
    log_drum_war(?LOG_EMPTY, NewDrumRole),
    calc_champion(T,NGuess,LNsigns);
calc_champion([DrumRole|T],Guess,NSigns)->
    calc_champion(T,Guess,[DrumRole|NSigns]).

%%轮空玩家计算到12场的累积奖励
calc_empty_champion_reward(_Node, _RoleID, _Zid, Act) when Act < 9 -> ok;
calc_empty_champion_reward(_Node, _RoleID, _Zid, Act) when Act > 12->
    ok;
calc_empty_champion_reward(Node, RoleID, Zid, Act) ->
    [{Award,_}] = data_drumwar:get_war(Zid, Act),
    lib_role_drum:war_award(Node, Act, 1, RoleID, Award),
    calc_empty_champion_reward(Node, RoleID, Zid, Act + 1).

%%Gm开启 10s后
gm_start(Time)->
    cast_center([{gm_start,Time}]).

%%模拟 10s后
analyse(Num,Time)->
    cast_center([{analyse,Num,Time}]).

%%gm开启排位赛
gm_startrank() ->
    cast_center([{gm_startrank}]).

%%gm结束排位赛
gm_closedrum()->
    cast_center([{gm_close}]).

gm_change_act([],Result)->Result;
gm_change_act([Role|T],Result) ->
    gm_change_act(T,[Role#drum_role{action=9}|Result]).


%%输出当前人员
print()->
    cast_center([print]).

%%计算开放 0未开放 1报名期间 2准备期间 3海选期间 4至强 5已结算 3 4其实都算比赛期间
calc_state()->
    {Date, _} = calendar:local_time(),
    Day = utime:day_of_week(),
    [OpenT] = data_drumwar:get_open(),
    [C] = data_drumwar:get_sign(),
    case lists:keyfind(Day,1,OpenT) of
        {_,H,M,S}->
            StartTime = {H,M,S},
            Start = utime:unixtime({Date, StartTime}),
            Now   = utime:unixtime(),
            End   = Start+C,
            if
                Now=<Start->
                    {sign, ?IDLE, max(Start-Now,1)};   %%处于闲置状态  即将进入报名状态
                Now=<End ->
                    {ready, ?SIGN, max(End-Now,1)}; %%处于报名状态  即将进入准备阶段
                true->
                    next_calc_state()
                     %活动期间 准备结束 已结束 准备下次
            end;
        _->
            next_calc_state()
    end.

%%下次开启时间
next_calc_state() ->
    [[OpenT]] = data_drumwar:get_open(),
    Day = utime:day_of_week(),
    {OpenW,OpenH,OpenM,OpenS} = OpenT,
    OpenTime = OpenH*3600 + OpenM*60 + OpenS,
    if
        OpenW == Day ->
            Reamain = 7*86400 + OpenTime - utime:get_seconds_from_midnight();
        OpenW > Day ->
            LeftDay = OpenW - Day,
            Reamain = LeftDay * 86400 + OpenTime - utime:get_seconds_from_midnight();
        true ->
            LeftDay = 7-(Day-OpenW),
            Reamain = LeftDay * 86400 + OpenTime - utime:get_seconds_from_midnight()
    end,
    LastRemain = max(Reamain,10),
    {sign, ?IDLE, LastRemain}.

%%取消开启，获取下次开启时间
cancel_next_calc_state()->
    {Date, _} = calendar:local_time(),
    Day = utime:day_of_week(),
    [OpenT] = data_drumwar:get_open(),
    case lists:keyfind(Day,1,OpenT) of
        {_,H,M,S}->
            StartTime = {H,M,S},
            Start = utime:unixtime({Date, StartTime}) + 7*86400,
            % TipTime = Start - 5*60,
            Now   = utime:unixtime(),
            {sign, ?IDLE, Start - Now};
        _->
            next_calc_state() %%木有活动 常规检测倒计时
    end.

%%构造报名玩家  分析用
make_signs(Num,Signs) when Num=<0->
    Signs;
make_signs(Num,Signs)->
    S = #drum_role{
        rid = Num
        ,figure = #figure{lv = urand:rand(1,100)}
        ,live = 1 %%命数 默认1
        ,online = 0
        ,action = 1  %%默认正在参与第一场
        ,power =urand:rand(1000,10000000)
    },
    make_signs(Num-1,[S|Signs]).


%%计算种子选手
calc_seed(SubSigns)->
    case length(SubSigns) =< 16 of
        true->
            {SubSigns,[],SubSigns};
        _->
            NSubSigns = compare_data(SubSigns),
            {SeedSigns,Signs}=lists:split(16,NSubSigns),
            {SeedSigns,Signs,NSubSigns}
    end.

%%排序 战力
compare_data(SubSigns)->
    lists:sort(fun(A1, A2) ->
            compare_data(A1, A2)
    end, SubSigns).

compare_data(V1, V2) ->
    Figure1 = V1#drum_role.figure,
    Figure2 = V2#drum_role.figure,
    case V1#drum_role.power == V2#drum_role.power of
        true ->
            Figure1#figure.lv >= Figure2#figure.lv;
        false ->
            case V1#drum_role.power > V2#drum_role.power of
                true->
                    true;
                _->
                    false
            end
    end.

%%广播状态数据
brocast_msg(13700,[State,Time])->
    {ok,Bin} = pt_137:write(13700,[State,Time]),
    clusters_center:apply_to_all_node(?MODULE, brocast_msg, [Bin]).

brocast_msg(Bin) ->
    OpenDay = util:get_open_day(),
    NeedOpenDay = get_kv(?OPEN_DAY),
    ?IF(OpenDay >= NeedOpenDay, lib_server_send:send_to_all(Bin), ok).

%%广播场次倒计时
brocast_act_tip(Act, Type, Time)->
    {ok,Bin} = pt_137:write(13717,[Act, Type, Time]),
    clusters_center:apply_to_all_node(lib_server_send, send_to_all, [Bin], 10).

%%广播竞猜数据
brocast_guess_msg(CTime,Guess)->
    {ok,Bin} = pt_137:write(13713,[CTime,Guess]),
    clusters_center:apply_to_all_node(?MODULE, brocast_guess_msg, [Bin]).

brocast_guess_msg(Bin) ->
    OpenDay = util:get_open_day(),
    NeedOpenDay = get_kv(?OPEN_DAY),
    ?IF(OpenDay >= NeedOpenDay, lib_server_send:send_to_all(Bin), ok).

brocast_act_msg(_Act,[],13703,[_Type,_RankPre])->
    ignore;
brocast_act_msg(Act,[Sign|Signs],13703,[Type,Time])->
    #drum_role{node=Node,rid=Rid,action=RAct,online=Online}=Sign,
    %%海选赛更新阶段推送给场景内外人
    IsCheck = ?IF(Type == ?TYPE_FIGHT_START, true, Online == 1),
    case RAct>=Act andalso RAct=<12 andalso IsCheck of
        true->
            {ok,Bin} = pt_137:write(13703,[Type,Time]),
            lib_role_drum:send_to_role(Node,Rid,Bin);
        _->
            ignore
    end,
    brocast_act_msg(Act,Signs,13703,[Type,Time]).

%%广播给玩家更新场次数据
brocast_refresh_act_info(_Act, _WinZone, []) -> ok;
brocast_refresh_act_info(Act, WinZone, [#drum_role{rid = RoleId, zid = Zid, node = Node, scene = Scene} = DrumRole | T]) when Scene > 0 ->
    case lists:keymember(Zid, 1, WinZone) of
        true -> ok;
        _ ->
            {ok, Bin} = pt_137:write(13705, [Act, DrumRole]),
            lib_role_drum:send_to_role(Node, RoleId, Bin)
    end,
    brocast_refresh_act_info(Act, WinZone, T);
brocast_refresh_act_info(Act, WinZone, [_DrumRole | T]) ->
    brocast_refresh_act_info(Act, WinZone, T).

%%拖人入擂台  拖人的时候人不在线 则通知对方直接获胜
summon_role_enter(_, [], _Signs, _ActionSt, Mons)->
    Mons;
summon_role_enter(Act, [#drum_role{action = Act, group  = Group} = DrumRole|Signs], Signs1, ActionSt, Mons) when Group > 0->
    #drum_role{
        node = Node,
        rid  = RoleID,
        live = Alife,
        ai   = Ai,
        ruid = RUid,
        pos  = Pos
    }=DrumRole,
    Blife = case Ai =< 0 of
        true->
            case lists:keyfind(RUid,#drum_role.rid,Signs1) of
                #drum_role{live=B}->
                    B;
                _->
                    1
            end;
        _->
            1
    end,
    {MonAid, MonAutoId} = case Ai of
        0->
            {0, RUid};
        _->
            lib_role_drum:create_mon(DrumRole, ActionSt)
    end,
    clusters_center:apply_cast(Node, lib_role_drum, enter_war_local, [RoleID, RUid, Group, Pos, ActionSt]),
    {ok,Bin} = pt_137:write(13710,[Alife, RUid, Blife]),
    {ok, Bin1} = pt_137:write(13716, [Pos, MonAutoId]),
    lib_role_drum:send_to_role(Node, RoleID, Bin1),
    lib_role_drum:send_to_role(Node, RoleID, Bin),
    summon_role_enter(Act, Signs, Signs1, ActionSt, [{Group,MonAid}|Mons]);
summon_role_enter(Act, [_DrumRole|Signs], Signs1, ActionSt, Mons)->
    summon_role_enter(Act, Signs, Signs1, ActionSt, Mons).

%%排位赛入场
summon_rank_enter(_, [], NSigns, _ActionSt, _ResultTime, Wins)->
    {NSigns,Wins};
summon_rank_enter(Act, [DrumRole|Signs], NSigns, ActionSt, ResultTime, Wins)->
    #drum_role{
        node = Node,
        rid  = RoleID,
        zid  = Zid,
        live = Alife,
        action = DAct,
        group = Group,
        figure = #figure{name=Name},
        one  = One,
        ruid = RUid,
        ai   = Ai,
        win = W,
        pos = Pos
    }=DrumRole,
    Uid = RoleID,
    [NDrumRole, NWins] = case Act == DAct of
        true when Group>0 andalso Ai=<0 -> %%正常进入比赛
            Blife = case lists:keyfind(RUid, #drum_role.rid, Signs++NSigns) of
                #drum_role{live = B}->
                    B;
                _->
                    1
            end,
            {ok, Bin} = pt_137:write(13710, [Alife, RUid, Blife]),
            {ok, Bin1} = pt_137:write(13716, [Pos, RUid]),
            lib_role_drum:send_to_role(Node, RoleID, Bin1),
            lib_role_drum:send_to_role(Node, RoleID, Bin),
            clusters_center:apply_cast(Node, lib_role_drum, enter_war_local, [RoleID, RUid, Group, Pos, ActionSt]),
            [DrumRole, Wins];
        true when Group>0 andalso Ai>0-> %%轮空 获胜 直接进入下一轮
            {ok, Bin} = pt_137:write(13708, [1, 4, Act]),
            {ok, Bin1} = pt_137:write(13705, [Act, DrumRole#drum_role{win = W +1, action = Act}]),
            {ok, Bin2} = pt_137:write(13703,[?TYPE_SUCCESS, ResultTime]),
            BinData = << Bin/binary, Bin1/binary, Bin2/binary >>,
            lib_role_drum:send_to_role(Node, RoleID, BinData),
            lib_role_drum:update_role_drum(Node, RoleID, Zid, Act),
            [{Award, _}] = data_drumwar:get_war(Zid, Act),
            lib_role_drum:war_award(Node, Act, 1, RoleID, Award),
            log_drum_war(?LOG_EMPTY, DrumRole),
            [DrumRole#drum_role{action = Act + 1, win = W + 1, calc_type = 1}, Wins];
        true when Group=<0 andalso One>0 -> %%截止 冠军已出,正常流程不走这里，只是兼容
            ?ERR("summon_rank_enter,champion error~p~n",[{RoleID, DAct, RUid}]),
            {ok, Bin} = pt_137:write(13708, [1, 5, Act]),
            {ok, Bin1} = pt_137:write(13705, [Act, DrumRole#drum_role{win = 12, action = Act}]),
            {ok, Bin2} = pt_137:write(13712, [RoleID, Zid, Name]),
            BinData = << Bin/binary, Bin1/binary, Bin2/binary >>,
            lib_role_drum:send_to_role(Node, RoleID, BinData),
            lib_role_drum:update_role_drum(Node, RoleID, Zid, 12),
            TypeId = lib_role_drum:get_zone(Zid),
            OpenLv = data_drumwar:get_kv(?DRUMLV),
            clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv, {OpenLv, 9999}},137, TypeId, [Name]], 600),
            spawn(fun()-> show_champion(Bin2, Zid, Signs++NSigns) end),
            calc_empty_champion_reward(Node, RoleID, Zid, Act),
            add_zone_win(Zid, RoleID, Name),
            log_drum_war(?LOG_EMPTY, DrumRole),
            [DrumRole#drum_role{action = 13, one = 0, win = 12, calc_type = 1},[Uid |Wins]];
        _->%%未参与本场次玩家
            [DrumRole,Wins]
    end,
    summon_rank_enter(Act, Signs, [NDrumRole|NSigns], ActionSt, ResultTime, NWins).

%%场内超时结算 先组 分组
account_war(_, Signs, [], _, Wins)->
    {Signs, Wins};
account_war(Act, Signs, [Scene| Scenes], Choice, Wins)->
    PlayerList = [D || D<-Signs,D#drum_role.scene == Scene, D#drum_role.calc_type < 1, D#drum_role.action == Act],
    ResGroups = calc_double(PlayerList, []),
    {NSigns, NWins} = account_group_war(Act, ResGroups, Signs, Choice, Wins),
    account_war(Act, NSigns, Scenes, Choice, NWins).

calc_double([], ResGroups)->
    ResGroups;
calc_double([A | OPlayerList], ResGroups)->
    #drum_role{group = Group} = A,
    case lists:keytake(Group, #drum_role.group, OPlayerList) of
        {value, B, PlayerList}->
            calc_double(PlayerList, [{A, B}| ResGroups]);
        _->
            calc_double(OPlayerList, [{A}| ResGroups])
    end.

account_group_war(_, [], Signs, _, Wins)->
    {Signs, Wins};
%%一人,打假人超时
account_group_war(Act, [{Win} | ResGroups], Signs, Choice, Wins)->
    #drum_role{
        figure = #figure{name = Name},
        node = Node,
        rid = RoleID
    } = Win,
    IsW = check_win(Act, RoleID, Signs),
    NSigns = case IsW of
        true->
            change_score(Act, RoleID, 1, 1, 0, Signs, Choice, Name);
        _->
            change_score(Act, RoleID, 0, 0, 1, Signs, Choice, Name)
    end,
    %%踢人回准备区
    clusters_center:apply_cast(Node, ?MODULE, enter_ready_local, [RoleID]),
    log_drum_war(?LOG_TIMEOUT, Win),
    account_group_war(Act, ResGroups, NSigns, Choice, [RoleID |Wins]);
account_group_war(Act, [{A, B}| ResGroups], Signs, Choice, Wins)->
        #drum_role{
            figure = #figure{name = AName},
            node = ANode,
            power = ValueA,
            live = LiveA,
            rid = AUid
        } = A,
        #drum_role{
            node = BNode,
            figure = #figure{name = BName},
            power = ValueB,
            live = LiveB,
            rid = BUid
        } = B,
        % LiveA = get_alive(AUid, Signs),
        % LiveB = get_alive(BUid, Signs),
        %%踢人回准备区
        clusters_center:apply_cast(ANode, ?MODULE, enter_ready_local, [AUid]),
        clusters_center:apply_cast(BNode, ?MODULE, enter_ready_local, [BUid]),
        {WUid, NSigns} = if
            (LiveA > LiveB) orelse (LiveA == LiveB andalso ValueA >= ValueB) -> %%A胜 B负
                %%同步 胜
                log_drum_war(?LOG_TIMEOUT, AUid, BUid, Signs),
                NSigns0 = change_score(Act, AUid, 1, 1, 0, Signs, Choice, BName),
                {AUid, change_score(Act, BUid, 0, 0, 1, NSigns0, Choice, AName)};
            true -> %%A负B胜
                log_drum_war(?LOG_TIMEOUT, BUid, AUid, Signs),
                NSigns0 = change_score(Act, BUid, 1, 1, 0, Signs, Choice, AName),
                {BUid, change_score(Act, AUid, 0, 0, 1, NSigns0, Choice, BName)}
        end,
        account_group_war(Act, ResGroups, NSigns, Choice, [WUid| Wins]).

%%战斗结算拿对手玩家看看是不是晋级来判断剩余玩家是不是晋级
check_win(Act, Uid, Signs)->
     case lists:keyfind(Uid, #drum_role.rid, Signs) of
        #drum_role{ruid = Ruid}->
            case lists:keyfind(Ruid, #drum_role.rid, Signs) of
                #drum_role{action = CurAct} when CurAct > Act->
                    false; %%对手已晋级
                _->
                    true
            end;
        _->
            true
    end.

enter_ready_local(RoleID)->
    lib_player:apply_cast(RoleID,?APPLY_CAST_STATUS, ?MODULE,enter_ready_role,[]).
enter_ready_role(Status)->
    #player_status{id=RoleId,skill=Skill}=Status,
    Scene = urand:list_rand(mod_drumwar_mgr:get_kv(?READY_SCENE)),
    {RandX,RandY,Circle} = urand:list_rand(mod_drumwar_mgr:get_kv(?READY_LOCATION)),
    {X,Y}=umath:rand_point_in_circle(RandX,RandY,Circle,1),
    case lib_role_drum:is_in_drumready(Status) of
        true->
            Status;
        _->
            mod_drumwar_mgr:cast_center([{mod, lib_role_drum, change_scene, [RoleId,Scene]}]),
            #status_skill{tmp_skill_list=TmpSkill} = Skill,
            NewTmpSkill = lib_role_drum:remove_tmp_skill(mod_drumwar_mgr:get_kv(?DRUM_SKILLS),TmpSkill),
            NStatus = Status#player_status{skill=Skill#status_skill{tmp_skill_list=NewTmpSkill}},
            lib_scene:change_scene(NStatus, Scene, 0, 0, X, Y, [{change_scene_hp_lim,1},{group,0}])
    end.

change_score(CurAct, Uid, IsA, W, L, Signs, Choice, _LName)->
    case lists:keyfind(Uid, #drum_role.rid, Signs) of
        #drum_role{} = DRole->
            #drum_role{
                node = Node, figure = #figure{name = Name}, live = Live, rid = RoleID,
                action = Act, zid = Zone, win = Win, lose = Lose, ruid = LUid, calc_type = CalcType
            } = DRole,
            case Act > CurAct of
                true->%%说明结算过了 比如提前战斗完毕 滞留场内
                    Signs;
                _ when Live =< 0-> %%说明战败 不予结算
                    Signs;
                _ when CalcType > 0 -> %%结算过 不结算
                    Signs;
                _->
                    case IsA >= 1 of
                        true->
                            [{Award, _}] = data_drumwar:get_war(Zone, Act),
                            lib_role_drum:war_award(Node, Act, 1, RoleID, Award),
                            NDRole = DRole#drum_role{action = Act + IsA, win = Win + W, lose = Lose + L, calc_type = 1},
                            Res = 3; %%超时得胜
                        _->
                            [{_, Award}] = data_drumwar:get_war(Zone, Act),
                            lib_role_drum:war_award(Node, Act, 0, RoleID, Award),
                            NDRole = DRole#drum_role{action = Act + IsA, win = Win + W, lose = 1, live = 0, calc_type = 1},
                            Res = 6 %%负
                    end,
                    {ok, Bin1} = pt_137:write(13705, [Act, NDRole#drum_role{action = Act}]),
                    {ok, Bin} = pt_137:write(13708, [1, Res, Act]),
                    BinData = << Bin/binary, Bin1/binary >>,
                    lib_role_drum:send_to_role(Node, RoleID, BinData),
                    lib_role_drum:update_role_drum(Node, RoleID, Zone, Act),
                    CurAct >= 12 andalso IsA > 0 andalso begin
                        TypeId = lib_role_drum:get_zone(Zone),
                        OpenLv = data_drumwar:get_kv(?DRUMLV),
                        clusters_center:apply_to_all_node(lib_chat, send_TV, [{all_lv, {OpenLv, 9999}}, ?MOD_DRUMWAR, TypeId, [Name]], 600),
                        {ok, Bin0} = pt_137:write(13712, [RoleID, Zone, Name]),
                        add_zone_win(Zone, RoleID, Name),
                        spawn(fun()-> show_champion(Bin0, Zone, Signs) end)
                    end,
                    %%第九场之后的超时结算有效
                    CurAct >= 9 andalso IsA > 0 andalso begin
                        spawn(fun()-> account_guess_result(Zone, CurAct, Uid, Name, LUid, Choice) end)
                    end,
                    lists:keyreplace(Uid, #drum_role.rid, Signs, NDRole)
            end;
        _-> %%找不到这个玩家
            Signs
    end.

%%获得命数
get_alive(Uid,Signs)->
    case lists:keyfind(Uid,#drum_role.rid,Signs) of
        #drum_role{live = L}->
            L;
        _->
            0
    end.

%%清理擂台的假人
clear_all_mons([])->
    ignore;
clear_all_mons([Scene|T])->
    lib_scene:clear_scene(Scene,0),
    clear_all_mons(T).

%%清理所有玩家 准备区 和 擂台区
clear_all_role()->
    % ?PRINT("sign~p~n",[Signs]),
    clear_all_role(mod_drumwar_mgr:get_kv(?READY_SCENE)++mod_drumwar_mgr:get_kv(?WAR_SCENE)).
clear_all_role([])->
    ignore;
clear_all_role([Scene|Scenes])->
    spawn(fun()->
        case catch mod_scene_agent:apply_call(Scene,0,lib_scene_agent,get_scene_user,[]) of
            PlayerList when is_list(PlayerList)->
                clear_all_mons([Scene]),
                role_back(PlayerList);
            _R->
                ignore
        end
    end),
    clear_all_role(Scenes).

role_back([])->
    ignore;
role_back([Role|PlayerList])->
    #ets_scene_user{
        node = Node,
        id = RoleID
    }=Role,
    clusters_center:apply_cast(Node,?MODULE,role_back_local,[RoleID]),
    role_back(PlayerList).

role_back_local(RoleID)->
    lib_player:apply_cast(RoleID,?APPLY_CAST_STATUS,?MODULE,role_back_role,[]).

%%回到旧场景
role_back_role(Status)->
    case lib_role_drum:is_drum(Status#player_status.scene) of
        true->
            {SceneId, ScenePoolId, CopyId, X, Y} = lib_role_drum:get_leave_scene(Status),
            KeyValList = [{group,0}, {pk,{?PK_PEACE,false}}, {change_scene_hp_lim, 1}, {action_free,?ERRCODE(err137_can_not_change_scene_in_drumwar)}],
            lib_scene:change_scene(Status, SceneId, ScenePoolId, CopyId, X, Y, KeyValList);
        _->
            Status
    end.

%%是否结算面板
is_over(L) when L>0->0;
is_over(_)->1.

%%最终排序结算
final_account(Signs,0)->
    Signs;
final_account(Signs,Zone)->
    [SignsZ,SignsL] = lists:foldl(fun(S,Args)->
        [A,B]=Args,
        case S of
            #drum_role{zid=Zone}->
                [[S|A],B];
            _->
                [A,[S|B]]
        end
    end,[[],[]],Signs),
    NSignsZ = final_zone_account(SignsZ),
    final_account(NSignsZ++SignsL,Zone-1).

%%子战区内结算
final_zone_account(Signs)->
    %%幸运玩家奖励
    Ratio = length(Signs) / (?WAR_MAX * 2) * 100,
    final_zone_lucky(Signs, Ratio, mod_drumwar_mgr:get_kv(?LUCKY_NUM)),
    %%排名结算
    [SignsZ,SignsL] = lists:foldl(fun(S,Args)->
        [A,B]=Args,
        case S#drum_role.action >=9 of
            true->
                [[S|A],B];
            _->
                [A,[S|B]]
        end
    end,[[],[]],Signs),
    NSignsZ = final_zone_account(SignsZ,1,[13,12,11,10,9]),
    NSignsZ++SignsL.

final_zone_account(Signs,_,[])->
    Signs;
final_zone_account(Signs,Rank,[Act|T])->
    [SignsZ,SignsL] = lists:foldl(fun(S,Args)->
        [A,B]=Args,
        case S#drum_role.action == Act  of
            true->
                [[S|A],B];
            _->
                [A,[S|B]]
        end
    end,[[],[]],Signs),
    SignsZ0 = compare_data(SignsZ),
    [NRank,NSignsZ] = compare_rank(SignsZ0,Rank,[]),
    final_zone_account(NSignsZ++SignsL,NRank,T).

%%排名赋值
compare_rank([],Rank,NSigns)->
    [Rank,NSigns];
compare_rank([DRole|OSigns],Rank,NSigns)->
    #drum_role{
        server_id = Node,
        zid  = Zone,
        rid  = RoleID
    }=DRole,
    Award = data_drumwar:get_rank(Zone,Rank),
    lib_role_drum:mail_award(Node, RoleID, Zone, Rank, Award),
    compare_rank(OSigns,Rank+1,[DRole#drum_role{rank=Rank}|NSigns]).

%%幸运玩家奖励
final_zone_lucky([], _Ratio, _Num) -> ok;
final_zone_lucky(_Signs, _Ratio, 0) -> ok;
final_zone_lucky(Signs, Ratio, Num) ->
    Role = urand:list_rand(Signs),
    #drum_role{
        server_id = Node,
        zid  = Zone,
        rid  = RoleID
    }=Role,
    LeftSigns = lists:keydelete(RoleID, #drum_role.rid, Signs),
    case urand:rand(0, 100) of
        RandRatio when RandRatio =< Ratio ->
            Award = data_drumwar:get_zone_lucky_reward(Zone),
            Title = utext:get(1370016),
            Content = utext:get(1370017),
            ApplyArgs = [[RoleID], ?MOD_DRUMWAR, Title, Content, Award],
            lib_role_drum:apply_to_local_role(Node, lib_mail_api, send_sys_mail, ApplyArgs);
        _ -> ok
    end,
    final_zone_lucky(LeftSigns, Ratio, Num-1).

lucky_reward(Status, Award) ->
    Produce = #produce{reward = Award, type= drumwar, show_tips=3},
    NStatus = lib_goods_api:send_reward(Status, Produce),
    NStatus.

%%谢绝多余的人
ready_check(Signs)->
    Signs0 = compare_data(Signs),
    case length(Signs0) > ?WAR_MAX of
        true->
            {SignsL, SignsR} = lists:split(?WAR_MAX,Signs0),
            spawn(fun()-> refuse_mail(SignsR,0) end),
            ReadyOut = ready_out(SignsR,[]),
            {SignsL,ReadyOut};
        _->
            {Signs0,[]}
    end.

%%谢绝人id
ready_out([], Ids)->Ids;
ready_out([#drum_role{rid = RoleId}|T], Ids)->
    ready_out(T, [RoleId |Ids]).

%%拒绝邮件
refuse_mail([], _N)->
    ignore;
refuse_mail([Sign |Signs], N)->
    #drum_role{
        node = Node,
        rid  = RoleID,
        server_id = Sid,
        power = Power
    }=Sign,
    case N >= 100 of
        true->
            timer:sleep(100),
            NewN = 0;
        false->
            NewN = N+1
    end,
    lib_role_drum:log_drum_refuce(Node, RoleID, Sid, Power),
    clusters_center:apply_cast(Node, ?MODULE, refuse_mail_local, [RoleID]),
    refuse_mail(Signs, NewN).

refuse_mail_local(RoleID)->
    lib_role_drum:log_drum_refuce_mail(RoleID),
    Title = utext:get(1370001),
    Content = utext:get(1370002),
    BackList = [{?TYPE_GOODS, mod_drumwar_mgr:get_kv(?DRUMITEM), 1}, {?TYPE_BGOLD, 0, 20}],
    lib_mail_api:send_sys_mail([RoleID], ?MOD_DRUMWAR, Title, Content, BackList).

%%计算当前期ID
get_id()->
    {{Y,M,D}, _} = calendar:local_time(),
    Y*10000+M*100+D.

%%往届战报集合
load_history()->
    WarRanks = case db:get_all(?SQL_DRUMRANK_GET) of
        [] ->
            [];
        Ranks when is_list(Ranks)  ->
            make_rank(Ranks,[]);
        _ ->
            []
    end,
    WarRanks.

make_rank([],WarRanks)->
    WarRanks;
make_rank([[Drumid,Zone,Rid,Name,Gname,ServerId,_PForm,SNum,Rank,Vip,Power,Career]|Ranks],WarRanks)->
    RankRole = #rank_role{
        drum = Drumid,
        zone = Zone,
        rid  = Rid,
        name = Name,
        gname = Gname,
        server_id = ServerId,
        servernum = SNum,
        rank = Rank,
        vip = Vip,
        power = Power,
        career = Career
    },
    NWarRanks = case lists:keyfind(Drumid,1,WarRanks) of
        {_,DRanks}->
            NDranks = [RankRole|DRanks],
            lists:keyreplace(Drumid,1,WarRanks,{Drumid,NDranks});
        _->
            [{Drumid,[RankRole]}|WarRanks]
    end,
    make_rank(Ranks,NWarRanks).

%%加载报名数据
load_signs(DrumId)->
    NSigns = case db:get_all(?SQL_DRUMSIGN_GET) of
        [] ->
            [];
        Signs when is_list(Signs)  ->
            make_signs(Signs,DrumId,[]);
        _ ->
            []
    end,
    NSigns.

make_signs([],_,Signs)->
    Signs;
make_signs([[RoleId,ServerId,_PForm,ServerNum,DrumID,Name,PicV,Turn,Lv,Career,Pow]|Signs],Did,NSigns)->
    case DrumID == Did of
        true->
            DRole = #drum_role{
                rid = RoleId,
                server_id = ServerId,
                node = ServerId,
                server_num = ServerNum,
                figure  = #figure{name = Name,picture_ver = PicV, turn = Turn, lv = Lv, career = Career},
                power = Pow
            },
            make_signs(Signs,Did,[DRole|NSigns]);
        _->
            make_signs(Signs,Did,NSigns)
    end.

%%加载上届对战表
load_choose()->
    case db:get_all(?SQL_DRUMRANK_RESULT_GET) of
        [] ->
            [];
        Choose when is_list(Choose)  ->
            NChoose = make_choose(Choose, []),
            calc_choose(NChoose, 4, []);
        _ ->
            []
    end.

make_choose([],Choose)->
    Choose;
make_choose([[Zone,Act,Group,ServerId,PForm,ServerNum,Rid,Name,PicV,Lv,Career,Pow]|Choose],NChoose)->
    DRole = #drum_role{
        rid = Rid,
        zid = Zone,
        server_id = ServerId,
        platform = PForm,
        server_num = ServerNum,
        action = Act,
        group = Group,
        figure = #figure{name=Name, picture_ver=PicV, lv=Lv, career=Career},
        power = Pow
    },
    make_choose(Choose,[DRole|NChoose]).

%%进行分区分场分组
calc_choose(_,0,Choose)->
    Choose;
calc_choose(Choose,Zone,NChoose)->
    ZChoose = [D||D<-Choose,D#drum_role.zid==Zone],
    NZChoose = calc_act_choose(ZChoose,[9,10,11,12,13],[]),
    calc_choose(Choose,Zone-1,[{Zone,NZChoose}|NChoose]).

%%分轮次
calc_act_choose(_,[],AChoose)->
    AChoose;
calc_act_choose(ZChoose,[Act|Acts],NAChoose)->
    AChoose = [D||D<-ZChoose,D#drum_role.action==Act],
    calc_act_choose(ZChoose,Acts,[{Act,cut_group(AChoose)}|NAChoose]).

%%分组
cut_group([])->
    [];
cut_group(Choose)->
    GChoose = lists:foldl(fun(D,Args)->
        #drum_role{group=G}=D,
        case lists:keyfind(G,1,Args) of
            {_,Groups}->
                NGroups = case Groups of
                    {B}->
                        {B,D};
                    _->%%满员
                        Groups
                end,

                lists:keyreplace(G,1,Args,{G,NGroups});
            _->
                [{G,{D}}|Args]
        end
    end,[],Choose),
    [SubGroup||{_,SubGroup}<-GChoose].

save_signs([])->
    ignore;
save_signs(Signs)->
    Did = get_id(),
    DataStrList = [format_bin_string(Did,Sign) || Sign <- Signs],
    DataStrAll  = string:join(DataStrList, ", "),
    SqlReplace  = io_lib:format(?SQL_DRUMWAR_SIGN_BATCH, [DataStrAll]),
    db:execute(SqlReplace).

format_bin_string(Did,Sign)->
    #drum_role{
        rid   = Uid,
        figure = #figure{lv= Lv},
        power = Pow
    } = Sign,
    io_lib:format(<<"('~s',~p,~w,~w)">>, [Uid,Did,Lv,Pow]).

%%只保存十期 旧的要把最早的一期删掉 写入最新一期
delete_overdue(_DrumID, [], History) -> History;
delete_overdue(DrumID,SignsR,History)->
    case length(History) >= 8 of
        true->
            History0 = lists:sort(fun(A,B)->{Ai,_}=A,{Bi,_}=B,Ai>=Bi end,History),
            {HistoryL,HistoryR} = lists:split(7,History0),
            delete_rank(HistoryR),
            insert_rank(SignsR),
            lists:keystore(DrumID,1,HistoryL,{DrumID,SignsR});
        _->
            insert_rank(SignsR),
            lists:keystore(DrumID,1,History,{DrumID,SignsR})
    end.

delete_rank([])->
    ignore;
delete_rank([{DrumID,_}|HistoryR])->
    db:execute(io_lib:format(?SQL_DRUMRANK_DEL,[DrumID])),
    delete_rank(HistoryR).

insert_rank([])->
    ignore;
insert_rank(SignsR)->
    DataStrList = [format_rank_bin_string(Sign) || Sign <- SignsR],
    DataStrAll  = string:join(DataStrList, ", "),
    SqlReplace  = io_lib:format(?SQL_DRUMWAR_RANK_BATCH, [DataStrAll]),
    db:execute(SqlReplace).

format_rank_bin_string(Sign)->
    #rank_role{
        drum = DrumID,
        zone = Zone,
        rid = RoleID,
        name = Name,
        gname = Gname,
        server_id = Sid,
        platform = PForm,
        servernum = Snum,
        rank = Rank,
        vip  = Vip,
        power = Pow,
        career = Career
    } = Sign,
    io_lib:format(<<"(~p,~p,~p,'~s','~s',~p,'~s',~p,~p,~p,~p,~p)">>, [DrumID,Zone,RoleID,Name,Gname,Sid,PForm,Snum,Rank,Vip,Pow,Career]).

%%匹配AI对手
match_ai([], Group, Signs)->
    {Group, Signs};
match_ai([Sign|OSigns], Group, NSigns)->
    NSign = Sign#drum_role{group = Group, ai = 1, pos = 1, ruid = 0, calc_type = 0},
    match_ai(OSigns, Group+1, [NSign|NSigns]).

show_champion(_Bin, _Zid, [])->
    ignore;
show_champion(Bin, Zid, [Sign|Signs])->
    case Sign of
        #drum_role{node = Node, rid = RoleID, zid = Zid}->
            lib_role_drum:send_to_role(Node, RoleID, Bin);
        _->
            ignore
    end,
    show_champion(Bin,Zid,Signs).

%%海选赛理想值
ideal_value(1)->2048;
ideal_value(2)->1024;
ideal_value(3)->512;
ideal_value(4)->256;
ideal_value(5)->128;
ideal_value(6)->64;
ideal_value(7)->32;
ideal_value(8)->16.

add_guess(Zone,Act,Value,Guess)->
    NGuess = case lists:keyfind(Zone,1,Guess) of
        {_,ActGuess}->
            case lists:keyfind(Act,1,ActGuess) of
                {_,Groups}->
                    NGroups = [Value|lists:delete(Value, Groups)],
                    NActGuess = lists:keystore(Act,1,ActGuess,{Act,NGroups}),
                    lists:keystore(Zone,1,Guess,{Zone,NActGuess});
                _->
                    NGroups = [Value],
                    NActGuess = lists:keystore(Act,1,ActGuess,{Act,NGroups}),
                    lists:keystore(Zone,1,Guess,{Zone,NActGuess})
            end;
        _->
            NGroups = [Value],
            NActGuess = [{Act,NGroups}],
            lists:keystore(Zone,1,Guess,{Zone,NActGuess})
    end,
    NGuess.

%%竞猜结算
account_guess_result(_Zone, Act, Uid, _WName, Lid, Choice)->
    case lists:keyfind(Uid, 1, Choice) of
        {_, GuessRoles}->
            % [Title,Content] = data_drumwar_m:get_guess_mail(Act,WName,LName),
            Title = utext:get(1370005),
            Content = utext:get(1370007),
            account_guess_roles(Title, Content, GuessRoles, Act);
        _->
            ignore
    end,
    case lists:keyfind(Lid, 1, Choice) of
        {Lid, LGuessRoles}->
            Title1 = utext:get(1370005),
            Content1 = utext:get(1370006),
            account_guess_fail(Title1, Content1, LGuessRoles);
        _->ignore
    end.

%%竞猜失败
account_guess_fail(_, _, [])-> ignore;
account_guess_fail(Title, Content, [{_Uid, Node, RoleID, _Type}| GuessRoles]) ->
    clusters_center:apply_cast(Node, lib_mail_api, send_sys_mail, [ [RoleID], ?MOD_DRUMWAR, Title, Content, [] ]),
    account_guess_fail(Title, Content, GuessRoles).

account_guess_roles(_,_,[],_)->
    ignore;
account_guess_roles(Title, Content, [{_Uid, Node, RoleID, Type}| GuessRoles], Act)->
    [_, Award] = get_award(Act, Type),
    mail_guess_award(Award, Title, Content, Node, RoleID),
    account_guess_roles(Title, Content, GuessRoles, Act).

get_award(Act, Type)->
    case data_drumwar:get_choose(Act, Type) of
        [{Cost, Reward}] -> [Cost, Reward];
        _ -> [[], []]
    end.

%%邮件结算
mail_guess_award([], _, _, _, _)->
    ignore;
mail_guess_award(Award, Title, Content, Node, RoleID)->
    clusters_center:apply_cast(Node, lib_mail_api, send_sys_mail, [ [RoleID], ?MOD_DRUMWAR, Title, Content, Award]).

%%回写对战结果
save_choose([])->
    ignore;
save_choose([{_Zid,AChoose}|Choose])->
    save_act_choose(AChoose),
    save_choose(Choose).

save_act_choose([])->
    ignore;
save_act_choose([{_Act,GChoose}|AChoose])->
    save_group_choose(GChoose),
    save_act_choose(AChoose).

save_group_choose([])->
    ignore;
save_group_choose([Value|GChoose])->
    case Value of
        {DRole}->
            db_save_result(DRole);
        {DRoleA,DRoleB}->
            db_save_result(DRoleA),
            db_save_result(DRoleB);
        _->
            ignore
    end,
    save_group_choose(GChoose).

db_save_result(DRole)->
    #drum_role{
        rid = Uid,
        server_id = ServerId,
        platform = Pfrom,
        server_num = ServerNum,
        zid = Zone,
        figure = #figure{name=Name,picture=_Pic,picture_ver=PicV,lv=Lv,career=Career},
        action = Act,
        group = Group,
        power = Pow
    } = DRole,
    Sql  = io_lib:format(?SQL_DRUMWAR_RESULT_INTERT, [Zone,Act,Group,ServerId,Pfrom,ServerNum,Uid,Name,PicV,Lv,Career,Pow]),
    db:execute(Sql).


%%决胜局 追加冠军
add_results([],_Signs,Choose)->
    Choose;
add_results([Uid|Wins],Signs,Choose)->
    NChoose = case lists:keyfind(Uid,#drum_role.rid,Signs) of
        DRole when is_record(DRole,drum_role) ->
            #drum_role{zid=Zone}=DRole,
            NDRole = DRole#drum_role{action=13,group=1},
            case lists:keyfind(Zone,1,Choose) of
                {_,AChoose}->
                    NAChoose = lists:keystore(13,1,AChoose,{13,[{NDRole}]}),
                    lists:keyreplace(Zone,1,Choose,{Zone,NAChoose});
                _->
                    NAChoose = [{13,[{NDRole}]}],
                    lists:keystore(Zone,1,Choose,{Zone,NAChoose})
            end;
        _->
            Choose
    end,
    add_results(Wins,Signs,NChoose).

%%命数广播 败给机器人
brocast_live(Type,LUid,Signs) when is_atom(Type) ->
    case lists:keyfind(LUid,#drum_role.rid,Signs) of
        #drum_role{live=Fl,node=LNode,rid=LRid}->
            ignore;
        _->Fl=0,LNode=none,LRid=0
    end,
    DummyLive = ?IF(Type == none, 1, 0),
    {ok,FBin} = pt_137:write(13710,[Fl, 0, DummyLive]),
    LRid /= 0 andalso lib_role_drum:send_to_role(LNode,LRid,FBin);
brocast_live(WUid,LUid,Signs)->
    case lists:keyfind(WUid,#drum_role.rid,Signs) of
        #drum_role{live=Wl,node=WNode,rid=WRid}->
            ignore;
        _->Wl=0,WNode=none,WRid=0
    end,
    case lists:keyfind(LUid,#drum_role.rid,Signs) of
        #drum_role{live=Fl,node=LNode,rid=LRid}->
            ignore;
        _->Fl=0,LNode=none,LRid=0
    end,
    {ok,WBin} = pt_137:write(13710,[Wl,LUid,Fl]),
    {ok,FBin} = pt_137:write(13710,[Fl,WUid,Wl]),
    WRid /= 0 andalso lib_role_drum:send_to_role(WNode,WRid,WBin),
    LRid /= 0 andalso lib_role_drum:send_to_role(LNode,LRid,FBin).

%'胜负类型1胜2负3轮空4超时5离线'
log_drum_war(Type,DrumRole)->
    DrumID = get_id(),
    log_drum_war_local(Type,DrumID,DrumRole).
log_drum_war(WUid,LUid,Signs)->
    log_drum_war(?LOG_WIN, WUid, LUid, Signs).
log_drum_war(Type,WUid,LUid,Signs)->
    DrumID = get_id(),
    {WDrum,_WNode}  = case lists:keyfind(WUid,#drum_role.rid,Signs) of
        false->{#drum_role{rid=0,figure=#figure{}},none};
        WR->{WR,WR#drum_role.node}
    end,
    {LDrum,_LNode}  = case lists:keyfind(LUid,#drum_role.rid,Signs) of
        false->{#drum_role{rid=0,figure=#figure{}},none};
        LR->{LR,LR#drum_role.node}
    end,
    log_drum_war_local(Type,DrumID,WDrum,LDrum).

log_drum_war_local(Type,DrumID,DrumRole)->
    #drum_role{
        rid = RoleID,
        zid  = Zone,
        action = War,
        figure = #figure{name=Name},
        server_id = ServerId,
        platform = Plat,
        server_num = Snum,
        power = Power,
        live = Live
    } = DrumRole,
    lib_log_api:log_drum_war(DrumID,Zone,War,RoleID,Name,ServerId,Plat,Snum,Live,Power,0,"",0,"",0,0,0,Type).
log_drum_war_local(Type,DrumID,WDrum,LDrum)->
    #drum_role{
        rid = WRoleID,
        zid  = WZone,
        action = WWar,
        figure = #figure{name=WName},
        server_id = WSId,
        platform = WPlat,
        server_num = WSnum,
        power = WPower,
        live = WLive
    }=WDrum,
    #drum_role{
        rid = LRoleID,
        figure = #figure{name=LName},
        server_id = LSId,
        platform = LPlat,
        server_num = LSnum,
        power = LPower,
        live = LLive
    }=LDrum,
    lib_log_api:log_drum_war(DrumID,WZone,WWar,WRoleID,WName,WSId,WPlat,WSnum,WLive,WPower,LRoleID,LName,LSId,LPlat,LSnum,LLive,LPower,Type).


test_sign(N,Act)->
    Signs = make_s(N,Act,[]),
    Total = compare_data(Signs),
    All = length(Total),
    Num = All-2*(All-ideal_value(Act)),  %%这部分人打AI
    {SignAi,SignsPk} = lists:split(Num,Total),
    ?ERR("Msg:~p~n,MM:~p~n", [SignAi, SignsPk]).

make_s(0,_,Signs)->
    Signs;
make_s(N,Act,Signs)->
    D=#drum_role{rid=N,action=Act,power=urand:rand(1000,9000),platform="4399",server_num=2,figure=#figure{lv=urand:rand(76,85)},online=1},
    make_s(N-1,Act,[D|Signs]).

%%模拟匹配
test_match(N,Act)->
    db:execute("TRUNCATE TABLE `log_drum_match`"),
    Signs = make_s(N,Act,[]),
    {Signs0,_} = calc_zones(Signs),
    L1 = length([D||D<-Signs0,D#drum_role.zid==1]),
    L2 = length([D||D<-Signs0,D#drum_role.zid==2]),
    L3 = length([D||D<-Signs0,D#drum_role.zid==3]),
    L4 = length([D||D<-Signs0,D#drum_role.zid==4]),
    io:format("~p~n",[{L1,L2,L3,L4}]),
    Signs1 = compare_data(Signs0),
    NSigns = calc_group(Signs1,Act),
    ?ERR("Msg:~p~n,MM:~p~n", [Signs1, NSigns]).

%%判断战区参加人数
check_zone_num(Signs0,ZoneNum)->
    F = fun({ZoneId,Num},TSigns)->
        case Num<?WAR_LIMIT of
            true->
                cancel_zone(TSigns,ZoneId,[]);
            false-> TSigns
        end
    end,
    lists:foldl(F,Signs0,ZoneNum).

%%取消战区大战
cancel_zone([],_ZoneId,Signs)->Signs;
cancel_zone([#drum_role{node=Node,rid=RoleId,zid=Zid,online=Online}=Drum|T],ZoneId,Signs)->
    case Zid == ZoneId of
        true->
            cancel_mail(Drum),
            case Online == 1 of
                true-> role_back([#ets_scene_user{node=Node,id=RoleId}]);
                false->skip
            end,
            cancel_zone(T,ZoneId,Signs);
        false-> cancel_zone(T,ZoneId,[Drum|Signs])
    end.

%%取消邮件
cancel_mail(Sign)->
    #drum_role{
        node = Node,
        rid  = RoleID
    }=Sign,
    clusters_center:apply_cast(Node,?MODULE,cancel_mail_local,[RoleID]).

cancel_mail_local(RoleID)->
    Title = utext:get(1370003),
    Content = utext:get(1370004),
    BackList = [{0, mod_drumwar_mgr:get_kv(?DRUMITEM), 1}],
    lib_mail_api:send_sys_mail([RoleID], ?MOD_DRUMWAR, Title, Content, BackList).

get_kv(Id) ->
    data_drumwar:get_kv(Id).

start_act_handle() ->
    OpenDay = util:get_open_day(),
    NeedOpenDay = get_kv(?OPEN_DAY),
    ?IF(OpenDay >= NeedOpenDay, lib_activitycalen_api:success_start_activity(?MOD_DRUMWAR), ok).

end_act_handle(Args) ->
    ?IF(Args == 0, lib_activitycalen_api:success_end_activity(?MOD_DRUMWAR), ok),
    OnlineList = ets:tab2list(?ETS_ONLINE),
    spawn(fun()-> clear_role_info(OnlineList) end).

clear_role_info(OnlineList) when is_list(OnlineList)->
    db:execute("TRUNCATE TABLE `role_drum`"),
    [lib_player:apply_cast(PlayerId, ?APPLY_CAST_STATUS, ?MODULE, clear_role_info, [])||#ets_online{id = PlayerId}<-OnlineList];
clear_role_info(PS) ->
    RoleDrum = #role_drum{},
    PS#player_status{role_drum = RoleDrum}.

%%增加已得出冠军的战区
add_zone_win(Zone, RoleId, Name) ->
    Info = {Zone, RoleId, Name},
    case get({?MODULE, zone_win}) of
        List when is_list(List) ->
            put({?MODULE, zone_win}, [Info |lists:keydelete(Zone, 1, List)]);
        _ -> put({?MODULE, zone_win}, [Info])
    end.

%%获取已得出冠军的战区
get_zone_win() ->
    case get({?MODULE, zone_win}) of
        List when is_list(List) -> List;
        _ -> []
    end.

close_handle(State) ->
    #drumwar_mgr{signs = Signs} = State,
    spawn(fun()-> finish_ac(Signs) end).

finish_ac([]) -> ok;
finish_ac([#drum_role{node = Node, rid = RoleId} | T]) ->
    clusters_center:apply_cast(Node, mod_hi_point, success_end,[RoleId, ?MOD_DRUMWAR, 0]),
    finish_ac(T).
