%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     活动BOSS，由定制活动控制开启和关闭
%%% @end
%%%-------------------------------------------------------------------
-module(act_boss_mgr).
-author("liushl").

-behaviour(gen_server).

-include("local_boss.hrl").
-include("common.hrl").
-include("custom_act.hrl").
-include("mon.hrl").
-include("scene.hrl").
-include("attr.hrl").
-include("def_module.hrl").
-include("predefine.hrl").
-include("errcode.hrl").
%% API
-export([start_link/0]).

%% gen_server callbacks
-export([init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3]).
-compile(export_all).
-define(SERVER, ?MODULE).

%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc 活动控制进程
%% 活动开始-定时BOSS出生
act_boss_begin(SubType) ->
    ?MODULE ! {act_boss_begin, SubType}.

%% 活动结束-取消BOSS出生定时器
act_boss_end(SubType) ->
    ?MODULE ! {act_boss_end, SubType}.
%%--------------------------------------------------------------------
%% @doc 怪物进程
%% BOSS出生
when_boss_born(init, Object, _) ->
    boss_born(Object).
%% 受击
when_boss_be_hurt(State, _MonAtter, IsFirstAttack, _) ->
    boss_be_hurt(State, IsFirstAttack),
    ok.
%% BOSS被清理-超时/分线回收
when_boss_stop(#scene_object{id = MonId, mon = Mon}) ->
    case Mon#scene_mon.boss of
        ?MON_ACT_BOSS ->
            boss_dead(MonId);
        _ ->
            ok
    end.
%% 通知管理进程-BOSS死亡
boss_dead(MonId) ->
    ?MODULE ! {act_boss_die, MonId}.
%%--------------------------------------------------------------------
%% @doc 玩家进程
%% 请求BOSS数据-场景/分线/BOSS数量
ask_boss_info(Sid) ->
    gen_server:cast(?MODULE, {ask_boss_info, Sid}).
%% 请求当前场景的BOSS信息
ask_my_scene_boss(Sid) ->
    gen_server:cast(?MODULE, {ask_my_scene_boss, Sid}).
%% 请求进入活动场景
ask_enter_scene(RoleId, Scene) ->
    gen_server:cast(?MODULE, {ask_enter_scene, RoleId, Scene}).
%% 靠近BOSS请求该BOSS的排行数据
ask_mon_info(SceneId, PoolId, MonId, Sid) ->
    mon_mgr:send({SceneId, PoolId}, MonId, {mod, ?MODULE, send_mon_info, [Sid]}).
%% 分享位置
share_position(RoleId, MonId, RoleScene, RolePoolId, RoleX, RoleY) ->
    gen_server:cast(?MODULE, {share_position, RoleId, MonId, RoleScene, RolePoolId, RoleX, RoleY}).
%% 队伍信息变更
team_change(RoleId, TeamId, TeamLeaderName) ->
    gen_server:cast(?MODULE, {'team_flag', RoleId, TeamId, TeamLeaderName}).
%% TODO 队伍变更
gm_init_boss() ->
    ?MODULE ! gm_init_boss.
gm_clean_boss() ->
    ?MODULE ! gm_clean_boss.
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @end
%%--------------------------------------------------------------------
-spec(start_link() ->
    {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%%                     {ok, State, Timeout} |
%%                     ignore |
%%                     {stop, Reason}
%% @end
%%--------------------------------------------------------------------
-spec(init(Args :: term()) ->
    {ok, State :: #local_act_boss{}} | {ok, State :: #local_act_boss{}, timeout() | hibernate} |
    {stop, Reason :: term()} | ignore).
init([]) ->
    %% 判断是否有正在开启的活动
    case lib_custom_act_api:get_open_custom_act_infos(?CUSTOM_ACT_TYPE_BOSS) of
        [#act_info{key = {_, SubType}}|_] ->
            act_boss_begin(SubType);
        _ ->
            ignore
    end,
    {ok, #local_act_boss{}}.

%%%===================================================================
%%% Logic 
%%%===================================================================
do_handle_call(_Request, _From, State) ->
    io:format("time:[~p], module:~p: do_handle_call unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Request]),
    {reply, ok, State}.

%% 请求BOSS数据
do_handle_cast({ask_boss_info, Sid}, State) ->
    #local_act_boss{boss_info = BossInfo, next_time = NextTime} = State,
    Info =
    lists:foldl(
        fun(Boss, Temp) ->
            #act_boss_info{
                scene_id = SceneId,
                alive = Alive
            } = Boss,
            case lists:keyfind(SceneId, 1, Temp) of
                {SceneId, PoolId, Num} ->
                    lists:keyreplace(SceneId, 1, Temp, {SceneId, PoolId, Num + Alive});
                false ->
                    [{SceneId, Boss#act_boss_info.pool_id + 1, Alive}|Temp]
            end
        end, [], BossInfo
    ),
    {ok, Bin} = pt_460:write(46026, [Info, NextTime]),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% 请求当前场景的BOSS信息
do_handle_cast({ask_my_scene_boss, Sid}, State) ->
    Bin = pack_boss_info(State),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% 请求进入活动场景
do_handle_cast({ask_enter_scene, RoleId, SceneId}, State) ->
    #local_act_boss{boss_info = BossInfo} = State,
    case lists:keyfind(SceneId, #act_boss_info.scene_id, BossInfo) of
        #act_boss_info{pool_id = PoolId} ->
            local_boss_api:act_boss_enter(RoleId, SceneId, PoolId);
        false ->
            lib_scene:change_player_scene(RoleId, SceneId, 0, 0, [])
    end,
    {noreply, State};

%% 队伍变更
do_handle_cast({'team_flag', RoleId, TeamId, TeamLeaderName}, State) ->
    [
        mon_mgr:send(MonPid, MonId, {'team_flag', RoleId, TeamId, TeamLeaderName})
        || #act_boss_info{boss_pid = MonPid, mon_id = MonId} <- State#local_act_boss.boss_info
    ],
    {noreply, State};

do_handle_cast(_Request, State) ->
    io:format("time:[~p], module:~p: handle_cast unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Request]),
    {noreply, State}.

pack_boss_info(State) ->
    #local_act_boss{boss_info = BossInfo} = State,
    List =
    [
        {BossSceneId, BossPoolId + 1, MonId}
        || #act_boss_info{scene_id = BossSceneId, pool_id = BossPoolId, mon_id = MonId} <- BossInfo
    ],
    {ok, Bin} = pt_460:write(46027, [List]),
    Bin.
%%%===================================================================
%%% 玩法流程
%%%===================================================================
%% @doc 活动开始-定时BOSS出生
do_handle_info({act_boss_begin, Repeat}, #local_act_boss{sub_type = SubType} = State)
    when SubType > 0 ->
    ?ERR("receive repeat act:[~p], now subtype=~p", [Repeat, SubType]),
    {noreply, State};
do_handle_info({act_boss_begin, SubType}, _) ->
    State = refresh_next_time(#local_act_boss{sub_type = SubType}),
    {noreply, State};

%% @doc 活动结束-取消BOSS出生定时器
do_handle_info({act_boss_end, SubType}, #local_act_boss{sub_type = SubType} = State) ->
    util:cancel_timer(State#local_act_boss.ref_born),
    %% 如果有没死亡的BOSS，杀死他，一般不会，方便临时关闭活动
    clean_boss(State),
    {noreply, #local_act_boss{}};

%% @doc BOSS活动开始
do_handle_info(act_boss_init, State) ->
    {_Date, {H, M, _S}} = erlang:localtime(),
    TimeCfg = data_act_boss:get_act_boss_kv(boss_time),
    case lists:member({H, M}, TimeCfg) of
        true  ->
            %% 传闻-活动开始
            lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 31, [State#local_act_boss.sub_type]),
            %% 先清理旧BOSS，再出生新BOSS
            clean_boss(State),
            Num = init_act_boss(),
            State1 = State#local_act_boss{boss_info = [], boss_num = Num};
        false ->
            %% 活动还未开始或者是修改了配置
            State1 = State
    end,
    
    NewState = refresh_next_time(State1),
    {noreply, NewState};

do_handle_info(gm_init_boss, State) ->
    Num = init_act_boss(),
    {noreply, State#local_act_boss{boss_num = Num}};
do_handle_info(gm_clean_boss, State) ->
    clean_boss(State),
    NewState = State#local_act_boss{boss_info = []},
    Bin = pack_boss_info(NewState),
    lib_server_send:send_to_all(Bin),
    {noreply, NewState};

%% @doc BOSS出生
do_handle_info({act_boss_born, OneBoss}, State) ->
    #local_act_boss{boss_info = BossInfo, boss_num = BossNum} = State,
    NewBossInfo = lists:keystore(OneBoss#act_boss_info.mon_id, #act_boss_info.mon_id, BossInfo, OneBoss),
    NewState = State#local_act_boss{boss_info = NewBossInfo, boss_num = BossNum - 1},
    case BossNum =:= 1 of
        true  ->
            Bin = pack_boss_info(NewState),
            lib_server_send:send_to_all(Bin);
        false ->
            ok
    end,
    {noreply, NewState};

%% @doc BOSS死亡 BOSS被清理-超时/分线回收
do_handle_info({act_boss_die, MonId}, State) ->
    #local_act_boss{boss_info = BossInfo} = State,
    case lists:keyfind(MonId, #act_boss_info.mon_id, BossInfo) of
        #act_boss_info{} = OneBoss ->
            NewBossInfo = lists:keyreplace(MonId, #act_boss_info.mon_id, BossInfo, OneBoss#act_boss_info{alive = 0}),
            AllDead = lists:all(
                fun(#act_boss_info{alive = Alive}) -> Alive =:= 0 end,
                NewBossInfo
            ),
            case AllDead of
                true  ->
                    %% 传闻-活动结束
                    lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 32, []),
                    NewState = State#local_act_boss{boss_info = []},
                    Bin = pack_boss_info(NewState),
                    lib_server_send:send_to_all(Bin),
                    {noreply, NewState};
                false ->
                    {noreply, State#local_act_boss{boss_info = NewBossInfo}}
            end;
        _ ->
            {noreply, State}
    end;

do_handle_info(_Info, State) ->
    io:format("time:[~p], module:~p: handle_info unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Info]),
    {noreply, State}.

%% 定时到下一场活动开启
refresh_next_time(State) ->
    util:cancel_timer(State#local_act_boss.ref_born),
    case set_timer_boss(State#local_act_boss.sub_type) of
        false ->
            State#local_act_boss{ref_born = undefined, next_time = 0};
        {NextTime, Ref} ->
            State#local_act_boss{ref_born = Ref, next_time = NextTime}
    end.

set_timer_boss(SubType) ->
    Type = ?CUSTOM_ACT_TYPE_BOSS,
    case lib_custom_act_util:get_custom_act_open_info(Type, SubType) of
        #act_info{etime = ETime} ->
            TimeCfg = data_act_boss:get_act_boss_kv(boss_time),
            Now  = utime:unixtime(),
            {Date, {_H, M, S}} = utime:localtime(),
            NextTime = calc_next_time(Now, Date, TimeCfg, TimeCfg),
            if
                NextTime == false -> false;
                NextTime > ETime -> false;
                true ->
                    %% 那就每半小时检查一次配置
                    CheckTime = case M >= 30 of
                                    true  -> (60 - M - 1) * 60 + (60 - S);
                                    false -> (30 - M - 1) * 60 + (60 - S)
                                end,
                    DiffTime = NextTime - Now,
                    Ref = case DiffTime > CheckTime of
                        true  ->
                            erlang:send_after(CheckTime * 1000, self(), act_boss_init);
                        false ->
                            erlang:send_after(DiffTime * 1000, self(), act_boss_init)
                    end,
                    {NextTime, Ref}
            end;
        _ ->
            false
    end.

calc_next_time(Now, Date, [{H, M}|T], TimeCfg) ->
    Time = utime:unixtime({Date, {H, M, 0}}),
    case Time > Now of
        true  -> Time;
        false -> calc_next_time(Now, Date, T, TimeCfg)
    end;
calc_next_time(_Now, Date, [], [{H, M}|_]) ->
    %% 第二天
    Tomorrow = utime:get_before_day(Date, 1, 1),
    utime:unixtime({Tomorrow, {H, M, 0}});
calc_next_time(_, _, _, _) -> false.

%% 初始化BOSS
init_act_boss() ->
    AliveTime = data_act_boss:get_act_boss_kv(boss_exist),
    AllScene  = data_act_boss:get_all_scene(),
    MonNumList=
    [
        begin
            MonIds       = data_act_boss:get_scene_boss(SceneId),
            PositionList = data_act_boss:get_scene_position(SceneId),
            PickPosition = urand:get_rand_list(erlang:length(MonIds), PositionList),
            %% 选择人数最少的分线作为活动场景
            PickPool = find_min_roles_pool(SceneId),
            mod_scene_agent:erase_scene_pid(SceneId, PickPool),
            init_act_boss_by_scene(SceneId, PickPool, MonIds, PickPosition, AliveTime),
            length(PickPosition)
        end || SceneId <- AllScene, not lists:member(SceneId, [1003, 1006, 1016, 1017])
    ],
    %% 不能配置到主城和交通枢纽
    lists:sum(MonNumList).

find_min_roles_pool(SceneId) ->
    PoolIds = scene_mgr:get_scene_pool_ids(SceneId),
    find_min_roles_pool(SceneId, PoolIds, max, 0).

find_min_roles_pool(_SceneId, [], _Min, PoolId) -> PoolId;
find_min_roles_pool(SceneId, [PoolId|T], Min, Pick) ->
    case ets:lookup(?SCENE_ROLE_COUNT, {SceneId, PoolId}) of
        [#scene_role_count{num = Num}] when Num < Min ->
            find_min_roles_pool(SceneId, T, Num, Pick);
        _ ->
            find_min_roles_pool(SceneId, T, Min, Pick)
    end.

init_act_boss_by_scene(SceneId, PickPool, [BossId|TBoss], [{X, Y}|TPosition], AliveTime) ->
    Args = [
        {born_handler, {?MODULE, when_boss_born, []}},
        {be_hurt_handler, {?MODULE, when_boss_be_hurt, []}},
        {stop, AliveTime * 1000}
    ],
    lib_mon:async_create_mon(BossId, SceneId, PickPool, X, Y, 1, 0, 1, Args),
    init_act_boss_by_scene(SceneId, PickPool, TBoss, TPosition, AliveTime);
init_act_boss_by_scene(_, _, _, _, _) -> ok.

%% 清理BOSS
clean_boss(State) ->
    [
        mon_mgr:send(Pid, MonId, {stop, 1})
        || #act_boss_info{boss_pid = Pid, mon_id = MonId, alive = Alive} <- State#local_act_boss.boss_info, Alive =:= 1
    ].
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
    State :: #local_act_boss{}) ->
    {reply, Reply :: term(), NewState :: #local_act_boss{}} |
    {reply, Reply :: term(), NewState :: #local_act_boss{}, timeout() | hibernate} |
    {noreply, NewState :: #local_act_boss{}} |
    {noreply, NewState :: #local_act_boss{}, timeout() | hibernate} |
    {stop, Reason :: term(), Reply :: term(), NewState :: #local_act_boss{}} |
    {stop, Reason :: term(), NewState :: #local_act_boss{}}).
handle_call(Msg, From, State) ->
    try
        do_handle_call(Msg, From, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_call Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {reply, error, State}
    end.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_cast(Request :: term(), State :: #local_act_boss{}) ->
    {noreply, NewState :: #local_act_boss{}} |
    {noreply, NewState :: #local_act_boss{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #local_act_boss{}}).
%% 分享位置-如果出错就爆出来吧
handle_cast({share_position, RoleId, MonId, RoleScene, RolePoolId, RoleX, RoleY}, State) ->
    #local_act_boss{boss_info = BossInfo} = State,
    case lists:keyfind(MonId, #act_boss_info.mon_id, BossInfo) of
        #act_boss_info{scene_id = SceneId, pool_id = PoolId, x = X, y = Y, share_roles = ShareRoles, boss_id = BossId} = OneBoss ->
            IsNear =
                RoleScene =:= SceneId
                    andalso RolePoolId =:= PoolId
                    andalso umath:distance({X, Y}, {RoleX, RoleY}) < 1600,
            Max = data_act_boss:get_act_boss_kv(share_max),
            CanReward = length(ShareRoles) < Max
                andalso (not lists:member(RoleId, ShareRoles)),
            if
                not IsNear ->
                    {ok, Bin} = pt_460:write(46031, [?ERRCODE(err460_never_find_boss), BossId, SceneId, PoolId + 1]),
                    lib_server_send:send_to_uid(RoleId, Bin),
                    {noreply, State};
                not CanReward ->
                    {ok, Bin} = pt_460:write(46031, [1, BossId, SceneId, PoolId + 1]),
                    lib_server_send:send_to_uid(RoleId, Bin),
                    {noreply, State};
                true ->
                    Award = data_act_boss:get_act_boss_kv(share_reward),
                    %% 清除一次聊天CD
                    lib_player:apply_cast(RoleId, ?APPLY_CAST, lib_chat, clean_world_channel_cd, []),
                    lib_goods_api:send_reward_by_id(Award, act_boss_share, RoleId),
                    NewBossInfo = lists:keyreplace(MonId, #act_boss_info.mon_id, BossInfo, OneBoss#act_boss_info{share_roles = [RoleId|ShareRoles]}),
                    {ok, Bin} = pt_460:write(46031, [1, BossId, SceneId, PoolId + 1]),
                    lib_server_send:send_to_uid(RoleId, Bin),
                    {noreply, State#local_act_boss{boss_info = NewBossInfo}}
            end;
        false ->
            {ok, Bin} = pt_460:write(46031, [?ERRCODE(err460_boss_has_gone), 0, 0, 0]),
            lib_server_send:send_to_uid(RoleId, Bin),
            {noreply, State}
    end;
handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_cast Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
-spec(handle_info(Info :: timeout() | term(), State :: #local_act_boss{}) ->
    {noreply, NewState :: #local_act_boss{}} |
    {noreply, NewState :: #local_act_boss{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #local_act_boss{}}).
handle_info(Msg, State) ->
    try
        do_handle_info(Msg, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_info Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
    State :: #local_act_boss{}) ->
    term()).
terminate(_Reason, _State) ->
    ok.

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

%%%===================================================================
%%% Internal functions
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc 怪物进程
%%--------------------------------------------------------------------
%% 玩家靠近怪物
send_mon_info(State, Sid) ->
    #ob_act{
        object = #scene_object{
            id = Id,
            config_id = BossId,
            battle_attr = #battle_attr{hp_lim = Hp}
        },
        klist = KList,
        first_att = FirstAtt
    } = State,
    case FirstAtt of
        #mon_atter{name = FirstRole} ->
            FirstRole;
        _ ->
            FirstRole = ""
    end,
    HurtRank =
    [
        {RoleId, Name, Hurt}
        || #mon_atter{id = RoleId, name = Name, hurt = Hurt} <- KList
    ],
    Info = [Id, BossId, Hp, FirstRole, HurtRank],
    {ok, Bin} = pt_460:write(46029, Info),
    lib_server_send:send_to_sid(Sid, Bin),
    ok.

%% BOSS出生
boss_born(Object) ->
    #scene_object{
            id = Id,
            config_id = BossId,
            aid = Aid,
            scene = SceneId,
            scene_pool_id = PoolId,
            x = X,
            y = Y
    } = Object,
    OneBoss = #act_boss_info{
        mon_id          = Id
        , boss_id       = BossId
        , boss_pid      = Aid
        , scene_id      = SceneId
        , pool_id       = PoolId
        , x             = X
        , y             = Y
    },
    ?MODULE ! {act_boss_born, OneBoss}.

%% BOSS受击
boss_be_hurt(#ob_act{klist = [Attacker|_] = KList} = State, IsFirst) ->
    #ob_act{
        object = #scene_object{
            id = MonId,
            battle_attr = #battle_attr{hp = Hp},
            scene = Scene,
            config_id = BossId,
            scene_pool_id = ScenePool,
            copy_id = CopyId,
            x = X,
            y = Y
        }
    } = State,
    #mon_atter{
        id = RoleId,
        name = Name,
        hurt = Hurt
    } = Attacker,
    %% 首刀-传闻-首刀奖励
    case IsFirst of
        true  ->
            FirstAward = data_act_boss:get_act_boss_kv(first_hurt),
            lib_goods_api:send_reward_by_id(FirstAward, act_boss_first, RoleId),
            lib_chat:send_TV({scene, Scene, ScenePool}, ?MOD_AC_CUSTOM, 33, [Name, BossId]),
            ok;
        false ->
            ok
    end,
    %% 广播伤害
    {ok, Bin} = pt_460:write(46030, [MonId, RoleId, Name, Hurt]),
    mod_scene_agent:send_to_area_scene(Scene, ScenePool, CopyId, X, Y, Bin),
    %% 死亡-最后一刀奖励-传闻-结算
    case Hp =:= 0 of
        true  ->
            LastAward = data_act_boss:get_act_boss_kv(last_hurt),
            lib_goods_api:send_reward_by_id(LastAward, act_boss_last, RoleId),
            lib_chat:send_TV({scene, Scene, ScenePool}, ?MOD_AC_CUSTOM, 37, [BossId, Name]),
            boss_dead(MonId),
            boss_die_settlement(KList, Scene, ScenePool, BossId),
            ok;
        false ->
            ok
    end;
boss_be_hurt(_, _) -> ok.

%% 结算
%% 统计是否有同一队伍的玩家
boss_die_settlement(KList, Scene, ScenePool, BossId) ->
    F = fun(#mon_atter{hurt = A}, #mon_atter{hurt = B}) -> A > B end,
    SortList = lists:sort(F, KList),
    {RoleTeamRank, _} =
    lists:foldl(
        fun(#mon_atter{id = RoleId, name = Name, team_id = TeamId}, {Temp, Rank}) ->
            {[{RoleId, Rank, Name, TeamId}|Temp], Rank+1}
        end, {[], 1}, SortList
    ),
    SameTeamRole = find_same_team(RoleTeamRank, []),
    lists:foldl(
        fun({RankRole, TheRank, TheName, Team}, _) ->
            %% 参与奖励
            PartAward = data_act_boss:get_act_boss_kv(kill_reward),
            lib_mail_api:send_sys_mail([RankRole], ?MOD_LOCAL_BOSS, utext:get(33111701), utext:get(33111702), PartAward),
            %% 组队奖励
            case Team > 0 of
                true  ->
                    TeamAward = data_act_boss:get_act_boss_kv(team_reward),
                    lib_mail_api:send_sys_mail([RankRole], ?MOD_LOCAL_BOSS, utext:get(33111703), utext:get(33111704), TeamAward);
                false ->
                    ok
            end,
            %% 排名奖励
            RankAward = data_act_boss:get_act_boss_rank_reward(TheRank),
            case RankAward =/= [] of
                true  ->
                    lib_chat:send_TV({scene, Scene, ScenePool}, ?MOD_AC_CUSTOM, 34, [TheName, BossId, TheRank]),
                    lib_mail_api:send_sys_mail([RankRole], ?MOD_LOCAL_BOSS, utext:get(33111705), utext:get(33111706, [TheRank]), RankAward);
                false ->
                    ok
            end
        end, ok, SameTeamRole
    ).

%% 判断是否有跟自己相同队伍的玩家
find_same_team([{RoleId, Rank, Name, 0}|T], List) ->
    find_same_team(T, [{RoleId, Rank, Name, 0}|List]);
find_same_team([{RoleId, Rank, Name, Team}|T], List) ->
    {Satisfying, NotSatisfying} =
    lists:partition(
        fun({_, _, _, TeamId}) -> TeamId =:= Team end, T
    ),
    case Satisfying =:= [] of
        true  ->
            find_same_team(T, [{RoleId, Rank, Name, 0}|List]);
        false ->
            find_same_team(NotSatisfying, [{RoleId, Rank, Name, Team}|Satisfying] ++ List)
    end;
find_same_team([], List) -> List.