%%-----------------------------------------------------------------------------
%% module  :       mod_guild_boss_mgr
%% @author  :      zmh
%% Created :       20200226
%% description:    社团BOSS管理
%%-----------------------------------------------------------------------------
-module(mod_guild_boss_mgr).

-include("errcode.hrl").
-include("server.hrl").
-include("scene.hrl").
-include("attr.hrl").
-include("battle.hrl").
-include("rec_event.hrl").
-include("common.hrl").
-include("guild.hrl").
-include("def_module.hrl").
-include("def_event.hrl").
-include("def_goods.hrl").
-include("goods.hrl").
-include("drop.hrl").
-include("team.hrl").
-include("chat.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("predefine.hrl").
-include("guild_tribe.hrl").

-export ([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).
-export ([
    start_link/0,
    init_guild_boss/4,
    clear_guild_boss/2,
    sync_boss_hp/3,
    % clear_follow_mon/2,
    % call_follow_mon/3,
    gm_start/1,
    print/1,
    attack_mon/3,
    get_act_state/1,
    get_hp_state/1,
    apply_guild_role_rank/3,
    apply_guild_rank/3,
    apply_self_data/4,
    activitycalen_start/1,
    create_guild/1,
    check_open/0,
    get_mon_state/2,
    mon_die/3,
    market_cashback/2,
    guild_market_cashback/5,
    handle_event/2,
    role_enter/4,
    role_exit/2,
    role_revive/2,
    get_role_inspire/2,
    get_role_inspire_data/3,
    inspire_anyone/2,
    update_box_remain/2,
    create_drop_box/4,
    update_guild_role_list/1,   %% 更新玩家列表
    start_roll_drops/4,         %% 记录掉落数据
    drops_roll_info/2,          %% 掉落roll点信息
    roll_drops/4,               %% 掉落roll点
    drop_multi_roll_info/3,     %% 单个掉落roll点信息
    auto_roll/4,
    check_drop/1
    ,update_ta_data_on_role/2
]).

gm_start(Sec)->
    gen_server:cast(?MODULE,{gm_start,Sec}).

print(GuildID)->
    gen_server:cast(?MODULE, {print,GuildID}).


get_act_state(RoleID)->
    gen_server:cast(?MODULE,{get_act_state,RoleID}).

get_hp_state(RoleID)->
    gen_server:cast(?MODULE,{get_hp_state,RoleID}).

apply_guild_role_rank(RoleID,Act,GuildId)->
    gen_server:cast(?MODULE,{apply_guild_role_rank,RoleID,Act,GuildId}).

apply_guild_rank(RoleID,Act,GuildID)->
    gen_server:cast(?MODULE,{apply_guild_rank,RoleID,Act,GuildID}).

apply_self_data(Act,OpTy,RoleID,GuildID)->
    gen_server:cast(?MODULE,{apply_self_data,Act,OpTy,RoleID,GuildID}).

activitycalen_start(AcSub)->
    gen_server:cast(?MODULE,{activitycalen_start,AcSub}).

create_guild(GuildId)->
    gen_server:cast(?MODULE,{create_guild,GuildId}).

check_open()->
    gen_server:call(?MODULE,{check_open}).

get_mon_state(RoleID,GuildID)->
    gen_server:cast(?MODULE,{get_mon_state,RoleID,GuildID}).

get_role_inspire(RoleID,GuildID)->
    gen_server:cast(?MODULE,{get_role_inspire,RoleID,GuildID}).

get_role_inspire_data(OpTy,RoleID,GuildID)->
    gen_server:call(?MODULE,{get_role_inspire_data,OpTy,RoleID,GuildID}).

inspire_anyone(OpTy,RecRank)->
    gen_server:cast(?MODULE,{inspire_anyone,OpTy,RecRank}).

market_cashback(GuildID,Price)->
    gen_server:cast(?MODULE,{market_cashback,GuildID,Price}).

role_enter(RoleID,RLv,GuildId,GName)->
    gen_server:cast(?MODULE,{role_enter,RoleID,RLv,GuildId,GName}).

role_exit(RoleId, GuildId) ->
    gen_server:cast(?MODULE,{role_exit, RoleId, GuildId}).

%% 复活
role_revive(RoleId, GuildId) ->
    gen_server:cast(?MODULE, {role_revive, RoleId, GuildId}).

update_box_remain(GuildID,BoxN)->
    gen_server:cast(?MODULE,{update_box_remain,GuildID,BoxN}).

update_guild_role_list(GuildRoleList) ->
    gen_server:cast(?MODULE,{update_guild_role_list, GuildRoleList}).

start_roll_drops(GuildId, MonArgs, DropRule, DropList) ->
    gen_server:cast(?MODULE,{start_roll_drops, GuildId, MonArgs, DropRule, DropList}).

drops_roll_info(RoleId, GuildId) ->
    gen_server:cast(?MODULE,{drops_roll_info, RoleId, GuildId}).

roll_drops(RoleId, GuildId, Option, DropId) ->
    gen_server:cast(?MODULE,{roll_drops, RoleId, GuildId, Option, DropId}).

drop_multi_roll_info(RoleId, GuildId, DropId) ->
    gen_server:cast(?MODULE, {drop_multi_roll_info, RoleId, GuildId, DropId}).

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

init([]) ->
    process_flag(trap_exit, true),
    Act = get_act_data(1),
    List0 = data_activitycalen:get_ac_list_by_module(?MOD_GUILD_BOSS),
    List  = [Ac||{_,Ac}<-List0],
    ActMap = load_act_map(List,maps:new()),
    GRanksMap = load_guild_map(List,maps:new()),
    State = #guild_boss_mgr{
        act = Act,
        state = ?STATE_IDLE,
        role_ranks = ActMap,
        guild_ranks = GRanksMap
    },
   {ok, State}.

handle_call(Msg, From, State) ->
    case catch do_handle_call(Msg, From, State) of
        {'EXIT', Error} ->
            ?ERR("handle_call error: ~p~nMsg=~p~n", [Error, Msg]),
            {reply, error, State};
        Return  ->
            Return
    end.

handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        {'EXIT', Error} ->
            ?ERR("handle_cast error: ~p~nMsg=~p~n", [Error, Msg]),
            {noreply, State};
        Return  ->
            Return
    end.

handle_info(Info, State) ->
    case catch do_handle_info(Info, State) of
        {'EXIT', Error} ->
            ?ERR("handle_info error: ~p~nInfo=~p~n", [Error, Info]),
            {noreply, State};
        Return  ->
            Return
    end.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

terminate(_Reason, _State) ->
    ?ERR("~p is terminate:~p", [?MODULE, _Reason]),
    ok.

do_handle_call({check_open},_,State)->
    IsOpen = case State#guild_boss_mgr.state of
        ?STATE_OPEN->
            true;
        _->
            false
    end,
    {reply,IsOpen,State};

do_handle_call({get_role_inspire_data,OpTy,RoleID,GuildID},_,State)->
    #guild_boss_mgr{
        act = Act,
        guild_ranks = GRanksMap
    }=State,
    [FTimes,CTimes,_Inspire] = get_inspire_data(RoleID,GuildID,State),
    Times = case OpTy of
        0->
            FTimes;
        _->
            CTimes
    end,
    IsOpen = case State#guild_boss_mgr.state of
        ?STATE_OPEN->
            true;
        _->
            false
    end,

    GRanks = maps:get(Act,GRanksMap,[]),
    OldGuildRec =  lists:keyfind(GuildID,#rec_rank.gid,GRanks),
    case OldGuildRec of
        #rec_rank{inspire=OInspire}->
            skip;
        _->
            OInspire=0
    end,

    {reply,{ok,IsOpen,Times,FTimes+CTimes,OInspire},State};

do_handle_call(_Msg, _From, State) ->
    {reply, ok, State}.


do_handle_cast({get_act_state,RoleID},State)->
    #guild_boss_mgr{
        act = AcSub,
        mon = BossID,
        hp  = HP,
        hp_limit = MaxHp,
        state = S,
        stime = STime,
        etime = ETime
    }=State,
    {ok,Bin} = pt_406:write(40600,[AcSub,BossID,HP,MaxHp,S,STime,ETime]),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

do_handle_cast({get_hp_state,RoleID},State)->
    #guild_boss_mgr{
        hp  = HP,
        hp_limit = MaxHp
    }=State,
    {ok,Bin} = pt_406:write(40601,[HP,MaxHp]),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};


