%% ---------------------------------
%% desc		:幻魔之家具体逻辑
%% module	:home_boss_mgr
%% author	:hh
%% time		:21/07/27
%% ---------------------------------


-module(home_boss_mgr).

-behaviour(gen_server).

-include("scene.hrl").
-include("local_boss.hrl").
-include("common.hrl").
-include("predefine.hrl").
-include("battle.hrl").
-include("def_fun.hrl").
-include("attr.hrl").
-include("server.hrl").
-include("guild.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("goods.hrl").
-include("figure.hrl").
-include("drop.hrl").
-include("errcode.hrl").
-include("common_rank.hrl").

-define(DELAY_TIME, 5000).
-define(WORKER_INIT, worker_init).
-define(TIMER_SYNC, timer_sync).

-ifdef (DEV_SERVER).
-define(GUILD_UPDATE_INTERVAL, 120000).
-else.
-define(GUILD_UPDATE_INTERVAL, 600000).
-endif.

%% 常规接口
-export([
    start_link/1,
    svr_call/2,
    svr_cast/1,
    svr_cast/2,                             %% 游戏服给管理进程发消息
    svr_cast_mon/4,                         %% 游戏服给怪物进程发消息
    home_boss_proc_name/1,
	get_home_boss_proc/1,

	revive/9,								%% 复活判断
	team_change/2,                          %% 队伍信息变更
	get_boss_hurt_info/4,                   %% 获取BOSS伤害排名
    get_deserted_boss_info/2,               %% 获取boss信息
    get_top_guild_info/3,
    enter_home_boss/6,                      %% 进入场景
    is_can_drop/3,                          %% 掉落判断等级差
    mon_sub_module_type/1,                  %% 
    mod_sub_module_type_by_scene/1,
    update_guild_race_rank/1                %% 更新社团竞榜排名
    ]).

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

%% 怪物进程调用
-export([
	boss_born_callback/3				%% 怪物出生回调
	,boss_hurt_callback/3				%% 怪物伤害回调
	,boss_die_callback/5				%% 怪物死亡回调
	,mon_proc_boss_hurt_info/3
	,mon_proc_role_revive/7				%% 复活检测
	,restat_when_hurt_change/1			%% 重新统计仇恨伤害
	]).

%% 人物进程调用
-export([
    role_enter_home_boss/5
	% ,role_boss_die_handle/3
	,role_notice_mon_info/5
	,add_mon_drop_log/2
    ,role_proc_settlement/6
	]).

-export([
    guild_proc_get_guild_info/3
    ,guild_proc_update_notice/2
    ,rank_proc_sync_guild_rank/2]).

-export([
    gm_update_guild_home_boss/0
    ]).

-compile(export_all).

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

%% ------------------------------------------------------------------------------

%% 获取boss信息
get_deserted_boss_info(SubModule, [RoleId, Guild, Sid, Level]) ->
	svr_cast(SubModule, {get_deserted_boss_info, RoleId, Guild, Sid, Level}).

%% 队伍信息变更
team_change(SubModule, [RoleId, Guild, Scene, TeamId, TeamLeaderName]) ->
    svr_cast(SubModule, {'team_flag', RoleId, Guild, Scene, TeamId, TeamLeaderName}).

%% 新增boss掉落拾取日志
add_mon_drop_log(SubModule, [RoleId, Guild, Name, Scene, MonId, DropReward]) ->
    svr_cast(SubModule, {'add_mon_drop_log', RoleId, Guild, Name, Scene, MonId, DropReward}).

enter_home_boss(SubModule, Guild, RoleId, BossId, {SceneId, X, Y}, Cost) ->
    svr_cast(SubModule, {'enter_home_boss', Guild, RoleId, BossId, {SceneId, X, Y}, Cost}).

update_guild_race_rank(GuildRaceInfo) ->
    svr_cast(?MOD_HOME_BOSS_GUILD, {'update_guild_race_rank', GuildRaceInfo}).

get_top_guild_info(Sid, RoleId, Guild) ->
    svr_cast(?MOD_HOME_BOSS_GUILD, {'get_top_guild_info', Sid, RoleId, Guild}).

gm_update_guild_home_boss() ->
    svr_cast(?MOD_HOME_BOSS_GUILD, {'gm_update_guild_home_boss'}),
    ok.

%% -------------------------------------------------------------------------------

%% 复活
revive(SubModule, Guild, BossId, RoleId, Scene, ScenePool, CopyId, X, Y) ->
	svr_cast_mon(SubModule, Guild, BossId, {'mod', ?MODULE, mon_proc_role_revive, [RoleId, Scene, ScenePool, CopyId, X, Y]}).

%% 获取BOSS伤害排名
get_boss_hurt_info(SubModule, Guild, Sid, BossId) ->
    svr_cast_mon(SubModule, Guild, BossId, {'mod', ?MODULE, mon_proc_boss_hurt_info, [SubModule, Sid]}).

%% --------------------------------------------------------------------------------

%% 游戏服给公共管理进程发消息
svr_cast(Msg) ->
    svr_cast(?MOD_HOME_BOSS_NORMAL, Msg).

-spec svr_cast(SubModule, Msg) -> Ret when
    SubModule :: ?MOD_HOME_BOSS_NORMAL|?MOD_HOME_BOSS_GUILD,
    Msg :: tuple(),
    Ret :: term().
svr_cast(SubModule, Msg) ->
    gen_server:cast(home_boss_proc_name(SubModule), Msg).

svr_call(SubModule, Msg) ->
    gen_server:call(home_boss_proc_name(SubModule), Msg).

%% 游戏服给怪物进程发消息
-spec svr_cast_mon(SubModule, Guild, BossId, Msg) -> Ret when
    SubModule :: ?MOD_HOME_BOSS_NORMAL | ?MOD_HOME_BOSS_GUILD,
    Guild :: integer(),
    BossId :: integer(),
    Msg :: tuple(),
    Ret :: term().
svr_cast_mon(SubModule, Guild, BossId, Msg) ->
    svr_cast(SubModule, {cast_mon, Guild, BossId, Msg}).


home_boss_proc_name(SubModule) ->
    list_to_atom(lists:concat(["home_boss", "_", SubModule])).

get_home_boss_proc(SubModule) ->
    erlang:whereis(home_boss_proc_name(SubModule)).

%% -----------------------------------------------------------------------------------
-spec init(list()) ->
    {ok, State :: #home_boss_state{}} | {ok, State :: #home_boss_state{}, timeout() | 
    hibernate | {continue, term()}} | {stop, Reason :: term()} | ignore.
init([SubModule|_]) ->
    Ref = erlang:send_after(?DELAY_TIME, self(),  {init, SubModule}),
    Map = maps:put(?WORKER_INIT, Ref, #{}),
    {ok, #home_boss_state{sub_module = SubModule, map = Map}}.

handle_call(Request, From, State) ->
    try
        do_handle_call(Request, From, State)
    catch ?EXCEPTION(_ErrorClass, _Error, StackTrace) ->
        ?ERR("home_boss_state handle_call Request:~w, Error:~w~n~p", [Request, _Error, ?GET_STACK(StackTrace)]),
        {reply, error, State}
    end.

-spec handle_cast(Msg, State) ->
    {noreply, State}
    | {stop, Reason, State} when
    Msg      :: term(),
    Reason   :: term(),
    State    :: #home_boss_state{}.
handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        NewState = #home_boss_state{} ->
            {noreply, NewState};
        {noreply, NewState} ->
            {noreply, NewState};
        ok ->
            {noreply, State};
        skip ->
            {noreply, State};
        {stop, _Reason, NewState} ->
            _Reason =/= normal andalso ?ERR("home_boss_state stop reason ~n ~p", [_Reason]),
            {stop, _Reason, NewState};
        Reason ->
            ?ERR("home_boss_state handle cast msg ~n ~p ~n error reason ~n ~p", [Msg, Reason]),
            {noreply, State}
    end.

-spec handle_info(Msg, State) ->
    {noreply, State}
    | {stop, Reason, State} when
    Msg :: term(),
    Reason :: term(),
    State :: #home_boss_state{}.
handle_info(Msg, State) ->
    case catch do_handle_info(Msg, State) of
        NewState = #home_boss_state{} ->
            {noreply, NewState};
        {noreply, NewState} ->
            {noreply, NewState};
        ok ->
            {noreply, State};
        skip ->
            {noreply, State};
        {stop, _Reason, NewState} ->
            _Reason =/= normal andalso ?ERR("home_boss_state process stop reason:~n ~p", [_Reason]),
            {stop, _Reason, NewState};
        _Reason ->
            ?ERR("home_boss_state process msg: ~n ~p ~n reason: ~n ~p", [Msg, _Reason]),
            {noreply, State}
    end.

terminate(_Reason, State) ->
    #home_boss_state{sub_module = SubModule, guild_boss_pids = GuildBossPids} = State,
    if _Reason == normal ->
            skip;
        true ->
            SceneIds = get_sub_module_scene(SubModule),
            maps:map(fun(_GuildId, {_, ScenePool}) ->
                [begin
                    mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, lib_scene, change_default_scene, [[]]),
                    mod_scene_agent:close_scene(Scene, ScenePool)
                end || Scene <- SceneIds]
            end, GuildBossPids)
    end,
    ok.

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

do_handle_call(_Request, _From, _State) ->
    {reply, ok, _State}.

do_handle_cast({cast_mon, Guild, BossId, Msg}, State) ->
	#home_boss_state{sub_module = SubModule, boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
    {MonId, MonPid} = get_guild_boss_mgr_pid(SubModule, Guild, BossId, BossInfos, GuildBossPids),
    case is_pid(MonPid) andalso misc:is_process_alive(MonPid) of
        true ->
            mon_mgr:send(MonPid, MonId, Msg);
        _A ->
            ?INFO_TTY("cast home boss error ~p", [_A]),
            skip
    end,
	ok;

do_handle_cast({boss_born, SubModule, RankIndex, Guild, BossId, MonMgrPid, MonId, ScenePool}, State) ->
	#home_boss_state{boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
    Now = utime:unixtime(),
    case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} ->
            case lists:keyfind(BossId, #home_boss.boss_id, SubBossInfos) of
                Boss = #home_boss{ref = Ref} ->
                    util:cancel_timer(Ref),
                    NewBoss = Boss#home_boss{
                        boss_pid = MonMgrPid, mon_id = MonId, born_time = Now,
                        pool_id = ScenePool, reborn_time = 0, ref = undefined
                    };
                _ ->
                    NewBoss = #home_boss{
                        boss_pid = MonMgrPid, mon_id = MonId, 
                        born_time = Now, reborn_time = 0, pool_id = ScenePool,
                        ref = undefined, guild = Guild
                    }
            end;
        _ ->
            SubBossInfos = [],
            NewBoss = #home_boss{
                boss_pid = MonMgrPid, mon_id = MonId, born_time = Now,
                reborn_time = 0, pool_id = ScenePool, ref = undefined,
                guild = Guild
            }
    end,
    NewSubBossInfos = lists:keystore(BossId, #home_boss.boss_id, SubBossInfos, NewBoss),
    NewBossInfos = lists:keystore({SubModule, RankIndex}, 1, BossInfos, {{SubModule, RankIndex}, NewSubBossInfos}),
    GuildBossPids1 =
    case maps:get(Guild, GuildBossPids, false) of
        {_RankIndex1, _} ->
            GuildBossPids;
        _ ->
            maps:put(Guild, {RankIndex, ScenePool}, GuildBossPids)
    end,
    State1 = State#home_boss_state{boss_infos = NewBossInfos, guild_boss_pids = GuildBossPids1},
    {noreply, State1};

do_handle_cast({boss_die, _RankIndex, _, BossId, BornTime, KillerName, Scene, ScenePool}, State) ->
	#home_boss_state{sub_module = SubModule, boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
    case get_guild_info_by_scene(ScenePool, GuildBossPids) of
        {_, RankIndex1} ->
            State1 =
            case lists:keyfind({SubModule, RankIndex1}, 1, BossInfos) of
                {_, SubBossInfos} ->
                    case lists:keyfind(BossId, #home_boss.boss_id, SubBossInfos) of
                        BossInfo = #home_boss{ref = OldRef, guild = Guild, pool_id = PoolId} ->
                            Now = utime:unixtime(),
                            OpenDay = util:get_open_day(),
                            db:execute(?SQL_SAVE_ONE_HOME_BOSS, [SubModule, RankIndex1, BossId, Guild, BornTime, Now, KillerName]),
                            #base_home_boss{level = Level, reborn_time = RebornTimeL, born_pos = {RebornX, RebornY}} = data_home_boss:get_boss_info(SubModule, BossId),
                            RebornTime = get_reborn_time(OpenDay, RebornTimeL),
                            % RebornTime = 30, 
                            NextTime   = Now + RebornTime,
                            Ref = util:send_after(OldRef, RebornTime*1000, self(), {create_home_boss, RankIndex1, PoolId, BossId, RebornX, RebornY}),
                            BossInfo1 = BossInfo#home_boss{ref = Ref, born_time = 0, reborn_time = NextTime, dead_time = Now, killer = KillerName},
                            SubBossInfos1 = lists:keystore(BossId, #home_boss.boss_id, SubBossInfos, BossInfo1),
                            BossInfos1    = lists:keystore({SubModule, RankIndex1}, 1, BossInfos, {{SubModule, RankIndex1}, SubBossInfos1}),
                            {MonL, GuildId} = pack_mon_info(SubModule, Level, SubBossInfos1),
                            mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, ?MODULE, role_notice_mon_info, [Level, SubModule, GuildId, MonL]),
                            State#home_boss_state{boss_infos = BossInfos1};
                        _ ->
                            State
                    end;
                _ ->
                    State
            end,
            {noreply, State1};
        _ ->
            {noreply, State}
    end;

do_handle_cast({get_deserted_boss_info, _RoleId, Guild, Sid, Level}, State) ->
	#home_boss_state{sub_module = SubModule, boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
	MonIds = data_home_boss:get_all_boss(SubModule),
    {RankIndex, _} = maps:get(Guild, GuildBossPids, {0, 0}),
    case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} -> ok;
        _ -> SubBossInfos = []
    end,
	MonInfo = lists:foldl(fun(MonId, Acc) ->
		case data_home_boss:get_boss_info(SubModule, MonId) of
			#base_home_boss{level = Level} ->
				case lists:keyfind(MonId, #home_boss.boss_id, SubBossInfos) of
					#home_boss{reborn_time = RebornTime, killer = Killer} ->
                        [{MonId, RebornTime, Killer}|Acc];
					_ -> Acc
				end;
			_ -> Acc
		end
	end, [], MonIds),
    % ?ERR("~p ~p ~p ~p", [SubModule, Level, Guild, MonInfo]),
 	{ok, BinData} = pt_462:write(46201, [SubModule, Level, Guild, MonInfo]),
 	lib_server_send:send_to_sid(Sid, BinData),
	ok;

do_handle_cast({'team_flag', _RoleId, Guild, Scene, _TeamId, _TeamLeaderName}, State) ->
	#home_boss_state{sub_module = SubModule, boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
    {RankIndex, _} = maps:get(Guild, GuildBossPids, {0, 0}),
    case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} ->
        	lists:map(fun(#home_boss{boss_id = BossId, mon_id = MonId, boss_pid = BossMgrPid}) ->
        		case data_home_boss:get_boss_info(SubModule, BossId) of
        			#base_home_boss{level = Level} ->
                        SceneRet =
        				case data_home_boss:get_home_boss_level(SubModule, Level) of
        					#base_home_boss_level{scene = BossScene} ->
                                BossScene == Scene;
                            _ -> false
                        end,
                        if
                            SceneRet ->
        						case misc:is_process_alive(BossMgrPid) of
        							true -> mon_mgr:send(BossMgrPid, MonId, {'team_flag', _RoleId, _TeamId, _TeamLeaderName});
        							_ 	 -> skip
        						end;
                            true -> skip
                        end;
        			_ -> skip
        		end
        	end, SubBossInfos);
        _ ->
            skip
    end,
	ok;

do_handle_cast({'add_mon_drop_log', RoleId, Guild, Name, Scene, MonId, DropReward}, State) ->
	#home_boss_state{sub_module = SubModule, boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
    {RankIndex, _} = maps:get(Guild, GuildBossPids, {0, 0}),
	case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} ->
            case lists:keyfind(MonId, #home_boss.boss_id, SubBossInfos) of
                #home_boss{} ->
        			case DropReward of
        				[{_, GoodsId, _DropNum}|_] ->
        					case data_goods_type:get(GoodsId) of
        						#ets_goods_type{color = Color} when Color >= ?ORANGE ->
        							add_log([Name, RoleId, Scene, MonId, GoodsId, utime:unixtime()]);
        						_ ->
        							skip
        					end;
        				_ -> skip
        			end;
                _ -> skip
            end;
		_ -> skip
	end,
	ok;

do_handle_cast({'enter_home_boss', Guild, RoleId, BossId, {SceneId, X, Y}, Cost}, State) ->
    #home_boss_state{sub_module = SubModule, boss_infos = BossInfos, guild_boss_pids = GuildBossPids} = State,
    {RankIndex, ScenePool} = maps:get(Guild, GuildBossPids, {0, 0}),
    case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} ->
            case lists:keyfind(BossId, #home_boss.boss_id, SubBossInfos) of
                #home_boss{} ->
                    case local_boss_api:check_role_num_limit(SceneId, ScenePool, 50) of
                        true ->
                            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_enter_home_boss, [{SceneId, ScenePool, 0, X, Y}, SubModule, BossId, Cost]);
                        {false, ErrorCode} ->
                            lib_server_send:send_to_uid(RoleId, pt_462, 46204, [ErrorCode, SubModule, BossId])
                    end;
                _ ->
                    lib_server_send:send_to_uid(RoleId, pt_462, 46204, [?FAIL, SubModule, BossId])
            end;
        _ ->
            lib_server_send:send_to_uid(RoleId, pt_462, 46204, [?ERRCODE(err462_not_top_3), SubModule, BossId])
    end,
    {noreply, State};

% #{guild => {rank_index, scene_pool}} 排名 => {社团, 分线}
do_handle_cast({'update_guild_race_rank', GuildRaceInfo}, State) ->
    #home_boss_state{boss_infos = BossInfos, sub_module = SubModule, guild_boss_pids = GuildBossPids} = State,
    % ?ERR("new guild rank ~p old guild ~p", [GuildRaceInfo, GuildBossPids]),
    {ok, BinData} = pt_462:write(46206, []),
    SceneIds = get_sub_module_scene(SubModule),
    {GuildBossPids1, GuildPoolMap} = update_guild_scene_pool(GuildRaceInfo, GuildBossPids, SceneIds, BinData),
    BossInfos1 = update_guild_boss_info(SubModule, GuildRaceInfo, BossInfos, GuildBossPids, GuildBossPids1, GuildPoolMap),
    % ?ERR("new guild ~p", [GuildBossPids1]),
    State1 = State#home_boss_state{boss_infos = BossInfos1, guild_boss_pids = GuildBossPids1},
    {noreply, State1};

do_handle_cast({'get_top_guild_info', Sid, RoleId, _Guild}, State) ->
    #home_boss_state{guild_boss_pids = GuildBossPids} = State,
    GuildIds = maps:fold(fun(GuildId, {_RankIndex, _ScenePool}, Acc) -> [GuildId|Acc] end, [], GuildBossPids),
    mod_guild:apply_cast(?MODULE, guild_proc_get_guild_info, [Sid, RoleId, GuildIds]),
    {noreply, State};

do_handle_cast({'gm_update_guild_home_boss'}, State) ->
    #home_boss_state{sub_module = SubModule, guild_boss_pids = GuildBossPids, boss_infos = BossInfos} = State,
    db:execute(<<"DELETE FROM home_boss_status WHERE sub_module = ~p">>, [SubModule]),
    BossInfos1 = maps:fold(fun(GuildId, {RankIndex, ScenePool}, AccBossInfos) -> 
        case lists:keyfind({SubModule, RankIndex}, 1, AccBossInfos) of
            {_, SubBossInfos} ->
                SubBossInfos1 =
                lists:map(fun(BossInfo) ->
                    #home_boss{boss_id = BossId, mon_id = MonId, born_time = BornTime, guild = _Guild, ref = BossRef, boss_pid = BossMgrPid, pool_id = OldPoolId} = BossInfo,
                    if 
                        OldPoolId == ScenePool andalso BornTime =/= 0 -> BossInfo#home_boss{guild = GuildId};
                        true -> %% OldPoolId =/= ScenePool orelse BornTime == 0
                            %% 销毁错误分线的boss
                            if is_reference(BossRef) ->
                                    Ret = erlang:read_timer(BossRef),
                                    if is_integer(Ret) andalso Ret > 0 -> erlang:cancel_timer(Ret);
                                        true -> skip
                                    end;
                                true -> skip
                            end,
                            case misc:is_process_alive(BossMgrPid) of
                                true -> mon_mgr:send(BossMgrPid, MonId, {'stop', 1});
                                _    -> skip
                            end,
                            %% 创建正常boss
                            case data_home_boss:get_boss_info(SubModule, BossId) of
                                #base_home_boss{born_pos = {RebornX, RebornY}} ->
                                    create_home_boss([SubModule, RankIndex, GuildId, ScenePool, BossId, RebornX, RebornY, utime:unixtime()]);
                                _ -> skip
                            end,
                            BossInfo#home_boss{pool_id = ScenePool, guild = GuildId}
                    end
                end, SubBossInfos),
                AccBossInfos1 = lists:keystore({SubModule, RankIndex}, 1, AccBossInfos, {{SubModule, RankIndex}, SubBossInfos1}),
                AccBossInfos1;
            _ ->
                AccBossInfos
        end
    end, BossInfos, GuildBossPids),
    NewState = State#home_boss_state{boss_infos = BossInfos1},
    {noreply, NewState};

do_handle_cast(_Msg, _State) ->
	?ERR("unkown cast msg ~p", [_Msg]),
	ok.

do_handle_info({init, SubModule}, State) ->
    #home_boss_state{map = Map} = State,
	MonList = [list_to_tuple(Mon) || Mon <- db:get_all(?SQL_GET_HOME_BOSS, [SubModule])],
	Now     = utime:unixtime(),
    OpenDay = util:get_open_day(),
    BossInfos = init_home_boss_data(SubModule, MonList, Now, OpenDay),
    if SubModule == ?MOD_HOME_BOSS_GUILD ->
            Ref = erlang:send_after(?DELAY_TIME, self(), {timer_sync_guild_rank}),
            Map1 = maps:put(?TIMER_SYNC, Ref, Map);
        true ->
            Map1 = Map
    end,
    State1 = State#home_boss_state{map = Map1, sub_module = SubModule, boss_infos = BossInfos},
	{noreply, State1};


do_handle_info({create_home_boss, _RankIndex, ScenePool, BossId, RebornX, RebornY}, State) ->
    #home_boss_state{sub_module = SubModule, guild_boss_pids = GuildBossPids} = State,
    case get_guild_info_by_scene(ScenePool, GuildBossPids) of
        {Guild, RankIndex1} ->
            % ?ERR("create boss ~p ~p ~p ~p ~p", [_RankIndex, RankIndex1, ScenePool, BossId, GuildBossPids]),
	       create_home_boss([SubModule, RankIndex1, Guild, ScenePool, BossId, RebornX, RebornY, utime:unixtime()]),
           #mon{name = BossName} = data_mon:get(BossId),
           lib_chat:send_TV({all}, ?MOD_HOME_BOSS, 2, [BossName, BossId]);
        _A ->
            skip
    end,
    {noreply, State};

do_handle_info({timer_sync_guild_rank}, State) ->
    #home_boss_state{map = Map} = State,
    Ref = util:send_after(maps:get(?TIMER_SYNC, Map, undefined), ?GUILD_UPDATE_INTERVAL, self(), {timer_sync_guild_rank}),
    Map1 = maps:put(?TIMER_SYNC, Ref, Map),
    mod_common_rank:apply_cast(?MODULE, rank_proc_sync_guild_rank, [self()]),
    State1 = State#home_boss_state{map = Map1},
    {noreply, State1};

do_handle_info(_Msg, _State) ->
	?ERR("unkown info msg ~p", [_Msg]),
	ok.

%% -------------------- 内部接口 --------------------------

%% boss怪创建
create_home_boss([SubModule, RankIndex, Guild, ScenePool, BossId, X, Y, Now|_]) ->
    case data_home_boss:get_boss_info(SubModule, BossId) of
        #base_home_boss{level = Level} ->
            case data_home_boss:get_home_boss_level(SubModule, Level) of
                #base_home_boss_level{scene = Scene} ->
                    Args = get_mon_args(SubModule, RankIndex, Guild, BossId, Now),
                    lib_mon:async_create_mon(BossId, Scene, ScenePool, X, Y, 1, 0, 1, Args);
                _ -> skip
            end;
        _ -> skip
    end.

%% 创怪参数
get_mon_args(SubModule, RankIndex, Guild, BossId, BornTime) ->
    case data_home_boss:get_boss_info(SubModule, BossId) of
        #base_home_boss{} ->
            [
                {born_handler, {?MODULE, boss_born_callback, [SubModule, RankIndex, Guild]}},
                {hp_change_handler, {?MODULE, boss_hurt_callback, [SubModule, RankIndex, Guild]}},
                {die_handler, {?MODULE, boss_die_callback, [SubModule, RankIndex, Guild, BornTime]}}
                % {origin, ?DROP_ORIGIN_DESERTED_BOSS}
            ];
        _ ->
            []
    end.

 stat_hurt_list(KList) ->
 	NewKList = stat_hurt_list_do(KList, []),
 	F = fun({_, _, _, HurtA, _}, {_, _, _, HurtB, _}) -> HurtA > HurtB end,
 	lists:sort(F, NewKList).

 stat_hurt_list_do([], KList) -> KList;
 stat_hurt_list_do([Atter|Rest], KList) ->
 	#mon_atter{id = RoleId, team_id = TeamId, hurt = RoleHurt} = Atter,
    NewKList =
 	if
 		TeamId > 0 ->
 			case lists:keyfind(TeamId, 1, KList) of
 				{TeamId, 0, _, Hurt, TeamRoles} ->
 					lists:keystore(TeamId, 1, KList, {TeamId, 0, 0, round(RoleHurt+Hurt), [Atter|TeamRoles]});
 				_ ->
 					[{TeamId, 0, 0, RoleHurt, [Atter]}|KList]
 			end;
 		true ->
 			[{0, RoleId, 0, RoleHurt, [Atter]}|KList]
 	end,
 	stat_hurt_list_do(Rest, NewKList).

 pack_hurt_list(SubModule, BossId, BossHp, HurtL) ->
 	HurtList = [pack_hurt_info(HurtInfo)|| HurtInfo <- HurtL],
    {ok, BinData} = pt_462:write(46202, [SubModule, BossId, BossHp, HurtList]),
 	BinData.

 pack_hurt_info(HurtInfo) ->
 	case HurtInfo of
 		{TeamId, _, _SvrNum, Hurt, [#mon_atter{team_leader_name = TeamLeaderName}|_]} when TeamId > 0 ->
            {TeamId, 1, TeamLeaderName, Hurt};
 		{_, RoleId, _SvrNum, Hurt, [#mon_atter{name = RoleName}|_]} when RoleId > 0 ->
 			{RoleId, 0, RoleName, Hurt};
 		_ ->
 			{0, 0, <<>>, 0}
 	end.

 pack_mon_info(SubModule, Level, BossInfos) ->
  	{MonL, GuildId} = lists:foldl(fun(#home_boss{boss_id = BossId, guild = Guild, reborn_time = RebornTime, killer = Name}, {Acc, TempGuild}) ->
 		TempGuild1 = ?IF(Guild == 0, TempGuild, Guild),
        case data_home_boss:get_boss_info(SubModule, BossId) of
 			#base_home_boss{level = Level} ->
 				{[{BossId, RebornTime, Name}|Acc], TempGuild1};
 			_ ->
 				{Acc, TempGuild1}
 		end
 	end, {[], 0}, BossInfos),
 	{MonL, GuildId}.

role_settlement(SubModule, _Rank, BossId, MaxHurtRoles) ->
    TeamLen = length([1 || #mon_atter{team_id = TeamId} <- MaxHurtRoles, TeamId =/= 0]),
    case data_mon:get(BossId) of
        #mon{hp_lim = HpLim} -> ok;
        _ -> HpLim = 100
    end,
    [begin 
        HurtPercent = round(Hurt/HpLim*100),
        role_settlement_do(RoleId, [SubModule, BossId, TeamLen, HurtPercent, 1])
    end || #mon_atter{id = RoleId, hurt = Hurt} <- MaxHurtRoles],
    ok.

role_settlement_do(RoleId, [SubModule, BossId, TeamLen, HurtPercent, Rank]) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_proc_settlement, [SubModule, BossId, TeamLen, HurtPercent, Rank]),
    ok.

role_proc_settlement(Player, SubModule, BossId, TeamLen, HurtPercent, Rank) ->
    #player_status{local_boss = #status_local_boss{ta_data = TAData}} = Player,
    %% 先统计每日击杀次数
    lib_daily:increment(Player#player_status.id, ?MOD_HOME_BOSS, ?COUNT_HOME_BOSS_KILL),
    Now = utime:unixtime(),
    case data_home_boss:get_boss_info(SubModule, BossId) of
        #base_home_boss{grade = BossSeries, level = Floor} -> ok;
        _ -> BossSeries = 0, Floor = 0
    end,
    case data_mon:get(BossId) of
        #mon{lv = BossLv} -> ok;
        _ -> BossLv = 0
    end,
    BossTAData  = maps:get(?MON_HOME_BOSS, TAData, #{}),
    ReviveTimes = maps:get(?REVIVE_TIME, BossTAData, 0),
    EnterTime   = maps:get(?ENTER_TIME, BossTAData, 0),
    UseTime = max(0, Now - EnterTime),
    ta_agent_fire:home_boss_belong(Player, [BossId, BossLv, BossSeries, TeamLen, SubModule, Floor, ReviveTimes, HurtPercent, Rank, UseTime]),
    Player1 = local_boss_api:kill_boss_refresh_ta_data(Player, ?MON_HOME_BOSS, Now),
    Player2 = equipment_logic:kill_home_boss(Player1),
    {ok, Player2}.


add_log([RoleName, _RoleId, Scene, BossId, GoodsId, Time|_]) ->
    case data_mon:get(BossId) of
        #mon{boss = BossType} -> ok;
        _ -> BossType = 0
    end,
    Log = #boss_drop_log{
        name = RoleName, scene = Scene,
        boss = BossId, boss_type = BossType, goods_id = GoodsId, time = Time
    },
    reward_boss_mgr:add_reward_boss_drop_log(Log),
    ok.

get_reborn_time(OpenDay, RebornList) ->
	case lists:keyfind(OpenDay, 1, RebornList) of
		{_, RebornTime} -> RebornTime;
		_ ->
			case lists:reverse(lists:keysort(1, RebornList)) of
				[{_, RebornTime}|_] -> RebornTime;
				_ -> 300
			end
	end.

init_home_boss_data(SubModule, MonList, Now, OpenDay) ->
    init_home_boss_data(SubModule, MonList, Now, OpenDay, []).

init_home_boss_data(SubModule, [], Now, _, BossInfos) ->
    AllBoss = data_home_boss:get_all_boss(SubModule),
    if SubModule == ?MOD_HOME_BOSS_NORMAL ->
            lists:foldl(fun(BossId, AccBossInfos) ->
                case AccBossInfos of
                    [{{SubModule, RankIndex}, AccSubBossInfos}|_] -> ok;
                    _ -> RankIndex = 0, AccSubBossInfos = []
                end,
                case lists:keyfind(BossId, #home_boss.boss_id, AccSubBossInfos) of
                    #home_boss{} -> AccBossInfos;
                    _ ->
                        #base_home_boss{born_pos = {X, Y}} = data_home_boss:get_boss_info(SubModule, BossId),
                        create_home_boss([SubModule, RankIndex, 0, 0, BossId, X, Y, Now]),
                        OneBoss = #home_boss{
                            boss_id  = BossId, pos = {X, Y}
                        },
                        [{{SubModule, RankIndex}, [OneBoss|AccSubBossInfos]}]
                end
            end, BossInfos, AllBoss);
        true ->
            BossInfos
    end;
init_home_boss_data(SubModule, [H|Rest], Now, OpenDay, BossInfos) ->
    {RankIndex, BossId, Guild, _BornTime, DeadTime, Killer} = H,
    #base_home_boss{reborn_time = RebornList, born_pos = {X, Y}} = data_home_boss:get_boss_info(SubModule, BossId),
    if DeadTime =/= 0 ->
            RebornTime = get_reborn_time(OpenDay, RebornList),
            NextTime = DeadTime + RebornTime,
            if 
                NextTime > Now ->
                    PoolId = Guild,
                    Ref = erlang:send_after((NextTime - Now)*1000, self(), {create_home_boss, RankIndex, PoolId, BossId, X, Y}),
                    NextTime1 = NextTime;
                true ->
                    create_home_boss([SubModule, RankIndex, Guild, Guild, BossId, X, Y, Now]),
                    Ref = undefined, NextTime1 = 0
            end;
        true ->
            create_home_boss([SubModule, RankIndex, Guild, Guild, BossId, X, Y, Now]),
            Ref = undefined, NextTime1 = 0
    end,
    OneBoss =
    #home_boss{
        boss_id  = BossId, pos = {X, Y}, ref = Ref,
        killer   = Killer, dead_time = DeadTime,
        reborn_time = NextTime1, guild = Guild
    },
    BossInfos1 =
    case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} ->
            SubBossInfos1 = [OneBoss|SubBossInfos],
            lists:keystore({SubModule, RankIndex}, 1, BossInfos, {{SubModule, RankIndex}, SubBossInfos1});
        _ ->
            lists:keystore({SubModule, RankIndex}, 1, BossInfos, {{SubModule, RankIndex}, [OneBoss]})
    end,
    init_home_boss_data(SubModule, Rest, Now, OpenDay, BossInfos1).

%% 修改怪物的社团信息
update_guild_race_rank_logic(SubBossInfos, SubModule, RankIndex, Guildx, GuildScenePool) ->
    % db:execute(?SQL_UPDATE_ONE_HOME_BOSS, [Guildx, SubModule, RankIndex]),
    AllBoss = data_home_boss:get_all_boss(SubModule),
    % ?ERR("~p ~p ~p", [Guild, RankIndex, length(AllBoss)]),
    % ?ERR("~p ~p", [RankIndex, Guildx]),
    Now = utime:unixtime(),
    BossInfos1 =
    lists:foldl(fun(BossId, AccBossInfos) ->
        case lists:keyfind(BossId, #home_boss.boss_id, AccBossInfos) of
            #home_boss{guild = Guildx} ->
                AccBossInfos;
            HomeBoss = #home_boss{} ->
                lists:keystore(BossId, #home_boss.boss_id, AccBossInfos, HomeBoss#home_boss{guild = Guildx});
            _A -> 
                #base_home_boss{born_pos = {X, Y}} = data_home_boss:get_boss_info(SubModule, BossId),
                % ?ERR("update guild create new boss ~p ~p ~p ~p", [_A, RankIndex, Guildx, GuildScenePool]),
                create_home_boss([SubModule, RankIndex, Guildx, GuildScenePool, BossId, X, Y, Now]),
                OneBoss = #home_boss{boss_id = BossId, pos = {X, Y}, guild = Guildx},
                [OneBoss|AccBossInfos]
        end
    end, SubBossInfos, AllBoss),
    BossInfos1.

%% 新增社团之家怪物
new_guild_boss_info(SubModule, RankIndex, Guild, GuildScenePool) ->
    AllBoss = data_home_boss:get_all_boss(SubModule),
    % ?ERR("~p ~p ~p", [Guild, RankIndex, length(AllBoss)]),
    Now = utime:unixtime(),
    lists:foldl(fun(BossId, AccBossInfos) -> 
        #base_home_boss{born_pos = {X, Y}} = data_home_boss:get_boss_info(SubModule, BossId),
        create_home_boss([SubModule, RankIndex, Guild, GuildScenePool, BossId, X, Y, Now]),
        OneBoss = #home_boss{boss_id = BossId, pos = {X, Y}, guild = Guild},
        [OneBoss|AccBossInfos]
    end, [], AllBoss).

get_guild_boss_mgr_pid(SubModule, Guild, BossId, BossInfos, GuildBossPids) ->
    case maps:get(Guild, GuildBossPids, false) of
        {RankIndex, _} ->
            ok;
        _ ->
            RankIndex = false
    end,
    case lists:keyfind({SubModule, RankIndex}, 1, BossInfos) of
        {_, SubBossInfos} ->
            case lists:keyfind(BossId, #home_boss.boss_id, SubBossInfos) of
                #home_boss{mon_id = MonId, boss_pid = MonPid} -> ok;
                _ -> MonId = 0, MonPid = undefined
            end;
        _ ->
            MonId = 0, MonPid = undefined
    end,
    {MonId, MonPid}.

get_guild_scene_info_by_rank_index(RankIndex, GuildBossPids) ->
    GuildBossPids1 = maps:to_list(GuildBossPids),
    case lists:filter(fun({_GuildIdx1, {RankIndex1, _ScenePoolx1}}) -> 
        RankIndex == RankIndex1
     end, GuildBossPids1) of
        [{Guild, {_, ScenePool}}|_] ->
            {Guild, ScenePool};
        _A ->
            false
    end.

get_guild_info_by_scene(ScenePool, GuildBossPids) ->
    GuildBossPids1 = maps:to_list(GuildBossPids),
    case lists:filter(fun({_GuildIdx1, {_RankIndex1, ScenePoolx1}}) -> 
        ScenePool == ScenePoolx1
     end, GuildBossPids1) of
        [{Guild, {RankIndex, _}}|_] ->
            {Guild, RankIndex};
        _A ->
            false
    end.

update_guild_scene_pool(GuildRaceInfo, GuildBossPids, SceneIds, BinData) ->
    {AddGuild, DeleteGuild} = calc_change_guild(GuildRaceInfo, GuildBossPids),
    % ?ERR("~p ~p", [AddGuild, DeleteGuild]),
    {NewGuildBossPids, NewChange, GuildPoolMap} = update_guild_scene_pool_logic(AddGuild, DeleteGuild, GuildRaceInfo, GuildBossPids),
    % ?ERR("~p ~p", [NewGuildBossPids, NewChange]),
    %% 踢人
    lists:map(fun(DeleteGuildx) -> 
        case maps:get(DeleteGuildx, GuildBossPids, false) of
            {_, DeleteGuildScenePool} ->
                [lib_server_send:send_to_scene(Scenex, DeleteGuildScenePool, 0, BinData) || Scenex <- SceneIds],
                spawn_link(fun() -> 
                    timer:sleep(10000),
                    [mod_scene_agent:apply_cast_scene_user(Scene, DeleteGuildScenePool, 0, lib_scene, change_default_scene, [[]]) || Scene <- SceneIds]                   
                end);
            _ -> skip
        end
    end, DeleteGuild),
    update_guild_notice(NewChange, GuildBossPids, NewGuildBossPids),
    {NewGuildBossPids, GuildPoolMap}.

update_guild_boss_info(SubModule, GuildRaceInfo, BossInfos, GuildBossPids, GuildBossPids1, GuildPoolMap) ->
    BossInfos1 = maps:fold(fun(NewGuild, OldGuild, AccBossInfos) -> 
        {_, RankIndex1} = lists:keyfind(NewGuild, 1, GuildRaceInfo),
        case get_guild_scene_info_by_rank_index(RankIndex1, GuildBossPids1) of
            {_, GuildScenePool} -> ok;
            _ -> GuildScenePool = NewGuild
        end,
        if 
            OldGuild == 0 -> %% 新社团
                SubBossInfos = new_guild_boss_info(SubModule, RankIndex1, NewGuild, GuildScenePool),
                lists:keystore({SubModule, RankIndex1}, 1, AccBossInfos, {{SubModule, RankIndex1}, SubBossInfos});
            NewGuild == OldGuild -> %% 可能只有排名变更
                case maps:get(OldGuild, GuildBossPids, false) of
                    {OldRank, _} ->
                        case lists:keyfind({SubModule, OldRank}, 1, BossInfos) of
                            {_, SubBossInfos} ->
                                SubBossInfos1 = update_guild_race_rank_logic(SubBossInfos, SubModule, RankIndex1, NewGuild, GuildScenePool),
                                lists:keystore({SubModule, RankIndex1}, 1, AccBossInfos, {{SubModule, RankIndex1}, SubBossInfos1});
                            _ -> %% 有问题
                                ?ERR("guild rank error ~p ~p", [OldGuild, OldRank]),
                                AccBossInfos
                        end;
                    _ -> %% 有问题
                        AccBossInfos
                end;
            true -> %% 新旧社团切换
                case maps:get(OldGuild, GuildBossPids, false) of
                    {OldRank, _} ->
                        case lists:keyfind({SubModule, OldRank}, 1, BossInfos) of
                            {_, SubBossInfos} ->
                                SubBossInfos1 = update_guild_race_rank_logic(SubBossInfos, SubModule, RankIndex1, NewGuild, GuildScenePool),
                                lists:keystore({SubModule, RankIndex1}, 1, AccBossInfos, {{SubModule, RankIndex1}, SubBossInfos1});
                            _ -> %% 有问题
                                AccBossInfos
                        end;
                    _ -> %% 有问题
                        AccBossInfos
                end                
        end
    end, [], GuildPoolMap),
    db_update_guild_boss_info(SubModule, BossInfos1),
    BossInfos1.

%% 计算本次新的社团和被顶掉的社团
calc_change_guild(GuildRaceInfo, GuildBossPids) ->
    TranGuildBossPids = [OldGuildx || {OldGuildx, {_, _}} <- maps:to_list(GuildBossPids)],
    AddGuild =
    lists:foldl(fun({Guild, _Rank}, Acc) -> 
        case lists:member(Guild, TranGuildBossPids) of
            true -> Acc;
            _    -> [Guild|Acc]
        end
    end, [], GuildRaceInfo),
    DeleteGuild =
    lists:foldl(fun(Guildx, Acc) -> 
        case lists:keymember(Guildx, 1, GuildRaceInfo) of
            true -> Acc;
            _    -> [Guildx|Acc]
        end
    end, [], TranGuildBossPids),
    {AddGuild, DeleteGuild}.

%% 更新社团排名及所处场景分线数据
update_guild_scene_pool_logic(AddGuild, DeleteGuild, GuildRaceInfo, GuildBossPids) ->
    GuildBossPids1 =
    lists:foldl(fun({Guild, NewRank}, Acc) -> 
        case maps:get(Guild, GuildBossPids, false) of
            {RankIndex, ScenePool} ->
                if NewRank == RankIndex -> maps:put(Guild, {RankIndex, ScenePool}, Acc);
                    true -> maps:put(Guild, {NewRank, ScenePool}, Acc)
                end;
            _ ->
                maps:put(Guild, {NewRank, Guild}, Acc)
        end
    end, #{}, GuildRaceInfo),
    {GuildBossPids2, _} =
    lists:foldl(fun(AddGuildx, {Acc1, AccDeleteGuild}) ->
        {RankIndex1, _ScenePool1} = maps:get(AddGuildx, GuildBossPids1), 
        case AccDeleteGuild of
            [DeleteGuildx|Rest] ->
                case maps:get(DeleteGuildx, GuildBossPids, false) of
                    {_, DeleteGuildScenePool} ->
                        Acc2 = maps:put(AddGuildx, {RankIndex1, DeleteGuildScenePool}, Acc1),
                        {Acc2, Rest};
                    _ ->
                        {Acc1, Rest}
                end;
            _ ->
                {Acc1, AccDeleteGuild}
        end
    end, {GuildBossPids1, DeleteGuild}, AddGuild),
    GuildBossPids3 =
    lists:foldl(fun(DeleteGuildx1, Acc3) -> 
        maps:remove(DeleteGuildx1, Acc3)
    end, GuildBossPids2, DeleteGuild),
    GuildPoolMap = calc_guild_pool_map(GuildBossPids3, GuildBossPids),
    % ?ERR("~p", [GuildPoolMap]),
    Change = check_scene_pool_update(GuildBossPids, GuildBossPids3),
    {GuildBossPids3, Change, GuildPoolMap}.

%% 新旧社团映射
calc_guild_pool_map(NewBossPids, OldBossPids) ->
    maps:fold(fun(Guild, {_RankIndex, ScenePool}, AccMap) ->
            case get_guild_info_by_scene(ScenePool, OldBossPids) of
                {OldGuild, _} ->
                    maps:put(Guild, OldGuild, AccMap);
                _ ->
                    maps:put(Guild, 0, AccMap)
            end
    end, #{}, NewBossPids).

db_update_guild_boss_info(SubModule, BossInfos) ->
    db:execute(<<"DELETE FROM home_boss_status WHERE sub_module = ~p">>, [SubModule]),
    DbBossData1 =
    lists:foldl(fun({{SubModule1, Rank}, SubBossInfos}, Acc) -> 
        FilterBossInfos = lists:filter(fun(#home_boss{dead_time = Time}) -> Time =/= 0 end, SubBossInfos),
        transformat(SubModule1, Rank, FilterBossInfos, Acc)
    end, [], BossInfos),
    if DbBossData1 =/= [] ->
            DataStrList = [util:fmt_bin(<<"(~p, ~p, ~p, ~p, ~p, ~p, '~ts')">>, [SubModule1, Rank, BossId, GuildId, BornTime, DeadTime, Killer]) || {SubModule1, Rank, BossId, GuildId, BornTime, DeadTime, Killer} <- DbBossData1],
            DataStrAll  = util:join_bitstring(DataStrList, <<",">>),
            SQL = util:fmt_bin(<<"REPLACE INTO home_boss_status (sub_module, rank_index, boss_id, guild, born_time, dead_time, killer) VALUES ~ts">>, [DataStrAll]),
            db:execute(SQL);
        true ->
            skip
    end.

transformat(_SubModule, _Rank, [], AccBossInfos) ->
    AccBossInfos;
transformat(SubModule, Rank, [#home_boss{
    boss_id   = BossId
    , killer    = Killer
    , dead_time = DeadTime
    , born_time = BornTime
    , guild = GuildId
    }|Rest], AccBossInfos) ->
    AccBossInfos1 = [{SubModule, Rank, BossId, GuildId, BornTime, DeadTime, Killer}|AccBossInfos],   
    transformat(SubModule, Rank, Rest, AccBossInfos1).

check_scene_pool_update(Old, New) ->
    SortOldKeys = lists:sort(maps:keys(Old)),
    SortNewKeys = lists:sort(maps:keys(New)),
    SortOldKeys =/= SortNewKeys.

%% ------------------ 怪物进程 ------------------------

%% 检测复活坐标与怪物距离
mon_proc_role_revive(MonState, RoleId, Scene, ScenePool, CopyId, X, Y) ->
	#ob_act{object = SceneObj, klist = KList, bl_who = BLWho, first_att = FirstAtt} = MonState,
	#scene_object{config_id = MonId, d_x = Dx, d_y = Dy, scene = MonSceneId, scene_pool_id = MonScenePool,
		copy_id = MonCopyId, tracing_distance = TraceDistance} = SceneObj,
	if
		MonSceneId == Scene andalso MonScenePool == ScenePool
		 andalso CopyId == MonCopyId ->
			case abs(Dx - X) =< TraceDistance andalso abs(Dy - Y) =< TraceDistance of
				true ->
					MonState;
				_ -> %% 复活已超追踪距离
					NewKList1 = lists:keydelete(RoleId, #mon_atter.id, KList),
					NewBLWho  = lists:keydelete(RoleId, #mon_atter.id, BLWho),
					NewFirstAtt =
					case FirstAtt of
						[] -> [];
						_  -> ?IF(FirstAtt#mon_atter.id == RoleId, [], FirstAtt)
					end,
					NewBLWho1 =
					case NewBLWho =/= BLWho of
						true ->
							mon_state_logic:update_belong_who(MonState, NewBLWho, NewKList1, NewFirstAtt);
						_ 	 -> BLWho
					end,
					NewSceneObj = mon_state_logic:recover_hp_no_att(NewBLWho1, NewKList1, SceneObj),
					%% 脱战通知
					lib_server_send:send_to_uid(RoleId, pt_462, 46203, [MonId]),
					NewMonState = MonState#ob_act{klist = NewKList1, bl_who = NewBLWho1, first_att = NewFirstAtt,
						object = NewSceneObj},
					case NewKList1 =/= KList of
						true -> restat_when_hurt_change(NewMonState);
						_ 	 -> NewMonState
					end
			end;
		true ->
			MonState
	end.

mon_proc_boss_hurt_info(MonState, SubModule, Sid) ->
	#ob_act{object = SceneObj, hurt_stat_list = HurtL} = MonState,
	#scene_object{config_id = BossId, battle_attr = #battle_attr{hp = Hp}} = SceneObj,
	BinData = pack_hurt_list(SubModule, BossId, Hp, HurtL),
	lib_server_send:send_to_sid(Sid, BinData),
	MonState.

%% 重新计算仇恨列表
restat_when_hurt_change(MonState) ->
	#ob_act{klist = KList, object = #scene_object{config_id = ConfigId, scene = Scene, battle_attr = #battle_attr{hp = Hp}}} = MonState,
	NewKList = stat_hurt_list(KList),
    SubModule = mod_sub_module_type_by_scene(Scene),
    BinData = pack_hurt_list(SubModule, ConfigId, Hp, NewKList),
    [lib_server_send:send_to_uid(AtterId, BinData) || #mon_atter{id = AtterId} <- KList],
	MonState#ob_act{hurt_stat_list = NewKList}.

%% ------------------------- 怪物回调 -------------------------------------

boss_born_callback(init, Minfo, [SubModule, RankIndex, Guild|_]) ->
    #scene_object{scene_pool_id = ScenePool, id = MonId, config_id = BossId} = Minfo,
    MonMgrPid = self(),
    Msg = {boss_born, SubModule, RankIndex, Guild, BossId, MonMgrPid, MonId, ScenePool},
    home_boss_mgr:svr_cast(SubModule, Msg),
    ok;
boss_born_callback(_, _, _) ->
    ok.

boss_hurt_callback(ObjState = #ob_act{object = MonInfo, klist = KList, 
 hurt_stat_list = HurtList}, MonAtter, [SubModule, _RankIndex, _Guild|_]) ->
    #scene_object{
        mon = #scene_mon{mid = BossId}, battle_attr = #battle_attr{hp = Hp}} = MonInfo,
    NewHurtList = update_hurt_list(MonAtter, HurtList),
    F = fun({_, _, _, HurtA, _}, {_, _, _, HurtB, _}) -> 
        HurtA > HurtB 
    end,
    SortedHurtList = lists:sort(F, NewHurtList),
    BinData = pack_hurt_list(SubModule, BossId, Hp, SortedHurtList),
    [lib_server_send:send_to_uid(Node, RoleId, BinData) || #mon_atter{id = RoleId, node = Node} <- KList],
    ObjState#ob_act{hurt_stat_list = NewHurtList};
boss_hurt_callback(_, _, _) ->
    ok.

boss_die_callback(#ob_act{object = Minfo}, [#mon_atter{name = Name}|_] = KList, 
 Atter, _AtterSign, [SubModule, RankIndex, Guild, BornTime|_]) ->
    #scene_object{mon = #scene_mon{mid = BossId}, scene = SceneId, scene_pool_id = ScenePool} = Minfo,
    {_Args, _RoleIds, MaxHurtRoles} = calc_max_hurt_roles(KList),
    role_settlement(SubModule, RankIndex, BossId, MaxHurtRoles),
    Msg = {boss_die, RankIndex, Guild, BossId, BornTime, Name, SceneId, ScenePool},
    home_boss_mgr:svr_cast(SubModule, Msg),
    RoleIds1 = calc_max_hurt_roles_1(KList),
    KillSvrNum = config:get_server_num(),
    #battle_return_atter{id = KillerId, real_name = KillName, lv = KillLv} = Atter,
    case data_mon:get(BossId) of
        #mon{lv = BossLv} -> ok;
        _ -> BossLv = 0
    end,
    NowTime = utime:unixtime(),
    lib_log_api:log_boss_belong([KillerId, KillName, ?NODE_GAME, KillSvrNum, KillLv, ?MON_HOME_BOSS, BossLv, BossId, RoleIds1, 0, NowTime]),
    ok;
boss_die_callback(_, _, _, _, _A) ->
    ok.

calc_max_hurt_roles(KList) ->
    case lib_drop:calc_max_plist(KList) of
        [[Role = #mon_atter{id = Id, name = Name}|_], []]   -> {[Name, Id], [Id], [Role]};
        [[], TP = [#mon_atter{id = Id, team_leader_name = TeamName}|_]]  ->
            {[TeamName, Id], [P#mon_atter.id || P <- TP, is_record(P, mon_atter)], TP};
        _R -> {[<<>>, 0], [], []}
    end.

update_hurt_list(Atter, HurtList) ->
    #mon_atter{id = RoleId, team_id = TeamId, hurt = Hurt} = Atter,
    SvrNum = 0,
    if
        TeamId > 0 ->
            case lists:keyfind(TeamId, 1, HurtList) of
                {TeamId, _, _, HurtVal, AtterList} ->
                    NewHurtVal = round(HurtVal+Hurt),
                    NewAtterList =
                    case lists:keyfind(RoleId, #mon_atter.id, AtterList) of
                        #mon_atter{hurt = OldRoleHurt} ->
                            lists:keystore(RoleId, #mon_atter.id, AtterList, Atter#mon_atter{hurt = round(OldRoleHurt+Hurt)});
                        _ ->
                            [Atter|AtterList]
                    end,
                    lists:keystore(TeamId, 1, HurtList, {TeamId, 0, SvrNum, NewHurtVal, NewAtterList});
                _ ->
                    [{TeamId, 0, SvrNum, Hurt, [Atter]}|HurtList]
            end;
        true ->
            case lists:keyfind(RoleId, 2, HurtList) of
                {0, RoleId, _, HurtVal, _} ->
                    lists:keystore(RoleId, 2, HurtList, {0, RoleId, SvrNum, round(HurtVal+Hurt), [Atter]});
                _ ->
                    [{0, RoleId, SvrNum, Hurt, [Atter]}|HurtList]
            end
    end.

is_can_drop(MonId, BossLv, Lv) ->
    MonCfg1 = data_home_boss:get_boss_info(?MOD_HOME_BOSS_NORMAL, MonId),
    MonCfg2 = data_home_boss:get_boss_info(?MOD_HOME_BOSS_GUILD, MonId),
    if 
        is_record(MonCfg1, base_home_boss) ->
            is_can_drop_limit(?MOD_HOME_BOSS_NORMAL, MonId, abs(BossLv - Lv));
        is_record(MonCfg2, base_home_boss) ->
            is_can_drop_limit(?MOD_HOME_BOSS_GUILD, MonId, abs(BossLv - Lv));
        true ->
            false
    end.

is_can_drop_limit(SubModule, MonId, AbsLv) ->
    case data_home_boss:get_boss_info(SubModule, MonId) of
        #base_home_boss{drop_lv_limit = DropLvLimit} ->
            if AbsLv > DropLvLimit ->
                    true;
                true ->
                    false
            end;
        _ ->
            true
    end.

mon_sub_module_type(MonId) ->
    MonCfg1 = data_home_boss:get_boss_info(?MOD_HOME_BOSS_NORMAL, MonId),
    MonCfg2 = data_home_boss:get_boss_info(?MOD_HOME_BOSS_GUILD, MonId),
    if 
        is_record(MonCfg1, base_home_boss) ->
            ?MOD_HOME_BOSS_NORMAL;
        is_record(MonCfg2, base_home_boss) ->
            ?MOD_HOME_BOSS_GUILD;
        true ->
            0
    end.

mod_sub_module_type_by_scene(Scene) ->
    data_home_boss:get_scene_sub_module(Scene).

get_sub_module_scene(SubModule) ->
    AllLevels = data_home_boss:get_all_level(SubModule),
    SceneIds = 
    lists:foldl(fun(Level, AccSceneIds) -> 
        case data_home_boss:get_home_boss_level(SubModule, Level) of
            #base_home_boss_level{scene = SceneId} ->
                case lists:member(SceneId, AccSceneIds) of
                    false -> [SceneId|AccSceneIds];
                    _     -> AccSceneIds
                end;
            _ -> AccSceneIds
        end                    
    end, [], AllLevels),
    SceneIds.

update_guild_notice(true, GuildBossPids, NewGuildBossPids) ->
    OldGuildIds = maps:keys(GuildBossPids),
    NewGuildIds = maps:keys(NewGuildBossPids),
    mod_guild:apply_cast(?MODULE, guild_proc_update_notice, [OldGuildIds, NewGuildIds]);
update_guild_notice(_, _, _) ->
    skip.

calc_max_hurt_roles_1(KList) ->
    case lib_drop:calc_max_plist(KList) of
        [[#mon_atter{id = Id}|_], []]   -> [Id];
        [[], TP = [#mon_atter{}|_]]  ->
            LogKList = [{P#mon_atter.server_id, P#mon_atter.id} || P <- TP, is_record(P, mon_atter)],
            if length(LogKList) > 3 ->
                    lists:sublist(3, LogKList);
                true ->
                    LogKList
            end;
        _R -> []
    end.

%% ------------------ 人物进程 ----------------------

%% 归属玩家击杀处理
% role_boss_die_handle(Player, _SubModule, _BossId) ->
%     {ok, Player}.


role_notice_mon_info(Player, Level, SubModule, Guild, MonL) ->
	#player_status{sid = Sid} = Player,
	{ok, BinData} = pt_462:write(46201, [SubModule, Level, Guild, MonL]),
	lib_server_send:send_to_sid(Sid, BinData),
	{ok, Player}.

%% 进入幻魔之家场景
role_enter_home_boss(Player, {SceneId, ScenePool, CopyId, X, Y}, SubModule, BossId, Cost) ->
    #player_status{sid = Sid} = Player,
    % Args = [{action_lock, ?ERRCODE(err460_in_reward_boss)}],
    Player1 = lib_scene:change_scene(Player, SceneId, ScenePool, CopyId, X, Y, []),
    Player3 =
    case lib_goods_api:cost_object_list_with_check(Player1, Cost, enter_home_boss_cost, integer_to_list(SubModule)) of
        {true, Player2, _} ->
            Player2;
        {false, _Error, _} ->
            Player1
    end,
    lib_server_send:send_to_sid(Sid, pt_462, 46204, [?SUCCESS, SubModule, BossId]),
    {ok, Player3}.

%% -------------------------- 社团进程 -----------------------------------
guild_proc_get_guild_info(Sid, _RoleId, GuildIds) ->
    GuildInfos =
    lists:foldl(fun(GuildId, Acc) -> 
        case lib_guild_data:get_guild_by_id(GuildId) of
            [] -> Acc;
            #guild{name = GuildName} ->
                [{GuildId, GuildName}|Acc]
        end
    end, [], GuildIds),
    lib_server_send:send_to_sid(Sid, pt_462, 46205, [GuildInfos]),
    ok.

guild_proc_update_notice(OldGuildIds, NewGuildIds) ->
    GuildInfos = 
    lists:foldl(fun(GuildId, Acc) -> 
        case lib_guild_data:get_guild_by_id(GuildId) of
            [] -> Acc;
            #guild{name = GuildName} ->
                [{GuildId, GuildName}|Acc]
        end
    end, [], NewGuildIds),
    {ok, BinData} = pt_462:write(46205, [GuildInfos]),
    [lib_server_send:send_to_guild(OldGuildId, BinData) || OldGuildId <- OldGuildIds],
    [lib_server_send:send_to_guild(NewGuildId, BinData) || NewGuildId <- NewGuildIds],
    ok.

%% 排行榜进程
rank_proc_sync_guild_rank(State, [_FromPid]) ->
    #common_rank_state{guild_maps = GuildMap} = State,
    GuildRankList = maps:get(?RANK_TYPE_GUILD, GuildMap, []),
    if
        GuildRankList == [] ->
            {ok, State};
        true ->
            SortGuildRankList = common_rank_logic:sort_rank_list(GuildRankList),
            TopGuildRankList  = [{GuildId, Index}  || #common_rank_guild{guild_id = GuildId, rank = Index} <- lists:sublist(SortGuildRankList, 3)],
            % ?ERR("new rank data ~p", [TopGuildRankList]),
            home_boss_mgr:update_guild_race_rank(TopGuildRankList),
            {ok, State}
    end.