do_handle_cast({apply_guild_role_rank,RoleID,Act,GuildID},State)->
    #guild_boss_mgr{role_ranks=ActRoleMap}=State,
    RRanksMap  = get_role_rank_map(Act,ActRoleMap),
    RoleRanks  = maps:get(GuildID,RRanksMap,[]),
    case lists:keyfind(RoleID,#rec_rank.rid,RoleRanks) of
        #rec_rank{rank=MRank,hurt=MHurt}->
            skip;
        _->
            MRank = 0,MHurt = 0
    end,
    {ok,Bin0} = pt_406:write(40604,[Act,0,RoleID,MRank,MHurt]),
    Bin1 = pack_40602_data(Act,RoleRanks),
    Bin = <<Bin0/binary,Bin1/binary>>,
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

do_handle_cast({apply_guild_rank,RoleID,Act,GuildID},State)->
    #guild_boss_mgr{guild_ranks=GRanksMap}=State,
    GuildRanks = maps:get(Act,GRanksMap,[]),
    case lists:keyfind(GuildID,#rec_rank.gid,GuildRanks) of
        #rec_rank{rank=MRank,hurt=MHurt}->
            skip;
        _->
            MRank = 0,MHurt = 0
    end,
    {ok,Bin0} = pt_406:write(40604,[Act,1,GuildID,MRank,MHurt]),
    Bin1 = pack_40603_data(Act,GuildRanks),
    Bin = <<Bin0/binary,Bin1/binary>>,
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

do_handle_cast({apply_self_data,Act,0,RoleID,GuildID},State)->
    #guild_boss_mgr{role_ranks=ActRoleMap}=State,
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    RoleRanks = maps:get(GuildID,RRanksMap,[]),
    case lists:keyfind(RoleID,#rec_rank.rid,RoleRanks) of
        #rec_rank{rank=MRank,hurt=MHurt}->
            skip;
        _->
            MRank = 0,MHurt = 0
    end,
    {ok,Bin} = pt_406:write(40604,[Act,0,RoleID,MRank,MHurt]),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};
do_handle_cast({apply_self_data,Act,_,RoleID,GuildID},State)->
    #guild_boss_mgr{guild_ranks=GRanksMap}=State,
    GuildRanks = maps:get(Act,GRanksMap,[]),
    case lists:keyfind(GuildID,#rec_rank.gid,GuildRanks) of
        #rec_rank{rank=MRank,hurt=MHurt}->
            skip;
        _->
            MRank = 0,MHurt = 0
    end,
    {ok,Bin} = pt_406:write(40604,[Act,1,GuildID,MRank,MHurt]),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

%%
do_handle_cast({update_guild_role_list, GuildRoleList}, State) ->
    RoleMap = maps:from_list(GuildRoleList),
    {noreply, State#guild_boss_mgr{role_map = RoleMap}};

%% 记录掉落逻辑并开始roll点
do_handle_cast({start_roll_drops, GuildId, MonArgs, DropRule, DropList}, State) ->
    #guild_boss_mgr{drop_map = GuildDropMap, roll_map = GuildRollMap, role_map = RoleMap} = State,
    {_, DropList1} = lists:foldl(fun(Drop, {TNum, TList}) ->
                                {TNum +1, [{TNum +1, Drop}|TList]}
                            end, {0, []}, DropList),
    NewGuildDropMap = maps:put(GuildId, [MonArgs, DropRule, DropList1], GuildDropMap),
    DropGoodsList = [{OrderId, GoodsId, Num, 0}||{OrderId, #ets_drop_goods{goods_id = GoodsId, num = Num}}<-DropList1],
    NowTime = utime:unixtime(),
    {ok, Bin} = pt_406:write(40613, [NowTime, DropGoodsList]),
    RoleList = maps:get(GuildId, RoleMap, []),
    DropGoodsList =/= [] andalso lib_server_send:send_to_uid(RoleList, Bin),
    RollDropsMap = maps:get(roll_drops, GuildRollMap, #{}),
    NewRollDropsMap = maps:put(GuildId, #{}, RollDropsMap),
    RollRolesMap = maps:get(refuse_roll_roles, GuildRollMap, #{}),
    NewRollRolesMap = maps:put(GuildId, #{}, RollRolesMap),
    NewGuildRollMap = #{
        roll_drops => NewRollDropsMap,
        refuse_roll_roles => NewRollRolesMap,
        start_time => NowTime
        },
    NewState = State#guild_boss_mgr{drop_map = NewGuildDropMap, roll_map = NewGuildRollMap},
    {noreply, NewState};

%% 个人掉落roll点信息
% {drops_roll_info, RoleId, GuildId}
do_handle_cast({drops_roll_info, RoleId, GuildId}, State) ->
    #guild_boss_mgr{drop_map = GuildDropMap, roll_map = GuildRollMap} = State,
    RollDropsMap = maps:get(roll_drops, GuildRollMap, #{}),
    StartTime = maps:get(start_time, GuildRollMap, 0),
    GuildRollDrops = maps:get(GuildId, RollDropsMap, #{}),
    DropParams = maps:get(GuildId, GuildDropMap, []),
    case DropParams of
        [_, _, DropList] ->
            F = fun({OrderId, EtsDrop}, TList) ->
                case EtsDrop of
                    #ets_drop_goods{goods_id = GoodsId, num = Num} ->
                        RandList = maps:get(OrderId, GuildRollDrops, []),
                        case lists:keyfind(RoleId, 1, RandList) of
                            {_, Rand} -> ok;
                            _ -> Rand = 0
                        end,
                        [{OrderId, GoodsId, Num, Rand}|TList];
                    _ -> TList
                end end,
            PackInfo = lists:foldl(F, [], DropList);
        _ ->
            PackInfo = []
    end,
    lib_server_send:send_to_uid(RoleId, pt_406, 40613, [StartTime, PackInfo]),
    {noreply, State};

%% 单个掉落的所有roll点数据
do_handle_cast({drop_multi_roll_info, RoleId, GuildId, DropId}, State) ->
    #guild_boss_mgr{drop_map = _GuildDropMap, roll_map = GuildRollMap} = State,
    RollDropsMap = maps:get(roll_drops, GuildRollMap, #{}),
    GuildRollDrops = maps:get(GuildId, RollDropsMap, #{}),
    RandList = maps:get(DropId, GuildRollDrops, []),
    DropRollInfos = pack_40616_data(RandList),
    lib_server_send:send_to_uid(RoleId, pt_406, 40616, [DropId, DropRollInfos]),
    {noreply, State};

%% 选择奖励 RollMap = #{refuse_roll_roles => map(), roll_drops => map()}
%% refuse_roll_roles 拒绝roll点的掉落-玩家映射
do_handle_cast({roll_drops, RoleId, GuildId, Option, OrderId}, State) ->
    #guild_boss_mgr{drop_map = GuildDropMap, roll_map = GuildRollMap} = State,
    DropParams = maps:get(GuildId, GuildDropMap, []),
    {CheckDrop, GoodsId} = case DropParams of
                    [_, _, DropList] ->
                        case lists:keyfind(OrderId, 1, DropList) of
                            {_, #ets_drop_goods{goods_id = TGoodsId}} -> {true, TGoodsId};
                            _ -> {false, 0}
                        end;
                    _ -> {false, 0}
                end,
    %% 如果已经拒绝了，不能再操作
    RefuseRollRoleMap = maps:get(refuse_roll_roles, GuildRollMap, #{}),
    RefuseRollDrop = maps:get(GuildId, RefuseRollRoleMap, #{}),
    RollRoles = maps:get(OrderId, RefuseRollDrop, []),
    CheckRefuse = lists:member(RoleId, RollRoles),
    %% 如果已经选择了，不能再操作
    HasRollDropsMap = maps:get(roll_drops, GuildRollMap, #{}),
    GuildHasRollDrops = maps:get(GuildId, HasRollDropsMap, #{}),
    RollRandList = maps:get(OrderId, GuildHasRollDrops, []),
    HasRollRoleList = [TRole||{TRole, _}<-RollRandList],
    CheckRoll = lists:member(RoleId, HasRollRoleList),
    StarTime  = maps:get(start_time, GuildRollMap, 0),
    RollTime  = case data_guild_boss:get(roll_time) of
                    TTime when is_integer(TTime), TTime > 0 -> TTime;
                    _ -> 15
                end,
    IsTimePass= utime:unixtime() >= StarTime + RollTime,
    NewState =
    if
        not CheckDrop ->
            lib_server_send:send_to_uid(
                RoleId, pt_406, 40614, [?ERRCODE(err406_not_drop), Option, OrderId, 0, 0]
            ),
            State;
        CheckRefuse ->
            lib_server_send:send_to_uid(
                RoleId, pt_406, 40614, [?ERRCODE(err406_has_refuse), Option, OrderId, 0, 0]
            ),
            State;
        CheckRoll ->
            lib_server_send:send_to_uid(
                RoleId, pt_406, 40614, [?ERRCODE(err406_has_roll), Option, OrderId, 0, 0]
            ),
            State;
        IsTimePass ->
            lib_server_send:send_to_uid(
                RoleId, pt_406, 40614, [?ERRCODE(err406_time_pass), Option, OrderId, 0, 0]
            ),
            State;
        true ->
            case Option of
                1 ->
                    RollDropsMap = maps:get(roll_drops, GuildRollMap, #{}),
                    GuildRollDrops = maps:get(GuildId, RollDropsMap, #{}),
                    RandList = maps:get(OrderId, GuildRollDrops, []),
                    RandNumList = [TNum||{_, TNum}<-RandList],
                    Max = case RandNumList of
                              [_|_] -> lists:max(RandNumList);
                              _ -> 1
                          end,
                    Rand = urand:rand(1, 100),
                    %% 修正随机值。如果等于最大值，则-1；如果Max=1，则+1；必须保证-1后仍大于1
                    Rand1 = case Rand == Max of
                                true when Max == 1 -> 2;
                                true -> max(1, Max -1);
                                _ -> Rand
                            end,
                    NewRandList = [{RoleId, Rand1}|lists:keydelete(RoleId, 1, RandList)],
                    NewGuildRollDrops = maps:put(OrderId, NewRandList, GuildRollDrops),
                    NewRollDropsMap = maps:put(GuildId, NewGuildRollDrops, RollDropsMap),
                    NewGuildRollMap = maps:put(roll_drops, NewRollDropsMap, GuildRollMap),
                    NewMax = case Rand1 > Max of true -> Rand1; _ -> Max end,
                    Msg = utext:get(?MOD_GUILD_BOSS, 11, [GoodsId, Rand1, NewMax]),
                    Args = [?CHAT_CHANNEL_GUILD, 0, Msg, "", 0, ""],
                    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, lib_chat, server_chat, Args),
                    lib_server_send:send_to_uid(RoleId, pt_406, 40614, [?SUCCESS, Option, OrderId, Rand1, NewMax]),
                    %% 给社团成员推送新的roll点数据
                    DropRollInfos = pack_40616_data(NewRandList),
                    {ok, Bin} = pt_406:write(40616, [OrderId, DropRollInfos]),
                    lib_server_send:send_to_guild(GuildId, Bin),
                    State#guild_boss_mgr{roll_map = NewGuildRollMap};
                2 ->
                    NewRollRoles = [RoleId|lists:delete(RoleId, RollRoles)],
                    NewRefuseRollDrop = maps:put(OrderId, NewRollRoles, RefuseRollDrop),
                    NewRollRoleMap = maps:put(GuildId, NewRefuseRollDrop, RefuseRollRoleMap),
                    NewGuildRollMap = maps:put(refuse_roll_roles, NewRollRoleMap, GuildRollMap),
                    State#guild_boss_mgr{roll_map = NewGuildRollMap}
            end
    end,
    {noreply, NewState};

do_handle_cast({gm_start,0},State)->
    #guild_boss_mgr{ref=ORef,mon_ref=OMRef}=State,
    util:cancel_timer(ORef),
    util:cancel_timer(OMRef),
    Ref = erlang:send_after(5*1000,self(),enter_close),
    NState = State#guild_boss_mgr{ref=Ref, role_map = #{}, roll_map = #{}, drop_map = #{}},
    {noreply,NState};

do_handle_cast({gm_start,Sec},State)->
    #guild_boss_mgr{scene=Scene,ref=ORef,mon=BossID,mon_ref=OMRef}=State,
    util:cancel_timer(ORef),
    util:cancel_timer(OMRef),
    BossID>0 andalso  Scene>0 andalso mod_guild:apply_cast(?MODULE,clear_guild_boss,[Scene,BossID]),
    Act = Sec rem 2 + 1,
    Ref = erlang:send_after(Sec*1000,self(),{enter_start,Act}),
    NState = State#guild_boss_mgr{act= Act, ref=Ref,boss_datas=[],role_map = #{}, roll_map = #{}, drop_map = #{}},
    {noreply,NState};

do_handle_cast({activitycalen_start,AcSub},State)->
    NState = do_start(AcSub,State),
    offline_hosting_guild_boss:check_hosting(AcSub),
    {noreply,NState};

%%打印怪物
do_handle_cast({print,GuildID},State)->
    #guild_boss_mgr{mon=BossID}=State,
    SceneID = lib_guild_api:get_guild_scene(),
    case lib_mon:get_scene_mon_by_mids(SceneID, ?GUILD_REM_POOL(GuildID), GuildID,[BossID], #scene_object.id) of
        [MonID|_]->
            ?INFO("---alive---:~p~n",[{SceneID,BossID,MonID}]);
        _->
            ?INFO("---dead---:~p~n",[{SceneID,BossID}])
    end,
    {noreply,State};

do_handle_cast({attack_mon,Badges,_MonID,PreRecRank,AttTime},#guild_boss_mgr{hp=CurHp,state=?STATE_OPEN}=State) when CurHp>0->
    #guild_boss_mgr{
        scene = Scene,
        act = Act,
        mon = BossID,
        mon_state = MonS,
        hp_limit  = HpLimit,
        role_ranks = ActRoleMap,
        guild_ranks = GRanksMap,
        boss_datas = BDatas
    }=State,

    RecRank0 = do_badge_add(Badges,PreRecRank),
    GRanks = maps:get(Act,GRanksMap,[]),
    RecRank = calc_inspire_hurt(RecRank0,GRanks),

    #rec_rank{
        gid  = Gid,
        hurt = Hurt
    }=RecRank,

    case check_useful_hurt(Gid,MonS,BDatas) of
        true->
            NewHp0 = max(CurHp-Hurt,0),

            RRanksMap = get_role_rank_map(Act,ActRoleMap),
            LRanks = maps:get(Gid,RRanksMap,[]),

            NewLRanks = update_role_rank(AttTime,Scene,Act,LRanks,RecRank),
            NewGRanks = update_guild_rank(AttTime,Scene,Act,GRanks,RecRank),
            NewGRanksMap = maps:put(Act,NewGRanks,GRanksMap),

            NewLRankMap = maps:put(Gid,NewLRanks,RRanksMap),
            NewActRoleMap = maps:put(Act,NewLRankMap,ActRoleMap),


            %%1000血量作为一个临界点
            NewHp = case CurHp>=1000 andalso NewHp0<1000 of
                true->
                    %%通知所有BOSS血量变低
                    mod_guild:apply_cast(?MODULE,sync_boss_hp,[Scene,BossID,100]),
                    100;
                _->
                    NewHp0
            end,
            NState0 = State#guild_boss_mgr{
                hp = NewHp,
                role_ranks = NewActRoleMap,
                guild_ranks = NewGRanksMap
            },

            NState = case NewHp=<0 of
                true ->
                    account_guild_boss(NState0);
                _->
                    NState0
            end,
            brocast_boss_hp(AttTime,Scene,Gid,NewHp,HpLimit),
            {noreply,NState};
        _->
            {noreply,State}
    end;

do_handle_cast({attack_mon,_Badges,_MonID,_RecRank,_AttTime},State)->
    %%?INFO("useless hurt:~p~n",[{_MonID,RecRank,State#guild_boss_mgr.state,State#guild_boss_mgr.hp}]),
    {noreply,State};

do_handle_cast({create_guild,GuildId},State)->
    #guild_boss_mgr{scene=SceneID,mon_state=_MonS,mon_etime=_ETime,mon=BossID}=State,
    case State#guild_boss_mgr.state of
        ?STATE_OPEN->
            {X,Y} = data_guild_boss:get(mon_pos),
            case data_mon:get(BossID) of
                [] ->
                    MonType = 1;
                #mon{type = MonType} ->
                    ok
            end,
            Lv = util:get_world_lv(),
            case data_mon_dynamic:get(BossID,Lv) of
                #mon_dynamic{att=Att}->
                    skip;
                _->
                    Att = 99999
            end,
            % FollowID = data_guild_boss:get(follow_mon),
            % MonS == ?MSTATE_BURST andalso call_follow_mon(Scene,[#guild{id=GuildId}],FollowID,ETime),
            lib_mon:async_create_mon(BossID, SceneID, ?GUILD_REM_POOL(GuildId), X, Y, MonType, GuildId, 1, [{create_key, guild_boss},{attr_list,[{?ATT,Att}]}]);
        _->
            skip
    end,
    {noreply,State};

do_handle_cast({get_mon_state,RoleID,GuildID},State)->
    Bin = pack_boss_ctrl(GuildID,State),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

%%获取鼓舞信息
do_handle_cast({get_role_inspire,RoleID,GuildID},State)->
    [FTimes,CTimes,Inspire] = get_inspire_data(RoleID,GuildID,State),
    {ok,Bin} = pt_406:write(40607,[FTimes,CTimes,Inspire]),
    lib_server_send:send_to_uid(RoleID,Bin),
    {noreply,State};

do_handle_cast({inspire_anyone,OpTy,RecRank},State)->
    #guild_boss_mgr{
        scene = Scene,
        act = Act,
        role_ranks = ActRoleMap,
        guild_ranks = GRanksMap
    }=State,
    #rec_rank{
        rid = RoleID,
        gid = GuildID
    }=RecRank,
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    LRanks = maps:get(GuildID,RRanksMap,[]),
    GRanks = maps:get(Act,GRanksMap,[]),

    NRoleRec = case lists:keyfind(RoleID,#rec_rank.rid,LRanks) of
        #rec_rank{free_times=OFtimes,cost_times=OCTimes}=ORoleRec->
            case OpTy of
                0->
                    ORoleRec#rec_rank{free_times=OFtimes+1};
                _->
                    ORoleRec#rec_rank{cost_times=OCTimes+1}
            end;
        _->
            case OpTy of
                0->
                    RecRank#rec_rank{free_times=1};
                _->
                    RecRank#rec_rank{cost_times=1}
            end
    end,
    NewLRanks = lists:keystore(RoleID,#rec_rank.rid,LRanks,NRoleRec),

    OldGuildRec =  lists:keyfind(GuildID,#rec_rank.gid,GRanks),
    NGuildRec = case OldGuildRec of
        #rec_rank{inspire=OInspire}->
            OldGuildRec#rec_rank{inspire=OInspire+1};
        _->
            RecRank#rec_rank{inspire=1}
    end,
    NewGRanks = lists:keystore(GuildID,#rec_rank.gid,GRanks,NGuildRec),


    NewGRanksMap = maps:put(Act,NewGRanks,GRanksMap),

    NewLRankMap = maps:put(GuildID,NewLRanks,RRanksMap),
    NewActRoleMap = maps:put(Act,NewLRankMap,ActRoleMap),


    {ok,Bin1} = pt_406:write(40608,[?SUCCESS,OpTy]),
    lib_server_send:send_to_uid(RoleID,Bin1),

    {ok,Bin2} = pt_406:write(40609,[NGuildRec#rec_rank.inspire]),
    brocast_guild_ranks([NGuildRec],Scene,Bin2),

    NState = State#guild_boss_mgr{
        role_ranks = NewActRoleMap,
        guild_ranks = NewGRanksMap
    },
    {noreply,NState};



do_handle_cast({mon_die,GuildID,_MonId},State)->
    #guild_boss_mgr{mon_state=MonS,boss_datas = BossDatas}=State,
    case MonS of
        ?MSTATE_BURST->
            case lists:keyfind(GuildID,#boss_ctrl.id,BossDatas) of
                #boss_ctrl{mon_state=?MSTATE_NORMAL}->
                    {noreply,State};
                #boss_ctrl{mon_state=?MSTATE_BURST,num=Num}->
                    case Num+1>=length(data_guild_boss:get(follow_pos)) of
                        true->
                            Data = #boss_ctrl{id=GuildID,mon_state=?MSTATE_NORMAL,num=Num+1},
                            NBDatas = lists:keyreplace(GuildID,#boss_ctrl.id,BossDatas,Data),
                            NState  = State#guild_boss_mgr{boss_datas=NBDatas},
                            Bin = pack_boss_ctrl(GuildID,NState),
                            lib_server_send:send_to_guild(GuildID,Bin),
                            {noreply,NState};
                        _->
                            Data = #boss_ctrl{id=GuildID,mon_state=?MSTATE_BURST,num=Num+1},
                            NBDatas = lists:keyreplace(GuildID,#boss_ctrl.id,BossDatas,Data),
                            NState  = State#guild_boss_mgr{boss_datas=NBDatas},
                            {noreply,NState}
                    end;
                _->
                    Data = #boss_ctrl{id=GuildID,mon_state=?MSTATE_BURST,num=1},
                    NBDatas = lists:keystore(GuildID,#boss_ctrl.id,BossDatas,Data),
                    NState  = State#guild_boss_mgr{boss_datas=NBDatas},
                    {noreply,NState}
            end;
        _->
            {noreply,State}
    end;

do_handle_cast({market_cashback,GuildID,Price},State)->
    #guild_boss_mgr{
        act = Act,
        role_ranks = ActRoleMap,
        guild_ranks = GRanksMap
    }=State,

    GRanks = maps:get(Act,GRanksMap,[]),
    RRanksMap = get_role_rank_map(Act,ActRoleMap),

    GuildData = lists:keyfind(GuildID,#rec_rank.gid,GRanks),
    case is_record(GuildData,rec_rank) of
        true->
            #rec_rank{
                cash = CurCash,
                gname = GName,
                count = CurCount,
                total = Total,
                finish = IsFinish
            }=GuildData,
            Count = CurCount+1,
            Cash  = CurCash+Price,
            NGuildData = case Count>=Total andalso Total>0 andalso IsFinish=<0 of
                true->%%都拍完了 结算
                    LRanks = maps:get(GuildID,RRanksMap,[]),
                    Roles = filter_valid_member(LRanks,[]),
                    Roles /= [] andalso mod_guild:apply_cast(?MODULE,guild_market_cashback,[Act,GuildID,GName,Cash,Roles]),
                    GuildData#rec_rank{cash=Cash,count=Count,finish=1};
                _->
                    GuildData#rec_rank{cash=Cash,count=Count}
            end,
            Sql = io_lib:format(?SQL_UPDATE_GUILD_COUNT,[Cash,Count,Act,2,GuildID]),
            db:execute(Sql),
            NGRanks = lists:keyreplace(GuildID,#rec_rank.gid,GRanks,NGuildData),
            NewGRanksMap = maps:put(Act,NGRanks,GRanksMap),
            {noreply,State#guild_boss_mgr{guild_ranks=NewGRanksMap}};
        _->
            {noreply,State}
    end;

do_handle_cast({role_enter,RoleID, _RLv,GuildId, _GName},State)->
    #guild_boss_mgr{state=CurS,act=_SubAct,role_map = RoleMap}=State,
    case CurS == ?STATE_OPEN of
        true->
            RoleList = maps:get(GuildId, RoleMap, []),
            NewRoleMap = maps:put(GuildId, [RoleID|lists:delete(RoleID, RoleList)], RoleMap);
            % mod_guild_tribe_mgr:enter_scene_logic(RoleID, GuildId, GName, RLv, ?MOD_GUILD_BOSS, SubAct);
        _->
            NewRoleMap = RoleMap
    end,
    % trigger_enter_guild_boss_event(RoleID, SubAct),
    {noreply,State#guild_boss_mgr{role_map = NewRoleMap}};

do_handle_cast({role_exit, RoleId, GuildId}, State)->
    #guild_boss_mgr{state=CurS, role_map = RoleMap}=State,
    case CurS == ?STATE_OPEN of
        true->
            RoleList = maps:get(GuildId, RoleMap, []),
            NewRoleMap = maps:put(GuildId, lists:delete(RoleId, RoleList), RoleMap);
        _ ->
            NewRoleMap = RoleMap
    end,
    {noreply,State#guild_boss_mgr{role_map = NewRoleMap}};

do_handle_cast({role_revive, RoleId, GuildId}, State)->
    #guild_boss_mgr{state = CurS, act = Act, role_ranks = ActRoleMap}=State,
    case CurS == ?STATE_OPEN of
        true ->
            RanksMap = get_role_rank_map(Act, ActRoleMap),
            RoleList = maps:get(GuildId, RanksMap, []),
            NewRoleList =
            case lists:keyfind(RoleId, #rec_rank.rid, RoleList) of
                #rec_rank{revive_times = ReviveTimes} = RecRank ->
                    NewReviveTimes = ReviveTimes + 1,
                    lists:keystore(RoleId, #rec_rank.rid, RoleList,
                        RecRank#rec_rank{revive_times = NewReviveTimes}
                    );
                _ ->
                    RoleList
            end,
            NewRankMap = maps:put(GuildId, NewRoleList, RanksMap),
            NewActRoleMap = maps:put(Act, NewRankMap, ActRoleMap);
        _ ->
            NewActRoleMap = ActRoleMap
    end,
    {noreply,State#guild_boss_mgr{role_ranks = NewActRoleMap}};

do_handle_cast({update_box_remain,GuildID,BoxN},State)->
    #guild_boss_mgr{boss_datas = BossDatas}=State,
    case lists:keyfind(GuildID,#boss_ctrl.id,BossDatas) of
        #boss_ctrl{box=OBox}=BoxD->
            Data = BoxD#boss_ctrl{box=OBox+BoxN},
            NBDatas = lists:keyreplace(GuildID,#boss_ctrl.id,BossDatas,Data),
            NState  = State#guild_boss_mgr{boss_datas=NBDatas},
            {noreply,NState};
        _->
            Data = #boss_ctrl{id=GuildID,box=BoxN},
            NBDatas = lists:keystore(GuildID,#boss_ctrl.id,BossDatas,Data),
            NState  = State#guild_boss_mgr{boss_datas=NBDatas},
            {noreply,NState}
    end;


do_handle_cast(_Msg, State) ->
    {noreply, State}.


%%进入活动 召唤BOSS
do_handle_info({enter_start,Act},State)->
    NState = do_start(Act,State),
    %% 判断托管
    offline_hosting_guild_boss:check_hosting(Act),
    {noreply, NState};

%%结束 进入结束 5s后清场
do_handle_info(enter_close,State)->
    #guild_boss_mgr{scene=Scene,act=Act,mon=BossID,state=CurS,
        role_ranks = ActRoleMap, hp_limit = HpLim, hp = Hp}=State,
    %% TA数据上报
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    update_ta_data(RRanksMap, max(1, HpLim-Hp)),
    NState0 = case CurS of
        ?STATE_OPEN->
            %%通知怪物血量变低
            account_guild_boss(State#guild_boss_mgr{hp=100});
        _->
            State
    end,
    CurS == ?STATE_OPEN andalso mod_guild:apply_cast(?MODULE,sync_boss_hp,[Scene,BossID,100]),
    NState = NState0#guild_boss_mgr{state=?STATE_CLOSE,steps=[]},
    {ok,Bin} = pt_406:write(40600,[Act,0,0,0,?STATE_CLOSE,0,NState#guild_boss_mgr.etime]),
    OpenLv = lib_module:get_open_lv(?MOD_GUILD_BOSS),
    lib_server_send:send_to_all(all_lv, {OpenLv, 40600}, Bin),
    %%还是要3s后通知怪物清理
    Scene>0 andalso erlang:send_after(3000,self(),{clear_guild_boss,BossID}),
    save_guild_boss(Act,NState),

    #guild_boss_mgr{
        guild_ranks = GRanksMap
    }=NState,
    GRanks = maps:get(Act,GRanksMap,[]),
    case lists:keyfind(1,#rec_rank.rank,GRanks) of
        #rec_rank{gname=GName}->
            lib_chat:send_TV({all}, ?MOD_GUILD_BOSS, 2, [GName]);
        _->
            skip
    end,
    lib_chat:send_TV({all}, ?MOD_GUILD_BOSS, 3, []),
    {noreply, NState};

do_handle_info({clear_guild_boss,BossID},State)->
    #guild_boss_mgr{scene=Scene,act=Act}=State,
    Scene>0 andalso mod_guild:apply_cast(?MODULE,clear_guild_boss,[Scene,BossID]),
    offline_hosting_guild_boss:notice_logout(Act),
    {noreply,State#guild_boss_mgr{scene=0}};

%%
do_handle_info(enter_idle,_State)->
    NState   = #guild_boss_mgr{state=?STATE_IDLE},
    {ok,Bin} = pt_406:write(40600,[0,0,0,0,?STATE_IDLE,0,0]),
    OpenLv = lib_module:get_open_lv(?MOD_GUILD_BOSS),
    lib_server_send:send_to_all(all_lv, {OpenLv, 40600}, Bin),
    {noreply, NState};

%%结束狂暴 进入正常 清理可能存在的小怪
do_handle_info(enter_normal,State)->
    #guild_boss_mgr{scene=_Scene,steps=OSteps,boss_datas=OBossDatas}=State,
    % FollowID = data_guild_boss:get(follow_mon),
    % mod_guild:cast_to_guild({clear_follow_mon,Scene,FollowID}),
    {Msg,Remain,Steps} = get_boss_step(OSteps),
    MRef = case Msg /= idle of
        true->
            erlang:send_after(Remain*1000,self(),Msg);
        _->
            0
    end,
    BossDatas = reset_boss_data(OBossDatas,[]),
    NState = State#guild_boss_mgr{
        mon_state = ?MSTATE_NORMAL,
        mon_ref = MRef,
        boss_datas = BossDatas,
        steps = Steps
    },
    {noreply,NState};

%%进入掉箱子
do_handle_info(enter_box,State)->
    #guild_boss_mgr{
        scene = Scene,
        act = Act,
        mon = Mid,
        steps=OSteps,
        click=OClick,
        role_ranks = ActRoleMap
    }=State,
    {Msg,RemainT,Steps} = get_boss_step(OSteps),
    ETime = utime:unixtime()+RemainT,
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    F = fun(GuildID, Ranks, List) ->
        L = length(Ranks),
        [{GuildID,L}|List]
    end,
    JoinDatas = maps:fold(F, [], RRanksMap),
    mod_guild:apply_cast(?MODULE,create_drop_box,[Mid,Scene,JoinDatas,OClick+1]),
    MRef = case Msg /= idle of
        true->
            erlang:send_after(RemainT*1000,self(),Msg);
        _->
            0
    end,
    %% 处理掉落
    RollTime = case data_guild_boss:get(roll_time) of
                   TTime when is_integer(TTime), TTime > 0 -> TTime;
                   _ -> 15
               end,
    erlang:send_after(RollTime*1000, self(), {handle_drop_list}),
    NState = State#guild_boss_mgr{
        mon_state = ?MSTATE_NORMAL,
        mon_ref = MRef,
        steps = Steps,
        click = OClick+1,
        mon_etime = ETime
    },
    {noreply,NState};

%% 处理掉落逻辑
do_handle_info({handle_drop_list}, State) ->
    #guild_boss_mgr{roll_map = RollMap, drop_map = DropMap, role_map = _RoleMap,
        act = Act, role_ranks = ActRoleRanks
    } = State,
    RoleRankMap = get_role_rank_map(Act, ActRoleRanks),
    F = fun(GuildId, DropParams, TRoleRankMap) ->
        case DropParams of
            [MonArgs, DropRule, DropList] ->
                RollRolesMap = maps:get(roll_drops, RollMap, #{}),
                % RoleList = maps:get(GuildId, RoleMap, []),
                GuildRoll = maps:get(GuildId, RollRolesMap, #{}),
                % RefuseMap = maps:get(refuse_roll_roles, RollMap, #{}),
                % RefuseDropsMap = maps:get(GuildId, RefuseMap, #{}),
                %% 自动roll点(拒绝roll点的需要排除在外)
                % GuildRoll1 = auto_roll(DropList, GuildRoll, RefuseDropsMap, RoleList),
                handle_drop_list_core(GuildId, GuildRoll, MonArgs, DropRule, TRoleRankMap, DropList);
            _ ->
                TRoleRankMap
        end end,
    NewRoleRankMap = maps:fold(F, RoleRankMap, DropMap),
    % ?INFO_TTY("NewRoleRankMap is ~w~n",[NewRoleRankMap]),
    NewActRoleRanks = maps:put(Act, NewRoleRankMap, ActRoleRanks),
    {noreply, State#guild_boss_mgr{role_ranks = NewActRoleRanks}};

%%状态结束 结束狂暴
do_handle_info(enter_finish,State)->
    #guild_boss_mgr{scene=_Scene,boss_datas=OBossDatas}=State,
    % FollowID = data_guild_boss:get(follow_mon),
    % mod_guild:apply_cast(?MODULE,clear_follow_mon,[Scene,FollowID]),
    BossDatas = reset_boss_data(OBossDatas,[]),
    NState = State#guild_boss_mgr{
        mon_state = ?MSTATE_NORMAL,
        boss_datas = BossDatas,
        steps = [],
        click = 0
    },
    {noreply,NState};

%%广播榜单
do_handle_info({brocast_guild_ranks,AcSub},State)->
    #guild_boss_mgr{guild_ranks=GRanksMap,scene=Scene,state=CurS}=State,
    case CurS /= ?STATE_CLOSE of
        true->
            GuildRanks = maps:get(AcSub,GRanksMap,[]),
            Bin = pack_40603_data(AcSub,GuildRanks),
            brocast_guild_ranks(GuildRanks,Scene,Bin),
            RankRef = erlang:send_after(1000,self(),{brocast_guild_ranks,AcSub}),
            NState  = State#guild_boss_mgr{rank_ref=RankRef};
        _->
            NState = State
    end,
    {noreply,NState};


do_handle_info(_Msg, State) ->
    {noreply, State}.

handle_event(Player, #event_callback{type_id = ?EVENT_FIN_CHANGE_SCENE}) ->
    #player_status{id = RoleId, old_scene_info = OldSceneInfo, scene = SceneId, figure = Figure, guild = StatusGuild} = Player,
    case data_scene:get(SceneId) of
        #ets_scene{type = ?SCENE_TYPE_GUILD} ->
            mod_guild_boss_mgr:role_enter(RoleId, Figure#figure.lv, StatusGuild#status_guild.id, StatusGuild#status_guild.name);
        _ ->
            ignore
    end,
    case OldSceneInfo of
        {OldScene, _, _, _, _} ->
            case data_scene:get(OldScene) of
                #ets_scene{type = ?SCENE_TYPE_GUILD} ->
                    case data_scene:get(SceneId) of
                        #ets_scene{type = ?SCENE_TYPE_GUILD} ->
                            ignore;
                        _ ->
                            mod_guild_boss_mgr:role_exit(RoleId, StatusGuild#status_guild.id)
                    end;
                _ ->
                    ignore
            end;
        _ ->
            ignore
    end,
    {ok, Player};
handle_event(Status,#event_callback{type_id = ?EVENT_DISCONNECT})->
    #player_status{id = RoleId, guild=#status_guild{id = GuildId}}=Status,
    GuildId > 0 andalso mod_guild_boss_mgr:role_exit(RoleId, GuildId),
    {ok, Status};
%% 复活记录次数
handle_event(Status,#event_callback{type_id = ?EVENT_REVIVE})->
    #player_status{id = RoleId, guild=#status_guild{id = GuildId}}=Status,
    GuildId > 0 andalso mod_guild_boss_mgr:role_revive(RoleId, GuildId),
    {ok, Status};
handle_event(Player, _) ->
    {ok, Player}.

%%trigger_enter_guild_boss_event(RoleId, SubAct) ->
%%    case SubAct of
%%        1->
%%            lib_child_task:async_event(RoleId, lib_child_task, finish_guild_noon_boss, []);
%%        _ ->
%%            lib_child_task:async_event(RoleId, lib_child_task, finish_guild_night_boss, [])
%%    end.

attack_mon(Atter, Minfo, Hurt)->
    #battle_return_atter{
        real_id = RoleID,
        real_name = RName,
        guild_id = GuildID,
        guild_name = GName,
        flag = Flag,
        badge = Badges,
        att_time = AttTime                       % 攻击者攻击时刻
    } = Atter,
    #scene_object{
        sign = Sign,
        scene = SceneId,
        mon = MonInfo
    } = Minfo,
    InGuild = lib_guild_api:check_in_guild_scene(SceneId),
    case InGuild andalso Sign == ?BATTLE_SIGN_MON of
        true ->
            #scene_mon{create_key = CreateKey, mid = MonId} = MonInfo,
            case CreateKey of
                guild_boss->
                    RecRank = #rec_rank{
                        rid = RoleID,
                        gid = GuildID,
                        name = RName,
                        gname = GName,
                        hurt = Hurt,
                        flag = Flag
                    },
                    gen_server:cast(?MODULE, {attack_mon,Badges,MonId,RecRank,AttTime});
                _->
                    skip
            end;
        false ->
            skip
    end.

mon_die(Atter,Minfo,Klist)->
    #battle_return_atter{
        guild_id = GuildID
    } = Atter,
    #scene_object{
        sign = Sign,
        scene = SceneId,
        scene_pool_id = PoolId,
        copy_id = CopyId,
        mon = MonInfo
    } = Minfo,
    InGuild = lib_guild_api:check_in_guild_scene(SceneId),
    case InGuild  andalso Sign == ?BATTLE_SIGN_MON of
        true ->
            #scene_mon{create_key = CreateKey, mid = MonId} = MonInfo,
            case CreateKey of
                guild_boss_follow->
                    gen_server:cast(?MODULE,{mon_die,GuildID,MonId});
                guild_boss ->
                    mod_scene_agent:apply_cast(SceneId, PoolId, phantom_task_api, kill_guild_boss_trigger, [CopyId, Klist]);
                _->
                    skip
            end;
        false ->
            skip
    end.

sync_boss_hp(Scene,BossID,Hp)->
    GuildMap = lib_guild_data:get_guild_map(),
    GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
    sync_boss_hp(Scene,GuildList,BossID,Hp).
sync_boss_hp(_,[],_,_)->
    ok;
sync_boss_hp(SceneID,[H|T],BossID,Hp)->
    #guild{id=GuildID}=H,
    Pool = ?GUILD_REM_POOL(GuildID),
    catch case lib_mon:get_scene_mon_by_mids(SceneID, Pool,GuildID,[BossID], #scene_object.id) of
        [MonID|_]->
            lib_mon:change_attr_by_ids(SceneID, Pool,[MonID],[{hp, Hp}]);
        _R->
            ignore
    end,
    sync_boss_hp(SceneID,T,BossID,Hp).


% %%清理随身怪
% clear_follow_mon(Scene,FollowID)->
%     GuildMap = lib_guild_data:get_guild_map(),
%     GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
%     clear_follow_mon(Scene,GuildList,FollowID).
% clear_follow_mon(_,[],_)->
%     ok;
% clear_follow_mon(SceneID,[H|T],FollowID)->
%     #guild{id=GuildID}=H,
%     Pool = GuildID rem 10,
%     lib_mon:clear_scene_mon_by_mids(SceneID,Pool,GuildID,1,[FollowID]),
%     {ok,Bin} = pt_406:write(40606,[?MSTATE_NORMAL,0]),
%     lib_server_send:send_to_guild(GuildID,Bin),
%     clear_follow_mon(SceneID,T,FollowID).

% %%召唤随身怪
% call_follow_mon(Scene,FollowID,ETime)->
%     GuildMap = lib_guild_data:get_guild_map(),
%     GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
%     call_follow_mon(Scene,GuildList,FollowID,ETime).
% call_follow_mon(_,[],_,_)->
%     ok;
% call_follow_mon(SceneID,[H|T],FollowID,ETime)->
%     #guild{id=GuildID}=H,
%     case data_mon:get(FollowID) of
%         [] ->
%             MonType = 1;
%         #mon{type = MonType} ->
%             ok
%     end,
%     Args = [{create_key, guild_boss_follow}],
%     Pool = GuildID rem 10,
%     PosList = data_guild_boss:get(follow_pos),
%     [lib_mon:async_create_mon(FollowID, SceneID,Pool, X, Y, MonType, GuildID, 1, Args)||{X,Y}<-PosList],
%     {ok,Bin} = pt_406:write(40606,[?MSTATE_BURST,ETime]),
%     lib_server_send:send_to_guild(GuildID,Bin),
%     call_follow_mon(SceneID,T,FollowID,ETime).


%%清理BOSS
clear_guild_boss(Scene,BossID)->
    GuildMap = lib_guild_data:get_guild_map(),
    GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
    clear_guild_boss(Scene,GuildList,BossID).
clear_guild_boss(_,[],_)->
    ok;
clear_guild_boss(SceneID,[H|T],BossID)->
    #guild{id=GuildID}=H,
    Pool = ?GUILD_REM_POOL(GuildID),
    lib_mon:clear_scene_mon(SceneID,Pool,GuildID,1),
    clear_guild_boss(SceneID,T,BossID).

%%通知各大驻地生成BOSS
init_guild_boss(Scene,BossID,RealHP,Att)->
    GuildMap = lib_guild_data:get_guild_map(),
    GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
    init_guild_boss(Scene,BossID,RealHP,Att,GuildList).

init_guild_boss(_,_,_,_,[])->
    ok;
init_guild_boss(SceneID,BossID,RealHP,Att,[H|T])->
    #guild{id=GuildID}=H,
    {X,Y} = data_guild_boss:get(mon_pos),
    case data_mon:get(BossID) of
        [] ->
            MonType = 1;
        #mon{type = MonType} ->
            ok
    end,
    lib_mon:async_create_mon(BossID, SceneID, ?GUILD_REM_POOL(GuildID), X, Y, MonType, GuildID, 1, [{create_key, guild_boss},{attr_list,[{?HP,RealHP},{?ATT,Att}]}]),
    init_guild_boss(SceneID,BossID,RealHP,Att,T).

%%更新社团个人榜单
update_role_rank(AttTime,Scene,Act,LRanks,RecRank)->
    #rec_rank{
        rid = RoleID,
        gid = Gid,
        hurt = Hurt
    }=RecRank,
    Now = utime:unixtime(),
    case lists:keyfind(RoleID,#rec_rank.rid,LRanks) of
        #rec_rank{stime=OSTime,hurt=OHurt,free_times=FTimes,cost_times=CTimes,revive_times=ReviveTimes}->
            skip;
        _->
            OHurt = 0,OSTime=0,FTimes=0,CTimes=0,ReviveTimes=0
    end,
    NHurt = OHurt+Hurt,
    Stime = case OSTime>0 of
        true->
            OSTime;
        _->
            Now
    end,
    NewRecRank = RecRank#rec_rank{hurt=NHurt,stime=Stime,etime=Now,free_times=FTimes,cost_times=CTimes,revive_times=ReviveTimes},
    NewLRanks0 = lists:keystore(RoleID,#rec_rank.rid,LRanks,NewRecRank),
    NewLRanks1 = compare_hurt(NewLRanks0),
    {NewLRanks,_LineHp}  = compare_hurt_data(NewLRanks1,1,[],0),
    case get({last_brocast_rank,Gid}) of
        undefined ->
            LastAttrT = AttTime-2000;
        LastAttrT->
            skip
    end,
    case AttTime-LastAttrT>1000 of
        true->
            brocast_guild_role_ranks(Scene,Act,Gid,NewLRanks);
        _->
            skip
    end,
    case lists:keyfind(RoleID,#rec_rank.rid,NewLRanks) of
        #rec_rank{rank=MRank,hurt=MHurt}->
            {ok,Bin} = pt_406:write(40604,[Act,0,RoleID,MRank,MHurt]),
            lib_server_send:send_to_uid(RoleID,Bin);
        _->
            skip
    end,
    NewLRanks.

%%场景广播
brocast_guild_role_ranks(Scene,Act,Gid,LRanks)->
    Bin = pack_40602_data(Act,LRanks),
    lib_server_send:send_to_scene(Scene,?GUILD_REM_POOL(Gid),Gid,Bin),
    ok.

brocast_guild_ranks([],_Scene,_Bin)->
    ok;
brocast_guild_ranks([H|T],Scene,Bin)->
    #rec_rank{gid=Gid}=H,
    lib_server_send:send_to_scene(Scene,?GUILD_REM_POOL(Gid),Gid,Bin),
    brocast_guild_ranks(T,Scene,Bin).


pack_40602_data(Act,LRanks)->
    MaxRank = data_guild_boss:get(rank_role),
    LRanks0 = [R||R<-LRanks,R#rec_rank.rank=<MaxRank],
    LRanks1  = pack_guild_role_rank(LRanks0,[]),
    {ok,Bin} = pt_406:write(40602,[Act,LRanks1]),
    Bin.

pack_40603_data(Act,GRanks)->
    MaxRank = data_guild_boss:get(rank_guild),
    GRanks0 = [R||R<-GRanks,R#rec_rank.rank=<MaxRank],
    GRanks1  = pack_guild_rank(GRanks0,[]),
    {ok,Bin} = pt_406:write(40603,[Act,GRanks1]),
    Bin.

pack_guild_role_rank([],LRanks)->
    LRanks;
pack_guild_role_rank([H|T],LRanks)->
    #rec_rank{
        rank = R,
        name = Name,
        hurt = Hurt
    }=H,
    pack_guild_role_rank(T,[{R,Name,Hurt}|LRanks]).


pack_guild_rank([],LRanks)->
    LRanks;
pack_guild_rank([H|T],LRanks)->
    #rec_rank{
        rank = R,
        gname = Name,
        hurt = Hurt
    }=H,
    pack_guild_rank(T,[{R,Name,Hurt}|LRanks]).

%% 打包roll点信息
pack_40616_data(RandList) ->
    F = fun(RandInfo, TList) ->
        case RandInfo of
            {RoleId, Rand} ->
                RoleName =
                    case lib_role:get_role_show(RoleId) of
                        #ets_role_show{figure = Figure} -> Figure#figure.name;
                        _ -> ""
                    end,
                [{RoleId, RoleName, Rand}|TList];
            _ ->
                TList
        end end,
    DropRollInfos = lists:foldl(F, [], RandList),
    DropRollInfos.

compare_hurt(Roles)->
    lists:sort(fun
        (A1, A2) ->
            compare_hurt(A1, A2)
    end, Roles).
compare_hurt(A,B)->
    #rec_rank{hurt=HurtA}=A,
    #rec_rank{hurt=HurtB}=B,
    HurtA>=HurtB.

compare_hurt_data([],_,Roles,LineHp)->
    {lists:reverse(Roles),LineHp};
compare_hurt_data([H|T],Rank,Roles,LineHp)->
    compare_hurt_data(T,Rank+1,[H#rec_rank{rank=Rank}|Roles],LineHp+H#rec_rank.hurt).


%%血量广播
brocast_boss_hp(AttTime,Scene,GuildID,Hp,HpLimit)->
    case get(last_brocast_hp) of
        undefined->
            LastAttrT = AttTime-1000;
        LastAttrT ->
            skip
    end,
    case AttTime-LastAttrT>500 of
        true->
            put(last_brocast_hp,AttTime),
            {ok,Bin} = pt_406:write(40601,[Hp,HpLimit]),
            lib_server_send:send_to_scene(Scene,?GUILD_REM_POOL(GuildID),Bin);
        _->
            skip
    end,
    ok.


%%更新帮派
update_guild_rank(AttTime,Scene,Act,GRanks,RecRank)->
    #rec_rank{
        gid = GuildID,
        hurt = Hurt
    }=RecRank,
    OldRec =  lists:keyfind(GuildID,#rec_rank.gid,GRanks),
    NRec = case OldRec of
        #rec_rank{hurt=OHurt}->
            NHurt = OHurt+Hurt,
            OldRec#rec_rank{hurt=NHurt};
        _->
            RecRank
    end,
    NewGRanks0 = lists:keystore(GuildID,#rec_rank.gid,GRanks,NRec),
    NewGRanks1 = compare_hurt(NewGRanks0),
    {NewGRanks,_}  = compare_hurt_data(NewGRanks1,1,[],0),
    % Bin0 = pack_40603_data(Act,GRanks),
    % brocast_guild_ranks(NewGRanks,Scene,Bin0),
    case get({last_brocast_rank,GuildID}) of
        undefined ->
            LastAttrT = AttTime-2000;
        LastAttrT->
            skip
    end,
    case AttTime-LastAttrT>1000 of
        true->
            put({last_brocast_rank,GuildID},AttTime),
            case lists:keyfind(GuildID,#rec_rank.gid,NewGRanks) of
                #rec_rank{rank=MRank,hurt=MHurt}->
                    {ok,Bin} = pt_406:write(40604,[Act,1,GuildID,MRank,MHurt]),
                    lib_server_send:send_to_scene(Scene,?GUILD_REM_POOL(GuildID),GuildID,Bin);
                _->
                    skip
            end;
        _->
            skip
    end,
    NewGRanks.

%%功能结算
account_guild_boss(State)->
    #guild_boss_mgr{
        act = Act,
        role_ranks = ActRoleMap,
        rank_ref = ORankRef,
        guild_ranks = GRanksMap
    }=State,
    util:cancel_timer(ORankRef),

    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    GRanks = maps:get(Act,GRanksMap,[]),

    Wlv = util:get_world_lv(),
    Day = util:get_open_day(),
    NRanksMap0 = account_guild_rank(GRanks,Wlv,Day,RRanksMap),
    {NGRanks,NRanksMap1} = account_guild(GRanks,Wlv,Day,NRanksMap0,[]),
    RankRoles = maps:to_list(NRanksMap1),
    NewRankRoles = account_guild_role_rank(Wlv,Day,RankRoles),
    NRanksMap = maps:from_list(NewRankRoles),
    % TopGuilds = make_guilds(NGRanks,[]),
    spawn(fun()-> account_all_roles(NewRankRoles) end),
    spawn(fun()-> account_all_guilds(NGRanks) end),

    NActRoleMap = maps:put(Act,NRanksMap,ActRoleMap),
    NGRanksMap  = maps:put(Act,NGRanks,GRanksMap),

    ETime = utime:unixtime()+data_guild_boss:get(maket_notice_time),

    State#guild_boss_mgr{state=?STATE_CLOSE,
        role_ranks=NActRoleMap,guild_ranks=NGRanksMap,etime=ETime,
        role_map = #{}, roll_map = #{}, drop_map = #{}
    }.

account_guild([],_Wlv,_Day,NRankMap,NGRanks)->
    {NGRanks,NRankMap};
account_guild([H|T],Wlv,Day,RankMap,GRanks)->
    #rec_rank{
        rank = Rank,
        gid  = Gid
    }=H,
    Ranks = maps:get(Gid,RankMap,[]),
    RoleNum = calc_participate(Ranks),
    Rule = data_guild_boss:get_awards(3,Rank,Wlv,Day,RoleNum),
    case Rule /= [] of
        true->
            {StableDrops,RandDrops} = drop_logic:calc_drop_goods(Rule, 0),
            DropGoods = StableDrops++RandDrops,
            NewDropGoods = trans_to_goods(3,DropGoods,[]),
            NRanks   = add_guild_rank(3,Ranks,NewDropGoods,[]),
            NRankMap = maps:put(Gid,NRanks,RankMap),
            account_guild(T,Wlv,Day,NRankMap,[H#rec_rank{gawards=NewDropGoods,count=0,finish=0,total=length(NewDropGoods)}|GRanks]);
        _->
            account_guild(T,Wlv,Day,RankMap,[H|GRanks])
    end.


account_guild_rank([],_,_,NRankMap)->
    NRankMap;
account_guild_rank([H|T],Wlv,Day,RankMap)->
    #rec_rank{
        rank = Rank,
        gid  = Gid
    }=H,
    Ranks = maps:get(Gid,RankMap,[]),
    RoleNum = calc_participate(Ranks),
    Rule = data_guild_boss:get_awards(2,Rank,Wlv,Day,RoleNum),
    case Rule /= [] of
        true->
            {StableDrops,RandDrops} = drop_logic:calc_drop_goods(Rule, 0),
            DropGoods = StableDrops++RandDrops,
            NRanks = add_guild_rank(2,Ranks,{DropGoods,Rank},[]),
            NRankMap = maps:put(Gid,NRanks,RankMap),
            account_guild_rank(T,Wlv,Day,NRankMap);
        _A->
            account_guild_rank(T,Wlv,Day,RankMap)
    end.


add_guild_rank(_,[],_,NRanks)->
    NRanks;
add_guild_rank(1,H,DropGoods,_)->
    #rec_rank{
        rawards=RAwards
    }=H,
    Awards = trans_to_goods(1,DropGoods,RAwards),
    H#rec_rank{rawards=Awards};
add_guild_rank(2,[H|T],{DropGoods,Rank},Ranks)->
    #rec_rank{
        rawards=RAwards,
        stime = Stime,
        etime = Etime
    }=H,
    NAwards = case Etime-Stime>=data_guild_boss:get(act_time) of
        true->
            trans_to_goods(2,DropGoods,RAwards);
        _->
            RAwards
    end,
    NewH = H#rec_rank{grank=Rank,rawards=NAwards},
    add_guild_rank(2,T,{DropGoods,Rank},[NewH|Ranks]);
add_guild_rank(3,[H|T],DropGoods,Ranks)->
    NewH = H#rec_rank{gawards=DropGoods},
    add_guild_rank(3,T,DropGoods,[NewH|Ranks]).


%%先结算个人参与
account_guild_role_rank(Wlv,Day,RankRoles)->
    account_guild_role_rank(Wlv,Day,RankRoles,[]).
account_guild_role_rank(_Wlv,_Day,[],RankRoles)->
    RankRoles;
account_guild_role_rank(Wlv,Day,[{Gid,Ranks}|T],RankRoles)->
    RoleNum = calc_participate(Ranks),
    NewRanks = sub_account_guild_role_rank(Wlv,Day,Ranks,RoleNum,[]),
    account_guild_role_rank(Wlv,Day,T,[{Gid,NewRanks}|RankRoles]).

sub_account_guild_role_rank(_Wlv,_Day,[],_,Ranks)->
    Ranks;
sub_account_guild_role_rank(Wlv,Day,[H|T],RoleNum,Ranks)->
    #rec_rank{
        rank = Rank,
        carrer = Carrer
    }=H,
    Rule = data_guild_boss:get_awards(1,Rank,Wlv,Day,RoleNum),
    case Rule /= [] of
        true->
            {StableDrops,RandDrops} = drop_logic:calc_drop_goods(Rule, Carrer),
            DropGoods = StableDrops++RandDrops,
            NewH = add_guild_rank(1,H,DropGoods,[]),
            sub_account_guild_role_rank(Wlv,Day,T,RoleNum,[NewH|Ranks]);
        _->
            sub_account_guild_role_rank(Wlv,Day,T,RoleNum,[H|Ranks])
    end.

%%掉落转道具
trans_to_goods(3,[],Awards)->
    Awards;
trans_to_goods(_,[],Awards)->
    lib_goods_api:make_reward_unique(Awards);
trans_to_goods(Type,[H|T],Awards)->
    #ets_drop_goods{drop_thing_type = DType, goods_id = GoodsId, num = Num,bind=Bind} = H,
    case DType of
        ?TYPE_GOODS when GoodsId>0 ->
            case Bind=<0 of
                true->
                    trans_to_goods(Type,T,[{?TYPE_GOODS, GoodsId, Num}|Awards]);
                _->
                    trans_to_goods(Type,T,[{?TYPE_BIND_GOODS, GoodsId, Num}|Awards])
            end;
        ?TYPE_COIN ->
            trans_to_goods(Type,T,[{?TYPE_COIN, ?GOODS_ID_COIN, Num}|Awards]);
        _->
            trans_to_goods(Type,T,Awards)
    end.

calc_participate(Ranks) ->
    Ranks1 = lists:filter(fun(#rec_rank{rid = RoleID}) -> 
        case offline_hosting_api:is_offline_hosting(RoleID, ?MOD_GUILD_BOSS) of
            true -> false;
            _    -> true
        end
    end, Ranks),
    length(Ranks1).

% %%拼接前三
% make_guilds([],Ranks)->
%     Ranks;
% make_guilds([H|T],Ranks)->
%     #rec_rank{
%         gid   = Gid,
%         rank  = Rank,
%         flag  = Flag,
%         gname = GName,
%         hurt = Hurt
%     }=H,
%     case Rank=<3 andalso Rank>0 of
%         true->
%             make_guilds(T,[{Rank,Gid,Flag,GName,Hurt}|Ranks]);
%         _->
%             make_guilds(T,Ranks)
%     end.

account_all_guilds([])->
    ok;
account_all_guilds([H|T])->
    #rec_rank{gid=Gid,gname=GName,grank=GRank,gawards=GAwards}=H,
    market:sys_put_on_goods(Gid,?MOD_GUILD_BOSS,GAwards),
    lib_log_api:log_guild_boss_guild(Gid,GName,GRank,GAwards),
    account_all_guilds(T).

account_all_roles([])->
    ok;
account_all_roles([{_,Ranks}|T])->
    sub_account_all_roles(Ranks),
    account_all_roles(T).

sub_account_all_roles([])->
    ok;
sub_account_all_roles([H|T])->
    #rec_rank{
        rid = Rid,
        name = Name,
        gid = Gid,
        gname = GName,
        rank = Rank,
        grank = GRank,
        rawards = RAwards0,
        roll_rewards = RollRewards,
        gawards = GAwards0,
        stime = Stime,
        etime = Etime
    }=H,
    RAwards = [{K,V}||{_,K,V}<-RAwards0++RollRewards],
    GAwards = [{K,V}||{_,K,V}<-GAwards0],
    {ok,Bin} = pt_406:write(40605,[Rank,GRank,RAwards,GAwards]),
    lib_server_send:send_to_uid(Rid,Bin),
    Produce = #produce{title = utext:get(4060001), content = utext:get(4060002), reward = RAwards0, type = guild_boss, show_tips = 1, remark = "guild_boss"},
    lib_goods_api:send_reward_with_mail(Rid, Produce),
    timer:sleep(100),
    lib_log_api:log_guild_boss_role(Rid,Name,Gid,GName,max(Etime-Stime,0),Rank),
    sub_account_all_roles(T).

do_start(AcSub,State)->
    #guild_boss_mgr{rank_ref=ORankRef}=State,
    util:cancel_timer(ORankRef),
    game_env:save(guild_boss,AcSub),
    NState = pre_account_cash(AcSub,State),
    ContinueT = lib_activitycalen_api:calc_continue_time(?MOD_GUILD_BOSS,AcSub),
    Ref   = erlang:send_after(ContinueT*1000,self(),enter_close),
    Wlv = util:get_world_lv(),
    BossID = data_guild_boss:get_boss(Wlv),
    RealHP = data_guild_boss:get(real_hp),
    BossSteps = data_guild_boss:get(boss_step),
    {Msg,Remain,Steps} = get_boss_step(BossSteps),
    %%实际创建超大血量怪 通知各社团驻地生成BOSS
    case data_mon_dynamic:get(BossID,Wlv) of
        #mon_dynamic{att=Att}->
            skip;
        _->
            Att = 99999
    end,
    Scene = lib_guild_api:get_guild_scene(),
    mod_guild:apply_cast(?MODULE,init_guild_boss,[Scene,BossID,RealHP,Att]),

    MRef = case Msg /= idle of
        true->
            erlang:send_after(Remain*1000,self(),Msg);
        _->
            0
    end,

    RankRef = erlang:send_after(3000,self(),{brocast_guild_ranks,AcSub}),

    Now = utime:unixtime(),
    NewState = NState#guild_boss_mgr{
        scene = Scene,
        act = AcSub,
        mon = BossID,
        mon_state = ?MSTATE_NORMAL,
        mon_ref = MRef,
        hp = RealHP,
        hp_limit = RealHP,

        state = ?STATE_OPEN,
        ref   = Ref,
        rank_ref = RankRef,
        stime = Now,
        etime = 0,
        click = 0,
        steps = Steps,
        boss_datas = []
    },

    {ok,Bin} = pt_406:write(40600,[AcSub,BossID,RealHP,RealHP,?STATE_OPEN,Now,0]),
    OpenLv = lib_module:get_open_lv(?MOD_GUILD_BOSS),
    lib_server_send:send_to_all(all_lv, {OpenLv, 40600}, Bin),
    lib_chat:send_TV({all}, ?MOD_GUILD_BOSS, 1, [?MOD_GUILD_BOSS,AcSub]),
    lib_chat:send_TV({all}, ?MOD_GUILD_BOSS, 9, []),
    % mod_guild_tribe_mgr:get_guild_members(),
    mod_guild:apply_cast(lib_guild_tribe_mod,guild_act_start,[Scene,?MOD_GUILD_BOSS,AcSub]),
    NewState.


get_boss_step([])->
    {idle,0,[]};
get_boss_step([H|T])->
    case H of
        {enter_normal,Remain}->
            {enter_normal,Remain,T};
        % {enter_burst,Remain}->
        %     {enter_burst,Remain,T};
        {enter_box,Remain}->
            {enter_box,Remain,T};
        {enter_finish,Remain}->
            {enter_finish,Remain,[]};
        _->
            {idle,0,[]}
    end.


pack_boss_ctrl(GuildID,State)->
    #guild_boss_mgr{
        mon_state = MonS,
        mon_etime = ETime,
        boss_datas = Datas
    }=State,
    {ok,Bin} = case MonS of
        ?MSTATE_NORMAL->
            pt_406:write(40606,[MonS,0]);
        _->
            case lists:keyfind(GuildID,#boss_ctrl.id,Datas) of
                #boss_ctrl{mon_state=?MSTATE_NORMAL}->
                    pt_406:write(40606,[?MSTATE_NORMAL,0]);
                _->
                    pt_406:write(40606,[?MSTATE_BURST,ETime])
            end
    end,
    Bin.


check_useful_hurt(_Gid,?MSTATE_NORMAL,_BDatas)->
    true;
check_useful_hurt(Gid,_,BDatas)->
    case lists:keyfind(Gid,#boss_ctrl.id,BDatas) of
        #boss_ctrl{mon_state=?MSTATE_NORMAL}->
            true;
        #boss_ctrl{mon_state=?MSTATE_BURST}->
            false;
        _->
            false
    end.

filter_valid_member([],Roles)->
    Roles;
filter_valid_member([H|T],Roles)->
    #rec_rank{
        rid = Rid,
        stime   = Stime, %%个人初次出手时间
        etime   = Etime  %%个人最终出手时间
    }=H,
    case Etime-Stime>=data_guild_boss:get(act_time) of
        true->
            filter_valid_member(T,[Rid|Roles]);
        _->
            filter_valid_member(T,Roles)
    end.


guild_market_cashback(Act,GuildID,GName,Cash,Roles)->
    Members = lib_guild_data:get_all_role_in_guild(GuildID),
    case lib_guild_data:get_guild_by_id(GuildID) of
        #guild{badges=Badges}->
            skip;
        _->
            Badges = []
    end,
    Discount = lib_guild_badge:badge_ability_for_cash(Badges),
    Len = length(Members),
    [Limit,Rate] = data_guild_boss:get_cash_rate(Len),
    Num = max(length(Roles),data_guild_boss:get(min_share)),
    Money = case Cash=<Limit of
        true->
            util:ceil(Cash/Num);
        _->
            util:ceil((Limit+(Cash-Limit)*(1-Rate/100+Discount/100))/Num)
    end,
    Awards  = [{?TYPE_COIN,?GOODS_ID_COIN,Money}],
    Title = utext:get(4060001),
    Content = utext:get(4060003),

    Sql = io_lib:format(?SQL_UPDATE_GUILD_FINISH,[Cash,1,Act,2,GuildID]),
    db:execute(Sql),
    RealRate = case Cash=<Limit of
        true->
            0;
        _->
            Rate
    end,
    lib_log_api:log_guild_boss_share(GuildID,GName,Len,RealRate,Cash,Money),
    [begin
        case lists:member(Rid,Members) of
            true when Money>0->
                lib_mail_api:send_sys_mail([Rid],?MOD_GUILD_BOSS,Title,Content,Awards);
            _->
                skip
        end
    end || Rid<-Roles],
    ok.

%%结算掉上一场
pre_account_cash(AcSub,State)->
    #guild_boss_mgr{
        act = Act,
        role_ranks  = ActRoleMap,
        guild_ranks = GRanksMap
    }=State,
    db_clean(AcSub),
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    GRanks    = maps:get(Act,GRanksMap,[]),
    do_pre_account_cash(Act,GRanks,RRanksMap),
    NActRoleMap = maps:remove(AcSub,ActRoleMap),
    NGRanksMap  = maps:remove(AcSub,GRanksMap),
    State#guild_boss_mgr{role_ranks=NActRoleMap,guild_ranks=NGRanksMap}.

do_pre_account_cash(_,[],_)->
    ok;
do_pre_account_cash(Act,[H|T],RRankMap)->
    #rec_rank{
        gid = GuildID,
        gname = GName,
        cash = Cash,
        finish = IsFinish
    }=H,
    LRanks = maps:get(GuildID,RRankMap,[]),
    Roles = filter_valid_member(LRanks,[]),
    case Roles /= [] andalso Cash>0 andalso IsFinish=<0 of
        true->
            mod_guild:apply_cast(?MODULE,guild_market_cashback,[Act,GuildID,GName,Cash,Roles]);
        _->
            skip
    end,
    do_pre_account_cash(Act,T,RRankMap).

db_clean(Act)->
    Sql = io_lib:format(?SQL_CLEAN_GUILD_BOSS, [Act]),
    db:execute(Sql).


get_role_rank_map(Act,ActMap)->
    case maps:get(Act,ActMap,[]) of
        []->
            RRanksMap = maps:new();
        RRanksMap->
            skip
    end,
    RRanksMap.

get_act_data(DeFault)->
    case game_env:get(guild_boss) of
        undefined->
            Act = DeFault;
        Act->
            skip
    end,
    Act.


%%数据保存
save_guild_boss(Act,State)->
    #guild_boss_mgr{
        act = Act,
        role_ranks  = ActRoleMap,
        guild_ranks = GRanksMap
    }=State,
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    GRanks    = maps:get(Act,GRanksMap,[]),
    RRanks    = maps:values(RRanksMap),

    Values = [
        begin
            #rec_rank{
                rank  = Rank,
                rid  = Rid,
                gid  = Gid,
                flag = Flag,
                name = Name,
                gname = GName,
                hurt = Hurt,

                cash    = Cash,
                count   = Count,
                total   = Total,
                finish  = Finish
            }=RecRank,
            io_lib:format("(~p,~p,~p,~p,~p,~p,'~ts','~ts',~p,~p,~p,~p,~p,~p,~p)", [Act,2,Rank,Rid,Gid,Flag,Name,GName,Hurt,Cash,Count,Total,Finish,0,0])
        end || RecRank <- GRanks
    ],
    ValuesStr = ulists:list_to_string(Values, ","),
    SQL = io_lib:format(?SQL_GUILD_BOSS_BATCH, [ValuesStr]),
    Values /= [] andalso db:execute(SQL),
    save_guild_boss_role(Act,RRanks).

save_guild_boss_role(_Act,[])->
    ok;
save_guild_boss_role(Act,[Roles|T])->
    Values = [
        begin
            #rec_rank{
                rank  = Rank,
                rid  = Rid,
                gid  = Gid,
                flag = Flag,
                name = Name,
                gname = GName,
                hurt = Hurt,

                cash    = Cash,
                count   = Count,
                total   = Total,
                finish  = Finish,
                stime   = Stime,
                etime   = Etime
            }=RecRank,
            io_lib:format("(~p,~p,~p,~p,~p,~p,'~ts','~ts',~p,~p,~p,~p,~p,~p,~p)", [Act,1,Rank,Rid,Gid,Flag,Name,GName,Hurt,Cash,Count,Total,Finish,Stime,Etime])
        end || RecRank <- Roles
    ],
    ValuesStr = ulists:list_to_string(Values, ","),
    SQL = io_lib:format(?SQL_GUILD_BOSS_BATCH, [ValuesStr]),
    Values /= [] andalso db:execute(SQL),
    save_guild_boss_role(Act,T).


load_guild_map([],GRanksMap)->
    GRanksMap;
load_guild_map([H|List],GRanksMap)->
    Sql = io_lib:format(?SQL_GUILD_BOSS_GET,[H,2]),
    All = db:get_all(Sql),
    RecRanks = init_rec_rank(All, []),
    NewGRanksMap = maps:put(H,RecRanks,GRanksMap),
    load_guild_map(List,NewGRanksMap).

load_act_map([],ActRoleMap)->
    ActRoleMap;
load_act_map([H|List],ActRoleMap)->
    Sql = io_lib:format(?SQL_GUILD_BOSS_GET,[H,1]),
    All = db:get_all(Sql),
    RecRanks  = init_rec_rank(All, []),
    RoleRanks = split_rec_rank(RecRanks,[]),
    RRanksMap = maps:from_list(RoleRanks),
    NewActRoleMap = maps:put(H,RRanksMap,ActRoleMap),
    load_act_map(List,NewActRoleMap).

init_rec_rank([],RecRanks)->
    lists:keysort(#rec_rank.rank,RecRanks);
init_rec_rank([[_,_Act,_Type,Rank,Rid,Gid,Flag,Name,GName,Hurt,Cash,Count,Total,Finish,STime,Etime]|T],RecRanks)->
    Data = #rec_rank{
        rank = Rank,
        rid = Rid,
        gid = Gid,
        flag = Flag,
        name = Name,
        gname = GName,
        hurt = Hurt,
        cash = Cash,
        count = Count,
        total = Total,
        finish = Finish,
        stime = STime,
        etime = Etime
    },
    init_rec_rank(T,[Data|RecRanks]).

split_rec_rank([],RecRanks)->
    RecRanks;
split_rec_rank([H|T],RecRanks)->
    #rec_rank{
        gid = Gid
    } = H,
    case lists:keyfind(Gid,1,RecRanks) of
        {_,Ranks}->
            NRanks = [H|Ranks];
        _->
            NRanks = [H]
    end,
    NRecRanks = lists:keystore(Gid,1,RecRanks,{Gid,NRanks}),
    case Gid>0 of
        true->
            split_rec_rank(T,NRecRanks);
        _->
            split_rec_rank(T,RecRanks)
    end.

do_badge_add(Badges,RecRank)->
    #rec_rank{
        hurt = Hurt
    }=RecRank,
    Rate  = lib_guild_badge:badge_ability_for_boss(Badges),
    NHurt = util:ceil(Hurt*(1+Rate/100)),
    RecRank#rec_rank{hurt=NHurt}.

get_inspire_data(RoleID,GuildID,State)->
    #guild_boss_mgr{
        act = Act,
        role_ranks = ActRoleMap,
        guild_ranks = GRanksMap
    }=State,
    RRanksMap = get_role_rank_map(Act,ActRoleMap),
    LRanks = maps:get(GuildID,RRanksMap,[]),
    GRanks = maps:get(Act,GRanksMap,[]),
    case lists:keyfind(RoleID,#rec_rank.rid,LRanks) of
        #rec_rank{free_times=FTimes,cost_times=CTimes}->
            skip;
        _->
            FTimes=0,CTimes=0
    end,
    case lists:keyfind(GuildID,#rec_rank.gid,GRanks) of
        #rec_rank{inspire=Inspire}->
            skip;
        _->
            Inspire = 0
    end,
    [FTimes,CTimes,Inspire].

calc_inspire_hurt(RecRank,GRanks)->
    #rec_rank{
        gid  = Gid,
        hurt = OHurt
    }=RecRank,
    Hurt = case lists:keyfind(Gid,#rec_rank.gid,GRanks) of
        #rec_rank{inspire=Ins} when Ins>0->
            Kv = data_guild_boss:get(encourage_hurt),
            util:ceil(OHurt*(1+Ins*Kv/10000));
        _->
            OHurt
    end,
    RecRank#rec_rank{hurt=Hurt}.

%%各个驻地创建
create_drop_box(Mid,Scene,JoinDatas,Click)->
    GuildMap  = lib_guild_data:get_guild_map(),
    GuildList = lib_guild_mod:get_guild_list(GuildMap, 0),
    case data_mon:get(Mid) of
        #mon{type = MonType} ->
            skip;
        _->
            MonType = 0
    end,
    [{X,Y,_}|_] = data_guild_boss:get(box_pos),
    MonArgs = #mon_args{mid=Mid,scene=Scene,boss=MonType,x=X,y=Y},
    create_drop_items(GuildList,MonArgs,JoinDatas,Click).

reset_boss_data([],BossDatas)->
    BossDatas;
reset_boss_data([H|T],BossDatas)->
    reset_boss_data(T,[H#boss_ctrl{mon_state=0,num=0}|BossDatas]).


%%创建掉落
create_drop_items([],_MonArgs,_JoinDatas,_Click)->
    ok;
create_drop_items([H|T],MonArgs,JoinDatas,Click)->
    #mon_args{mid=Mid}=MonArgs,
    #guild{id=GuildID}=H,
    Pool = ?GUILD_REM_POOL(GuildID),
    NMonArgs = MonArgs#mon_args{scene_pool_id=Pool,copy_id=GuildID},
    case lists:keyfind(GuildID,1,JoinDatas) of
        {_,J} when J>0->
            alloc_drop(GuildID,JoinDatas,NMonArgs);
        _->
            skip
    end,
    Bin0 = lib_chat:make_tv(?MOD_GUILD_BOSS, 4, []),
    {ok,Bin1} = pt_406:write(40611,[Mid,Click]),
    Bin = <<Bin0/binary,Bin1/binary>>,
    lib_server_send:send_to_guild(GuildID,Bin),
    create_drop_items(T,MonArgs,JoinDatas,Click).

alloc_drop(GuildID,JoinDatas,MonArgs)->
    [alloc_drop(GuildID,JoinDatas,MonArgs,Alloc)|| Alloc <- data_drop:get_rule_list(MonArgs#mon_args.mid)].

alloc_drop(GuildID,JoinDatas,MonArgs,Alloc)->
    DropRule = data_drop:get_rule(MonArgs#mon_args.mid, Alloc, 1),
    {StableGoods, RandGoods, _TaskGoods} = calc_drop_goods(GuildID,JoinDatas,DropRule),
    NDropList = StableGoods ++ RandGoods,
    %% 先roll点再处理掉落
    mod_guild_boss_mgr:start_roll_drops(GuildID, MonArgs, DropRule, NDropList),
    ok.
    % handle_drop_list_core(MonArgs,DropRule,NDropList).

%% 计算掉落物品
calc_drop_goods(GuildID,JoinDatas,DropRule) ->
    [_StableGoods, TaskGoods, _RandGoods] = drop_logic:get_drop_goods_list(DropRule#ets_drop_rule.task_drop_list, 0),
    DropNumList  = get_guild_drop_num_list(GuildID,JoinDatas,DropRule),
    {StableDropGoods, RandDropGoods} = drop_logic:drop_goods_list(DropNumList, 0),
    {StableDropGoods, RandDropGoods, TaskGoods}.

%% 自动roll点
auto_roll(DropList, GuildRoll, RefuseDropsMap, RoleList) ->
    RollF = fun({OrderId, Drop}, TMap) ->
        RandList = maps:get(OrderId, GuildRoll, []),
        OldRoleList = [RoleId||{RoleId, _}<-RandList],
        RefuseList  = maps:get(OrderId, RefuseDropsMap, []),
        NotRollList  = RoleList -- RefuseList,
        NotRollList1 = NotRollList -- OldRoleList,
        F1 = fun(TRoleId, TRandList) ->
            RandNumList = [Num||{_, Num}<-TRandList],
            Max = case RandNumList of
                      [_|_] -> lists:max(RandNumList);
                      _ -> 1
                  end,
            Rand = urand:rand(1, 100),
            %% 修整随机值。如果等于最大值，则-1；如果Max=1，则+1；必须保证-1后仍大于1
            Rand1 = case Rand == Max of
                        true when Max == 1 -> 2;
                        true -> max(1, Max -1);
                        _ -> Rand
                    end,
            NewMax = case Rand1 > Max of true -> Rand1; _ -> Max end,
            case Drop of
                #ets_drop_goods{goods_id = GoodsId} -> ok;
                _ -> GoodsId = 0
            end,
            Msg = utext:get(?MOD_GUILD_BOSS, 11, [GoodsId, Rand1, NewMax]),
            Args = [?CHAT_CHANNEL_GUILD, 0, Msg, "", 0, ""],
            lib_player:apply_cast(TRoleId, ?APPLY_CAST_STATUS, lib_chat, server_chat, Args),
            lib_server_send:send_to_uid(TRoleId, pt_406, 40614, [?SUCCESS, 1, OrderId, Rand1, NewMax]),
            TRandList1 = [{TRoleId, Rand1}|lists:keydelete(TRoleId, 1, TRandList)],
            TRandList1
        end,
        NewRandList = lists:foldl(F1, RandList, NotRollList1),
        maps:put(OrderId, NewRandList, TMap)
    end,
    NewGuildRoll = lists:foldl(RollF, GuildRoll, DropList),
    NewGuildRoll.

%% 处理掉落物品列表
handle_drop_list_core(_, _, _,_, RoleRankMap,[])->
    RoleRankMap;
handle_drop_list_core(GuildId, GuildRoll, _MonArgs, _DropRule, RoleRankMap, InitDropList) ->
    % DropAlive = data_guild_boss:get(drop_alive),
    % DropSpace = data_guild_boss:get(drop_space),
    % ExpireTime = utime:unixtime() + DropAlive,
    % #mon_args{mid=_Mid,scene = Scene, scene_pool_id = PoolId, copy_id = CopyID, x = Mx, y = My,boss=MBoss} = MonArgs,
    % Xys = calc_goods_drop_xy(DropSpace,Scene, PoolId, CopyID, Mx, My, length(InitDropList)),
    %% 生成掉落包数据
    %% 每一个掉落都有归属
    RoleRankList = maps:get(GuildId, RoleRankMap, []),
    F = fun({OrderId, #ets_drop_goods{goods_id = GoodsId, num = GoodNum} = _Drop}, {TRoleRankList, TTvMsg}) ->
        RoleRolls = maps:get(OrderId, GuildRoll, []),
        SortFun = fun({_, NumA}, {_, NumB}) -> NumA > NumB end,
        case lists:sort(SortFun, RoleRolls) of
            [{RoleId, RandNum}|_] -> ok;
            _ -> RoleId = 0, RandNum = 0
        end,
        Produce = #produce{reward = [{?TYPE_GOODS, GoodsId, GoodNum}], type = guild_boss},
        % DropArgs = [#player_status{id=RoleId,copy_id=CopyID,team = #status_team{}}, MonArgs, DropRule, ExpireTime, [], [], Xys, []],
        % [_, _, _, _, DropBin, _DropIds, _, _] = lists:foldl(fun lib_goods_drop:handle_drop_item/2, DropArgs, [Drop]),
        % {ok, Bin} = pt_120:write(12017, [Mid, ExpireTime, Scene, DropBin, Mx, My, MBoss]),
        % [Bin|TBinData]
        RoleId =/= 0 andalso
            lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_GUILD_BOSS),
        TRoleRankList1 = case lists:keyfind(RoleId, #rec_rank.rid, TRoleRankList) of
                             #rec_rank{roll_rewards = RollRewards} = ResRank ->
                                 RollRewards1 = [{?TYPE_GOODS, GoodsId, GoodNum}] ++ RollRewards,
                                 RollRewards2 = lib_goods_util:merge_same_goods(RollRewards1),
                                 lists:keystore(
                                     RoleId, #rec_rank.rid, TRoleRankList, ResRank#rec_rank{roll_rewards = RollRewards2}
                                 );
                             _ ->
                                 TRoleRankList
                         end,
        case RoleId =/= 0 of
            true ->
                case lib_role:get_role_show(RoleId) of
                    #ets_role_show{figure = Figure} -> ok;
                    _ -> Figure = #figure{}
                end,
                TvMsg1 = [{GuildId, Figure#figure.name, RoleId, RandNum, GoodsId}|TTvMsg];
            _ ->
                TvMsg1 = TTvMsg
        end,
        %% 通知前端roll点结算
        {ok, Bin}  = pt_406:write(40615, [?SUCCESS]),
        DropInfos  = pack_40616_data(RoleRolls),
        {ok, Bin1} = pt_406:write(40616, [OrderId, DropInfos]),
        lib_server_send:send_to_guild(GuildId, <<Bin/binary, Bin1/binary>>),
        {TRoleRankList1, TvMsg1}
        end,
    {NewRoleRankList, TvMsgs} = lists:foldl(F, {RoleRankList, []}, InitDropList),
    delay_send_tv(TvMsgs),
    NewRoleRankMap = maps:put(GuildId, NewRoleRankList, RoleRankMap),
    NewRoleRankMap.
    % lib_server_send:send_to_scene(Scene, PoolId, CopyID, BinData).

delay_send_tv(MsgList) ->
    F = fun(Msg) ->
        case Msg of
            {GuildId, RoleName, RoleId, RandNum, GoodsId} ->
                lib_chat:send_TV({guild, GuildId}, ?MOD_GUILD_BOSS, 10, [RoleName, RoleId, RandNum, GoodsId]);
            _ -> ignore
        end end,
    spawn(fun() ->
        timer:sleep(2000),
        lists:map(F, MsgList)
    end),
    ok.

get_guild_drop_num_list(GuildID,JoinDatas,DropRule)->
    case lists:keyfind(GuildID,1,JoinDatas) of
        {_,JoinN}->
            skip;
        _->
            JoinN = 0
    end,
    DropNum = data_guild_boss:get_box_num(JoinN),
    do_get_guild_drop_num_list(DropNum,DropRule,[]).

do_get_guild_drop_num_list(0,_DropRule,DropNumList)->
    DropNumList;
do_get_guild_drop_num_list(DropNum,DropRule,DropNumList)->
    DropNumList0 = drop_logic:get_drop_num_list(DropRule),
    do_get_guild_drop_num_list(DropNum-1,DropRule,DropNumList0++DropNumList).


%%禁掉boss的死亡掉落
check_drop(Mid)->
    Boss = data_guild_boss:get_all_boss(),
    case lists:member(Mid,Boss) of
        true->
            false;
        _->
            true
    end.


%%有特殊要求  拿出来
%% 计算掉落点
%%calc_goods_drop_xy(BaseV,Scene, _ScenePoolId, _CopyId, Mx, My, DropNum)->
%%    DotList = data_drop:get_dot_list(),
%%    calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, 0, [],0).
%%
%%%%分配完毕 有可能指标不够
%%calc_goods_drop_xy(BaseV,Scene,[],Mx,My,DropNum,CurNum,PosList,Limit)->
%%    case DropNum /= CurNum of
%%        true when Limit<3->%%指标不够 还不够则循环
%%            DotList = data_drop:get_dot_list(),
%%            calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum, PosList,Limit+1);
%%        _->
%%            PosList
%%    end;
%%%%数量满足
%%calc_goods_drop_xy(_BaseV,_Scene, _DotList, _Mx, _My, DropNum, DropNum, PosList,_Limit)->
%%    lists:reverse(PosList);
%%calc_goods_drop_xy(BaseV,Scene, [{Tx, Ty}|DotList], Mx, My, DropNum, CurNum, PosList,Limit)->
%%    Nx = util:ceil(Mx + Tx*BaseV),
%%    Ny = util:ceil(My + Ty*BaseV),
%%    case scene_landform:is_block(Scene, Nx, Ny) of
%%        false->
%%            case urand:rand(1,100) =< 65 of
%%                true->
%%                    calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum+1, [{Nx, Ny}|PosList],Limit);
%%                _->
%%                    calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum, PosList,Limit)
%%            end;
%%        _-> %%该坐标无效 取下一个点
%%            calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum, PosList,Limit)
%%    end.

%% -----------------------------------------------------------------------------------------------
%% @doc TA数据上报 @end
update_ta_data(RoleRankMap, HpLim) ->
    RoleRanks = lists:flatten(maps:values(RoleRankMap)),
    %% 分批上报，每20个做一个时间缓冲
    spawn(fun()-> update_ta_data_core(RoleRanks, HpLim) end),
    ok.

update_ta_data_core(RoleRanks, HpLim) ->
    F = fun(RoleRank, TList) ->
        case RoleRank of
            #rec_rank{} ->
                #rec_rank{rid = RoleId, free_times = FreeTimes, cost_times = CostTimes,
                    revive_times = ReviveTimes, hurt = Hurt
                } = RoleRank,
                Percent = max(0, round(Hurt / HpLim * 100)),
                IsHosting = offline_hosting_api:is_offline_hosting(RoleId, ?MOD_GUILD_BOSS),
                [{RoleId, IsHosting, FreeTimes + CostTimes, ReviveTimes, Percent}|TList];
            _ ->
               TList
        end end,
    SendInfoList = lists:foldl(F, [], RoleRanks),
    SendFun = fun(SendInfo, TNum) ->
        case TNum rem 20 == 0 of
            true -> timer:sleep(2000);
            _ -> ignore
        end,
        case SendInfo of
            {TRoleId, TIsHosting, TEncourageTimes, TReviveTimes, TDamagePercent} ->
                lib_player:apply_cast(TRoleId, ?APPLY_CAST_STATUS, ?HAND_OFFLINE,
                    ?MODULE, update_ta_data_on_role, [[TIsHosting, TEncourageTimes, TReviveTimes, TDamagePercent]]),
                TNum + 1;
            _ ->
                TNum + 1
        end end,
    lists:foldl(SendFun, 1, SendInfoList),
    %% 延迟10s清理数据
    lib_activitycalen_api:activity_end_clean_record(?MOD_GUILD_BOSS, 10),
    ok.

update_ta_data_on_role(Player, [IsHosting, EncourageTimes, ReviveTimes, DamagePercent]) ->
    IsCountDown = lib_activitycalen_api:get_enter_activity_record(?MOD_GUILD_BOSS, Player#player_status.id),
    ta_agent_fire:guild_boss(Player,
        [IsHosting, IsCountDown, EncourageTimes, ReviveTimes, DamagePercent]),
    {ok, Player}.
