%% ---------------------------------
%% desc		:废都幻魔(古战场boss)/混乱星域具体逻辑
%% module	:deserted_boss_mgr
%% author	:hh
%% time		:20/09/15
%% ---------------------------------


-module(deserted_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("czone.hrl").
-include("deserted_boss.hrl").
-include("figure.hrl").
-include("drop.hrl").

-define(DESERTED_DELAY_TIME, 5000).

%% 常规接口
-export([
    start_link/0,
	start/1,
    svr_cast/1,                             %% 游戏服给管理进程发消息
    svr_cast_mon/2,                         %% 游戏服给怪物进程发消息
    cast_mon/4,                             %% 跨服中心给怪物进程发消息                            
    cast/3,                                 %% 跨服中心给阵营管理进程发消息
    call/3,
    get_zone_info_by_by_pool/1,
    get_worker_by_name/2,                   %% 根据注册名获取进程
    calc_msg_pid/1,
    check_cls_deserted_boss/0,
	
    add_support_asker/2,                    %% 添加被协助者
	role_go_supporting/2,					%% 开始协助
	asker_cancel_support/2,					%% 被协助者取消协助
	supported_cancel_support/2,				%% 协助者取消协助
	revive/8,								%% 复活判断
	team_change/4,                          %% 队伍信息变更
	get_boss_hurt_info/3,                   %% 获取BOSS伤害排名
    get_deserted_boss_info/5,               %% 获取boss信息
    get_elite_mon_info/3,                   %% 获得精英怪物存活状况
    revive_mon/0,                           %% 复活当前死亡的boss

    conn_game_node/1,
    close_local_deserted_boss/0,
    boss_revive/1,                         %% 复活单个Boss
    get_boss_reborn_time/1,                %% 获取单个boss复活时间

    gm_local_mode/1,                        %% 线上正式逻辑不能调用
    gm_start_cls_mode/2,
    gm_close_cls_mode/2,
    gm_close_cls_mode_1/3
    ]).

%% 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_add_support_asker/2       %% 开始请求协助
	,mon_proc_role_supporting/2			%% 开始协助
	,mon_proc_cancel_support/2			%% 取消协助
	,mon_proc_role_revive/8				%% 复活检测
	,leave_boss_distance_trigger/3		%% 脱离boss范围触发
	,restat_when_hurt_change/1			%% 重新统计仇恨伤害
	]).

%% 场景进程调用
-export([
	supporter_attack_check/2
	]).

%% 人物进程调用
-export([
	role_support_cancel_check/2
	,role_boss_die_handle/4
	,role_notice_mon_info/2
    ,role_notice_elite_info/3
	,add_mon_drop_log/6
	]).

%% 本服启动
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [0, 0, 0], []).

%% 跨服启动
start([ZoneId, FacId, SvrOpenTime]) ->
	gen_server:start(?MODULE, [ZoneId, FacId, SvrOpenTime], []).

%% 秘籍开启本服模式
gm_local_mode(start) ->
    Pid    = misc:whereis_name(local, ?MODULE),
    PidRet = is_pid(Pid) andalso misc:is_process_alive(Pid),
    czone_api:env_del_zone(),
    if PidRet -> skip;
        true ->
            supervisor:restart_child(game_master_sup, ?MODULE)
    end;

%% 秘籍关闭本服模式
gm_local_mode(close) ->
    close_local_deserted_boss(),
    SvrId = config:get_server_id(),
    case catch clusters_node:apply_call(czone, get_zone_svr_local, [SvrId]) of
        CzoneSvrLoc = #czone_svr_local{zone_id = ZoneId, faction = FacId} ->
            czone_api:env_set_zone(CzoneSvrLoc#czone_svr_local{stage = 3}),
            clusters_node:apply_cast(?MODULE, gm_start_cls_mode, [ZoneId, FacId]);
        _Error ->
            ?ERR("~p", [_Error])
    end,
    ok.

%% 秘籍开启跨服模式
gm_start_cls_mode(ZoneId, FacId) ->
    Pid = get_worker_by_name(ZoneId, FacId),
    PidRet = is_pid(Pid) andalso misc:is_process_alive(Pid),
    if PidRet -> skip;
        true  -> erlang:send(deserted_boss_sup, {init_deserted_boss_worker, ZoneId, FacId})
    end.

%% 秘籍关闭跨服模式
gm_close_cls_mode(ZoneId, FacId) ->
    deserted_boss_sup:apply_cast({?MODULE, gm_close_cls_mode_1, [ZoneId, FacId]}).

gm_close_cls_mode_1(State, ZoneId, FacId) ->
    Pid = get_worker_by_name(ZoneId, FacId),
    PidRet = is_pid(Pid) andalso misc:is_process_alive(Pid),
    if PidRet -> 
            #deserted_sup_state{monitor_map = MonitorMap, zone_faction_pids = ZoneFactionPids} = State,
            MonitorList = maps:to_list(MonitorMap),
            case lists:filter(fun({_MonitorRefX, {ZoneIdX, FacIdX, _PidX}}) -> 
                ZoneIdX == ZoneId andalso FacId == FacIdX
            end, MonitorList) of
                [{MonitorRef, {ZoneId, FacId, _WorkerPid}}|_] ->
                    erlang:demonitor(MonitorRef),
                    NewMonitorMap = maps:remove(MonitorRef, MonitorMap),
                    exit(Pid, close),
                    NewZoneFactionPids = maps:remove({ZoneId, FacId}, ZoneFactionPids),
                    State#deserted_sup_state{
                        monitor_map = NewMonitorMap, 
                        zone_faction_pids = NewZoneFactionPids
                    };
                _ ->
                    State
            end;
        true ->
            State
    end.

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

%% 获取boss信息
get_deserted_boss_info(RoleId, Sid, Node, Level, FocusL) ->
	svr_cast({get_deserted_boss_info, RoleId, Sid, Node, Level, FocusL}).

%% 获得精英怪物存活状况
get_elite_mon_info(Sid, Node, Level) ->
    svr_cast({get_elite_mon_info, Sid, Node, Level}).

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

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

revive_mon() ->
    svr_cast({'revive_mon'}).

%% 复活单个Boss
boss_revive(BossId) ->
    svr_cast({boss_revive, BossId}).

%% 获取单个boss复活时间
get_boss_reborn_time(BossId) ->
    svr_call({get_boss_reborn_time, BossId}).


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

%% 添加被协助者
add_support_asker(RoleInfo, BossId) ->
    svr_cast_mon(BossId, {'mod', ?MODULE, mon_proc_add_support_asker, [RoleInfo]}).

%% 开始协助
role_go_supporting(RoleId, BossId) ->
	svr_cast_mon(BossId, {'mod', ?MODULE, mon_proc_role_supporting, [RoleId]}).

%% 主动取消协助
asker_cancel_support(RoleId, BossId) ->
	svr_cast_mon(BossId, {'leave', RoleId, undefined, ?BATTLE_SIGN_PLAYER}).

%% 协助者取消协助
supported_cancel_support(RoleId, BossId) ->
	svr_cast_mon(BossId, {'mod', ?MODULE, mon_proc_cancel_support, [RoleId]}).

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

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


%% 跨服分区中的游戏服连接到跨服节点回调--游戏服执行
%% ------------------------------------------------
%% @doc 
%% terminate_child(SupRef, Id) -> Result
%% If the supervisor is not simple_one_for_one, 
%% Id must be the child specification identifier.
conn_game_node(_) ->
    {Ret, _ZoneId, _FacId} = check_cls_deserted_boss(),
    % ?ERR("~p ~p ~p", [Ret, _ZoneId, _FacId]),
    if
        Ret ->
            close_local_deserted_boss();
        true ->
            skip
    end.

%% 本地boss管理进程关闭处理
close_local_deserted_boss() ->
    Pid    = misc:whereis_name(local, deserted_boss_mgr),
    PidRet = is_pid(Pid) andalso misc:is_process_alive(Pid),
    if PidRet ->
            spawn(fun() ->
                gen_server:cast(Pid, {local_close}),
                timer:sleep(1000),
                supervisor:terminate_child(game_master_sup, deserted_boss_mgr)
            end);
        true ->
            skip
    end.

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

%% 游戏服给公共管理进程发消息
-spec svr_cast(Msg) -> Ret when
    Msg :: tuple(),
    Ret :: term().
svr_cast(Msg) ->
    {Ret, ZoneId, FacId} = check_cls_deserted_boss(),
    if 
        Ret ->
            clusters_node:apply_cast(?MODULE, cast, [ZoneId, FacId, Msg]);
        true ->
            gen_server:cast(?MODULE, Msg)
    end.

svr_call(Msg) ->
    {Ret, ZoneId, FacId} = check_cls_deserted_boss(),
    if
        Ret ->
            clusters_node:apply_call(?MODULE, call, [ZoneId, FacId, Msg]);
        true ->
            gen_server:call(?MODULE, Msg)
    end.

%% 游戏服给怪物进程发消息
-spec svr_cast_mon(BossId, Msg) -> Ret when
    BossId :: integer(),
    Msg :: tuple(),
    Ret :: term().
svr_cast_mon(BossId, Msg) ->
    {Ret, ZoneId, FacId} = check_cls_deserted_boss(),
    if 
        Ret ->
            clusters_node:apply_cast(?MODULE, cast_mon, [ZoneId, FacId, BossId, Msg]);
        true ->
            gen_server:cast(?MODULE, {cast_mon, BossId, Msg})
    end.

%% 游戏服调用
%% 阶段判断待定
-spec check_cls_deserted_boss() -> Ret when
    Ret :: {IsCzone, ZoneId, FacId},
    IsCzone :: boolean(),           %% 是否处于跨服玩法
    ZoneId :: non_neg_integer(),    %% 分区id
    FacId :: integer().             %% 阵营id
check_cls_deserted_boss() ->
    CZoneSvrLocal = czone_api:env_get_zone(),
    if is_record(CZoneSvrLocal, czone_svr_local) ->
            #czone_svr_local{zone_id = ZoneId, faction = FacId, stage = Stage} = CZoneSvrLocal,
            if Stage >= 3 -> {true, ZoneId, FacId}; %% 处于分区且不是阶段3(即已处于1个阵营多个服的情况了)
                true     -> {false, 0, 0}
            end;
        true -> {false, 0, 0}
    end.

%% 跨服中心给怪物发消息
-spec cast_mon(ZoneId, FacId, BossId, Msg) -> ok when
    ZoneId :: non_neg_integer(),
    FacId  :: integer(),
    BossId :: integer(), 
    Msg    :: term().
cast_mon(ZoneId, FacId, BossId, Msg) ->
    cast(ZoneId, FacId, {cast_mon, BossId, Msg}),
    ok.

%% 跨服中心给阵营工作进程发消息
-spec cast(ZoneId, FacId, Msg) -> ok when
    ZoneId :: non_neg_integer(),   %% 分区id
    FacId  :: integer(),           %% 阵营id
    Msg    :: term().              %% 消息
cast(ZoneId, FacId, Msg) ->
    Worker = get_worker_by_name(ZoneId, FacId),
    gen_server:cast(Worker, Msg),
    ok.

call(ZoneId, FacId, Msg) ->
    Worker = get_worker_by_name(ZoneId, FacId),
    gen_server:call(Worker, Msg).



%% local注册
register_worker(ZoneId, FacId, Pid) ->
    erlang:register(boss_worker_name(ZoneId, FacId), Pid).

%% 阵营工作进程名称
boss_worker_name(ZoneId, FacId) ->
    list_to_atom(lists:concat(["de_worker_", ZoneId, "_", FacId])).

%% 根据注册名获取阵营工作进程
get_worker_by_name(ZoneId, FacId) ->
    erlang:whereis(boss_worker_name(ZoneId, FacId)).

%% 根据分区和阵营获取分线
calc_scene_pool(ZoneId, FacId) ->
    <<ScenePool:40>> = <<ZoneId:32, FacId:8>>,
    ScenePool.

%% 根据分线获取分区和阵营
get_zone_info_by_by_pool(ScenePool) ->
    <<ZoneId:32, FacId:8>> = <<ScenePool:40>>,
    {ZoneId, FacId}.

calc_msg_pid([?NODE_CENTER, ZoneId, FacId|_]) ->
    get_worker_by_name(ZoneId, FacId);
calc_msg_pid([?NODE_GAME|_]) ->
    deserted_boss_mgr.

%% -----------------------------------------------------------------------------------
-spec init(list()) ->
    {ok, State :: #deserted_boss_state{}} | {ok, State :: #deserted_boss_state{}, timeout() | 
    hibernate | {continue, term()}} | {stop, Reason :: term()} | ignore.
init([ZoneId, FacId, OpenTime|_]) ->
    ClsType = config:get_cls_type(),
    init_do([ClsType, ZoneId, FacId, OpenTime]).

init_do([?NODE_GAME|_]) ->
    Ref = erlang:send_after(3000, self(),  {local_init}),
    Map = maps:put(?WORKER_INIT, Ref, #{}),
    {ok, #deserted_boss_state{map = Map}};
init_do([?NODE_CENTER, ZoneId, FacId, OpenTime|_]) ->
    Pid = self(),
    register_worker(ZoneId, FacId, Pid),
    Ref = erlang:send_after(?DESERTED_DELAY_TIME, Pid, {init}),
    Map = #{?WORKER_INIT => Ref, ?CLS_OPEN_TIME => OpenTime},
	State = #deserted_boss_state{
        zone_id = ZoneId, fac_id = FacId, 
        cls_type = ?NODE_CENTER, map = Map
    },
	{ok, State}.

handle_call(Request, From, State) ->
    try
        do_handle_call(Request, From, State)
    catch ?EXCEPTION(_ErrorClass, _Error, StackTrace) ->
        ?ERR("deserted_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    :: #deserted_boss_state{}.
handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        NewState = #deserted_boss_state{} ->
            {noreply, NewState};
        {noreply, NewState} ->
            {noreply, NewState};
        ok ->
            {noreply, State};
        skip ->
            {noreply, State};
        {stop, _Reason, NewState} ->
            _Reason =/= normal andalso ?ERR("deserted_boss_state stop reason ~n ~p", [_Reason]),
            {stop, _Reason, NewState};
        Reason ->
            ?ERR("deserted_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 :: #deserted_boss_state{}.
handle_info(Msg, State) ->
    case catch do_handle_info(Msg, State) of
        NewState = #deserted_boss_state{} ->
            {noreply, NewState};
        {noreply, NewState} ->
            {noreply, NewState};
        ok ->
            {noreply, State};
        skip ->
            {noreply, State};
        {stop, _Reason, NewState} ->
            _Reason =/= normal andalso ?ERR("deserted_boss_state process stop reason:~n ~p", [_Reason]),
            {stop, _Reason, NewState};
        _Reason ->
            ?ERR("deserted_boss_state process msg: ~n ~p ~n reason: ~n ~p", [Msg, _Reason]),
            {noreply, State}
    end.

%% 跨服中心进程停止时检查是否正常结束
terminate(_Reason, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId, boss_info = BossInfos, cls_type = ClsType} = State,
    ?ERR("de_worker:~w close ~p", [{ZoneId, FacId}, _Reason]),
    if _Reason == normal ->
            skip;
        _Reason == monitor_error_exit ->
            skip;
        true ->
            if ClsType == ?NODE_GAME -> ScenePool = 0;
                true -> ScenePool = calc_scene_pool(ZoneId, FacId)
            end,
            lists:map(fun(#deserted_boss_info{boss_id = MonId}) -> 
                case get_boss_scene(ClsType, MonId) of
                    Scene when is_integer(Scene) andalso Scene =/= 0 ->
                        ExitArgs = [],
                        mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, lib_scene, player_change_default_scene, ExitArgs),
                        mod_scene_agent:close_scene(Scene, ScenePool);
                    _ ->
                        skip
                end
            end, BossInfos)
    end,
    ok.

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

do_handle_call({get_boss_reborn_time, BossId}, _From, State) ->
    #deserted_boss_state{boss_info = BossInfos} = State,
    case lists:keyfind(BossId, #deserted_boss_info.boss_id, BossInfos) of
        #deserted_boss_info{reborn_time = RebornTime} ->
            {reply, RebornTime, State};
        _ ->
            {reply, false, State}
    end.

do_handle_cast({cast_mon, BossId, Msg}, State) ->
	#deserted_boss_state{boss_info = BossInfos} = State,
	case lists:keyfind(BossId, #deserted_boss_info.boss_id, BossInfos) of
		#deserted_boss_info{boss_pid = BossMgrPid, mon_id = MonId} ->
			case misc:is_process_alive(BossMgrPid) of
				true ->
					% old: erlang:send(BossPid, Msg);
                    mon_mgr:send(BossMgrPid, MonId, Msg);
				_ ->
					skip
			end;
		_ ->
			skip
	end,
	ok;

do_handle_cast({boss_born, BossId, MonMgrPid, MonId}, State) ->
	#deserted_boss_state{boss_info = BossInfos} = State,
	case lists:keyfind(BossId, #deserted_boss_info.boss_id, BossInfos) of
		Boss = #deserted_boss_info{ref_reborn = Ref} ->
			Now = utime:unixtime(),
			util:cancel_timer(Ref),
			NewBoss = Boss#deserted_boss_info{
				boss_pid = MonMgrPid,
				mon_id = MonId,
				born_time = Now,
				reborn_time = 0,
				ref_reborn = undefined
			},
			NewBossInfos = lists:keystore(BossId, #deserted_boss_info.boss_id, BossInfos, NewBoss),
			NewState = State#deserted_boss_state{boss_info = NewBossInfos},
			{noreply, NewState};
		_ ->
			ok
	end;

do_handle_cast({boss_die, BossId, _BossType, BornTime, SvrId, KillerName, Scene, ScenePool}, State) ->
	#deserted_boss_state{boss_info = BossInfos, cls_type = ClsType, map = Map, zone_id = ZoneId, fac_id = FacId} = State,
	case lists:keyfind(BossId, #deserted_boss_info.boss_id, BossInfos) of
	 	Boss = #deserted_boss_info{ref_reborn = OldRef} ->
            Now = utime:unixtime(),
            %% 保存状态
            if ClsType == ?NODE_GAME ->
                    db:execute(?SQL_SAVE_ONE_REWARD_BOSS, [BossId, ?MON_DESERTED_BOSS, BornTime, Now, KillerName]);
                ClsType == ?NODE_CENTER ->
                    SvrNum = clusters_center:find_server_num(SvrId),
                    db:execute(?SQL_REPLACE_DESERTED_BOSS_STATUS, [ZoneId, FacId, BossId, Now, KillerName, SvrNum])
            end,
            case data_deserted_boss:get_boss_cfg(BossId) of
            	#base_deserted_boss_info{level = Level, reborn_time = RebornTimeL, born_pos = {RebornX, RebornY}} ->
                    OpenDay = calc_open_day(ClsType, maps:get(?CLS_OPEN_TIME, Map, Now)),
            		RebornTime = get_reborn_time(OpenDay, RebornTimeL),
            		NextTime = Now + RebornTime,
            		Ref = util:send_after(OldRef, RebornTime*1000, self(), {create_deserted_boss, BossId, RebornX, RebornY}),
            		NewBoss = Boss#deserted_boss_info{
            			ref_reborn = Ref, reborn_time = NextTime,
            			last_killer = KillerName},
            		NewBossInfos = lists:keyreplace(BossId, #deserted_boss_info.boss_id, BossInfos, NewBoss),
    				% [one_boss_die(ClsType, BossId, BossType, TopHurtRoleId) || TopHurtRoleId <- TopHurtRoleIds],
    				MonL = pack_mon_info(Level, NewBossInfos),
    				mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, ?MODULE, role_notice_mon_info, [MonL]),
            		NewState = State#deserted_boss_state{boss_info = NewBossInfos},
            		{noreply, NewState};
            	_ ->
            		{noreply, State}
            end;
		_ ->
			{noreply, State}
	end;

do_handle_cast({elite_mon_die, BossId, _BossType, MonIndex, _BornTime}, State) ->
	#deserted_boss_state{elite_mon_info = EliteMonInfos, cls_type = ClsType, map = Map} = State,
	case data_deserted_boss:get_elite_mon_cfg(MonIndex) of
		#base_elite_mon{reborn_time = RebornTimeL, born_pos = {X, Y}} ->
    		Now = utime:unixtime(),
    		OpenDay = calc_open_day(ClsType, maps:get(?CLS_OPEN_TIME, Map, Now)),
            RebornTime = get_reborn_time(OpenDay, RebornTimeL),
    		% NextTime = Now + RebornTime,
    		Ref = util:send_after(undefined, RebornTime*1000, self(), {create_deserted_mon, BossId, MonIndex, X, Y}),
    		NewEliteMonInfo = {{MonIndex, BossId}, Ref},
    		NewEliteMonInfos = lists:keystore({MonIndex, BossId}, 1, EliteMonInfos, NewEliteMonInfo),
    		% [one_boss_die(ClsType, BossId, BossType, RoleId) || RoleId <- RoleIds ],
    		NewState = State#deserted_boss_state{elite_mon_info = NewEliteMonInfos},
    		{noreply, NewState};
		_ ->
			{noreply, State}
	end;

do_handle_cast({get_deserted_boss_info, _RoleId, Sid, Node, Level, FocusL}, State) ->
	#deserted_boss_state{boss_info = BossInfos} = State,
	MonIds = data_deserted_boss:get_all_boss(),
	MonInfo = lists:foldl(fun(MonId, Acc) ->
		case data_deserted_boss:get_boss_key_info(MonId) of
			[{Level, _, _}|_] ->
				case lists:keyfind(MonId, #deserted_boss_info.boss_id, BossInfos) of
					#deserted_boss_info{reborn_time = RebornTime, last_killer = Killer} ->
						case lists:member(MonId, FocusL) of
							true -> [{MonId, RebornTime, 1, Killer}|Acc];
							_ 	 -> [{MonId, RebornTime, 0, Killer}|Acc]
						end;
					_ -> Acc
				end;
			_ -> Acc
		end
	end, [], MonIds),
 	{ok, BinData} = pt_461:write(46101, [MonInfo]),
 	lib_server_send:send_to_sid(Node, Sid, BinData),
	ok;

%% 获得精英怪物存活状况
do_handle_cast({get_elite_mon_info, Sid, Node, Level}, State) ->
    #deserted_boss_state{elite_mon_info = EliteMonInfo} = State,
    MonIds = data_deserted_boss:get_mon_by_level(Level),
    MonInfo = lists:foldl(
        fun({Index, _MonId} = Key, Acc) ->
            case lists:keyfind(Key, 1, EliteMonInfo) of
                {Key, 1} ->
                    Alive = 1;
                _ -> Alive = 0
            end,
            [{Index, Alive}|Acc]
        end, [], MonIds),
    {ok, BinData} = pt_461:write(46109, [MonInfo]),
    lib_server_send:send_to_sid(Node, Sid, BinData),
    ok;

do_handle_cast({'team_flag', _RoleId, Scene, _TeamId, _TeamLeaderName}, State) ->
	#deserted_boss_state{boss_info = BossInfos, cls_type = ClsType} = State,
	lists:map(fun(#deserted_boss_info{boss_id = BossId, boss_pid = BossMgrPid, mon_id = MonId}) ->
		case data_deserted_boss:get_boss_key_info(BossId) of
			[{Level, _, _}|_] ->
                SceneRet =
				case data_deserted_boss:get_level(Level) of
					#base_deserted_level{scene = LocalScene, cls_scene = ClsScene} ->
                        if  ClsType == ?NODE_GAME -> LocalScene == Scene;
                            ClsType == ?NODE_CENTER -> ClsScene == Scene;
                            true -> false
                        end;
                    _ -> 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, BossInfos),
	ok;

do_handle_cast({'add_mon_drop_log', RoleId, SvrNum, Name, Scene, MonId, DropReward}, State) ->
	#deserted_boss_state{zone_id = ZoneId, fac_id = FacId, cls_type = ClsType, boss_info = BossInfos} = State,
	case lists:keyfind(MonId, #deserted_boss_info.boss_id, BossInfos) of
		#deserted_boss_info{} ->
			case DropReward of
				[{_, GoodsId, _DropNum}|_] ->
					case data_goods_type:get(GoodsId) of
						#ets_goods_type{color = Color} when Color >= ?ORANGE ->
							add_log([ClsType, ZoneId, FacId, Name, RoleId, SvrNum, Scene, MonId, GoodsId, utime:unixtime()]);
						_ ->
							skip
					end;
				_ ->
					skip
			end;
		_ ->
			skip
	end,
	ok;

do_handle_cast({monitor_error_exit}, State) ->
    #deserted_boss_state{
        boss_info = BossInfos,
        zone_id = ZoneId, fac_id = FacId, cls_type = ClsType
    } = State,
    %% 踢人&清怪
    ScenePool = calc_scene_pool(ZoneId, FacId),
    lists:map(fun(#deserted_boss_info{boss_id = MonId}) -> 
        case get_boss_scene(ClsType, MonId) of
            Scene when is_integer(Scene) andalso Scene =/= 0 ->
                ExitArgs = [],
                mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, lib_scene, player_change_default_scene, ExitArgs),
                mod_scene_agent:close_scene(Scene, ScenePool);
            _ ->
                skip
        end
    end, BossInfos),
    Reason = monitor_error_exit,
    {stop, Reason, State};

do_handle_cast({enter_deserted_boss_scene, [SceneId, Node, RoleId, Sid, GuildId, SupportSid, BossId, X, Y, _RebornX, _RebornY, EnterArgs|_]}, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId} = State,
    ScenePool = calc_scene_pool(ZoneId, FacId),
    case local_boss_api:check_role_num_limit(SceneId, ScenePool, ?DESERTED_BOSS_NUM) of
        true ->
            if SupportSid == 0 -> %% 正常进入
                    clusters_center:apply_cast(Node, lib_scene, change_player_scene, [RoleId, SceneId, ScenePool, 0, X, Y, []]);
                true -> %% 协助进入需直接跳转到怪物周围
                    % RandX = RebornX + urand:rand(-200, 200),
                    % RandY = RebornY + urand:rand(-200, 200),
                    % clusters_center:apply_cast(Node, lib_scene, change_player_scene, [RoleId, SceneId, ScenePool, 0, RandX, RandY, []]),
                    SceneArgs = [RoleId, SceneId, ScenePool, 0, X, Y, []],
                    clusters_center:apply_cast(Node, guild_support_deserted_boss, supporter_enter_cls_scene, [SceneArgs, EnterArgs]),
                    Msg = {'mod', ?MODULE, mon_proc_role_supporting, [RoleId]},
                    do_handle_cast({cast_mon, BossId, Msg}, State)
            end,
            ok;
        {false, Error} ->
            {ok, BinData} = pt_461:write(46106, [Error, BossId]),
            lib_server_send:send_to_sid(Node, Sid, BinData),
            %% 取消协助
            if SupportSid == 0 -> skip;
                true ->
                    GuildExeMod  = lib_guild_support_mod,
                    GuildExeFun  = delete_from_support_role_list,
                    GuildExeArgs = [GuildId, SupportSid, RoleId],   
                    Args = [GuildExeMod, GuildExeFun, GuildExeArgs],
                    clusters_center:apply_cast(Node, mod_guild_support, apply_cast, Args)
            end
    end,
    {noreply, State};

%% 跨服分区变动关闭工作进程
do_handle_cast({deserted_boss_close_after_recalc}, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId, cls_type = ClsType, boss_info = BossInfos} = State,
    ScenePool = calc_scene_pool(ZoneId, FacId),
    lists:map(fun(#deserted_boss_info{boss_id = MonId}) -> 
        case get_boss_scene(ClsType, MonId) of
            Scene when is_integer(Scene) andalso Scene =/= 0 ->
                ExitArgs = [],
                mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, lib_scene, player_change_default_scene, ExitArgs),
                mod_scene_agent:close_scene(Scene, ScenePool);
            _ ->
                skip
        end
    end, BossInfos),
    db:execute(?SQL_DELETE_DESERTED_BOSS_STATUS, [ZoneId, FacId]),
    {stop, normal, State};

%% 达到指定分区标准后关闭本服场景
do_handle_cast({local_close}, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId, boss_info = BossInfos, cls_type = ClsType} = State,
    ScenePool = calc_scene_pool(ZoneId, FacId),
    lists:map(fun(#deserted_boss_info{boss_id = MonId}) -> 
        case get_boss_scene(ClsType, MonId) of
            Scene when is_integer(Scene) andalso Scene =/= 0 ->
                ExitArgs = [],
                mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, lib_scene, player_change_default_scene, ExitArgs),
                mod_scene_agent:close_scene(Scene, ScenePool);
            _ ->
                skip
        end
    end, BossInfos),
    % ?ERR("local close", []),
    {noreply, State};

%% 更新阵营内最晚开服天数，供生成怪物判断
do_handle_cast({update_node_open_time, NewTime}, State) ->
    #deserted_boss_state{map = Map} = State,
    ClsOpenTime = maps:get(?CLS_OPEN_TIME, Map, 0),
    if ClsOpenTime =/= 0 andalso NewTime > ClsOpenTime ->
            NewMap = maps:put(?CLS_OPEN_TIME, NewTime, Map);
        true ->
            NewMap = Map
    end,
    NewState = State#deserted_boss_state{map = NewMap},
    {noreply, NewState};

%% 复活当前死亡的boss
do_handle_cast({'revive_mon'}, State) ->
    #deserted_boss_state{cls_type = ClsType, boss_info = BossInfos, zone_id = ZoneId, fac_id = FacId} = State,
    NewBossInfos = lists:map(fun(Boss) ->
        #deserted_boss_info{boss_id = BossId, reborn_time = RebornTime, ref_reborn = Ref} = Boss, 
        if RebornTime =/= 0 ->
                case data_deserted_boss:get_boss_key_info(BossId) of
                    [{_Level, {X, Y}, _RebornList}|_] ->
                        util:cancel_timer(Ref),
                        create_deserted_boss([ClsType, ZoneId, FacId, BossId, X, Y]),
                        Boss#deserted_boss_info{ref_reborn = undefined, reborn_time = 0};
                    _ ->
                        Boss
                end;
            true ->
                Boss
        end
    end, BossInfos),
    NewState = State#deserted_boss_state{boss_info = NewBossInfos},
    {noreply, NewState};

%% 复活单个死亡的boss
do_handle_cast({boss_revive, BossId}, State) ->
    #deserted_boss_state{cls_type = ClsType, boss_info = BossInfos, zone_id = ZoneId, fac_id = FacId} = State,
    case lists:keyfind(BossId, #deserted_boss_info.boss_id, BossInfos) of
        #deserted_boss_info{boss_id = BossId, reborn_time = RebornTime, ref_reborn = Ref} = Boss ->
            NewBoss =
                if RebornTime =/= 0 ->
                case data_deserted_boss:get_boss_key_info(BossId) of
                    [{_Level, {X, Y}, _RebornList}|_] ->
                        util:cancel_timer(Ref),
                        create_deserted_boss([ClsType, ZoneId, FacId, BossId, X, Y]),
                        Boss#deserted_boss_info{ref_reborn = undefined, reborn_time = 0};
                    _ ->
                        Boss
                end;
                true ->
                    Boss
            end,
            NewBossInfos = lists:keyreplace(BossId, #deserted_boss_info.boss_id, BossInfos, NewBoss);
        _ ->  NewBossInfos = BossInfos
    end,
    NewState = State#deserted_boss_state{boss_info = NewBossInfos},
    {noreply, NewState};

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

do_handle_info({init}, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId, map = Map, cls_type = ClsType} = State,
	MonList = [list_to_tuple(Mon) || Mon <- db:get_all(?SQL_GET_DESERTED_BOSS_STATUS, [ZoneId, FacId])],
	MonIds  = data_deserted_boss:get_all_boss(),
    %% 跨服中心没有开服天数,创怪依据阵营内最晚开服的天数
	Now     = utime:unixtime(),
    OpenDay = calc_open_day(ClsType, maps:get(?CLS_OPEN_TIME, Map, Now)),
    ClsType = config:get_cls_type(),
	BossInfos =
	[begin
		[{_Level, {X, Y}, RebornList}|_] = data_deserted_boss:get_boss_key_info(MonId),
		RebornTime = get_reborn_time(OpenDay, RebornList),
		case lists:keyfind(MonId, 1, MonList) of
			{_, DeadTime, Killer, SrvNum} ->
				NextTime = DeadTime + RebornTime,
				if NextTime > Now ->
						Ref = erlang:send_after((NextTime - Now)*1000, self(), {create_deserted_boss, MonId, X, Y}),
						NextTime1 = NextTime;
					true ->
						create_deserted_boss([ClsType, ZoneId, FacId, MonId, X, Y]),
						Ref = undefined, NextTime1 = 0
				end;
			_ ->
				create_deserted_boss([ClsType, ZoneId, FacId, MonId, X, Y]),
				Ref = undefined, NextTime1 = 0,
				Killer = <<>>, SrvNum = 0
		end,
		#deserted_boss_info{
            boss_id = MonId, reborn_time = NextTime1, 
            last_killer = Killer, srv_num = SrvNum,
            ref_reborn = Ref}
	end || MonId <- MonIds
	],
    EliteMonInfo =
	[begin
         create_elite_mon([ClsType, EliteMonIndex, ZoneId, FacId]),
         {{EliteMonIndex, EliteMonId}, 1}
     end  || {EliteMonIndex, EliteMonId} <- data_deserted_boss:get_mon_index()],
	NewState = State#deserted_boss_state{boss_info = BossInfos, elite_mon_info = EliteMonInfo},
	{noreply, NewState};

do_handle_info({create_deserted_boss, BossId, RebornX, RebornY}, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId, cls_type = ClsType} = State,
	create_deserted_boss([ClsType, ZoneId, FacId, BossId, RebornX, RebornY]),
	#mon{name = BossName} = data_mon:get(BossId),
    Args = [{all}, ?MOD_DESERTED_BOSS, 1, [BossName]],
    if ClsType == ?NODE_CENTER ->
	       deserted_boss_sup:zone_fac_apply_cast(ZoneId, FacId, {lib_chat, send_TV, Args});
        true ->
            lib_chat:send_TV({all}, ?MOD_DESERTED_BOSS, 1, [BossName])
    end,
    {noreply, State};

do_handle_info({create_deserted_mon, BossId, MonIndex, _X, _Y}, State) ->
    #deserted_boss_state{zone_id = ZoneId, fac_id = FacId, cls_type = ClsType, elite_mon_info = EliteMonInfos} = State,
	create_elite_mon([ClsType, MonIndex, ZoneId, FacId]),
    NewEliteMonInfo = {{MonIndex, BossId}, 1},
    NewEliteMonInfos = lists:keystore({MonIndex, BossId}, 1, EliteMonInfos, NewEliteMonInfo),
	{noreply, State#deserted_boss_state{elite_mon_info = NewEliteMonInfos}};

do_handle_info({local_init}, State) ->
    % ?ERR("local init", []),
    #deserted_boss_state{map = Map} = State,
    util:cancel_timer(maps:get(?WORKER_INIT, Map, undefined)),
    NewMap   = maps:remove(?WORKER_INIT, Map),
    NewState = local_init(State#deserted_boss_state{map = NewMap}),
    {noreply, NewState};

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

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

%% boss怪创建
create_deserted_boss([?NODE_CENTER, ZoneId, FacId, MonId, X, Y|_]) ->
    ScenePool = calc_scene_pool(ZoneId, FacId),
    MonArgs   = [?NODE_CENTER, ZoneId, FacId],
    create_deserted_boss_do(?NODE_CENTER, ScenePool, MonId, X, Y, MonArgs);

create_deserted_boss([?NODE_GAME, _, _, MonId, X, Y|_]) ->
    ScenePool = 0,
    MonArgs   = [?NODE_GAME, 0, 0],
    create_deserted_boss_do(?NODE_GAME, ScenePool, MonId, X, Y, MonArgs);

create_deserted_boss(_L) ->
    ?ERR("deserted boss create args arror ~p", [_L]),
    skip.


create_deserted_boss_do(ClsType, ScenePool, MonId, X, Y, MonArgs) ->
    case data_deserted_boss:get_boss_cfg(MonId) of
        #base_deserted_boss_info{level = Level} ->
            case data_deserted_boss:get_level(Level) of
                #base_deserted_level{scene = Scene, cls_scene = ClsScene} ->
                    if  ClsType == ?NODE_GAME ->
                            TarScene = Scene;
                        ClsType == ?NODE_CENTER ->
                            TarScene = ClsScene;
                        true -> TarScene = 0
                    end,
                    Args = get_mon_args(MonArgs, MonId, utime:unixtime()),
                    TarScene =/= 0 andalso lib_mon:async_create_mon(MonId, TarScene, ScenePool, X, Y, 1, 0, 1, Args);
                _ -> skip
            end;
        _ -> skip
    end.

%% 精英怪(小怪)创建
create_elite_mon([?NODE_CENTER, MonIndex, ZoneId, FacId|_]) ->
    ScenePool = calc_scene_pool(ZoneId, FacId),
    MonArgs   = [?NODE_CENTER, ZoneId, FacId, utime:unixtime()],
    create_elite_mon_do(?NODE_CENTER, ScenePool, MonIndex, MonArgs);
create_elite_mon([?NODE_GAME, MonIndex|_]) ->
    ScenePool = 0,
    MonArgs   = [?NODE_GAME, 0, 0, utime:unixtime()],
    create_elite_mon_do(?NODE_GAME, ScenePool, MonIndex, MonArgs).


create_elite_mon_do(ClsType, ScenePool, MonIndex, MonArgs) ->
	case data_deserted_boss:get_elite_mon_cfg(MonIndex) of
		#base_elite_mon{mon_id = MonId, level = Level, born_pos = {X, Y}} ->
			case data_deserted_boss:get_level(Level) of
				#base_deserted_level{scene = Scene, cls_scene = ClsScene} ->
                if ClsType == ?NODE_GAME ->
                        TarScene = Scene;
                    ClsType == ?NODE_CENTER ->
                        TarScene = ClsScene;
                    true -> TarScene = 0
                end,
				Args = [
					{die_handler, {?MODULE, boss_die_callback, MonArgs}},
					{create_key,  {deserted_elite_mon, MonIndex}}
				],
                mod_scene_agent:apply_cast_scene_user(TarScene, ScenePool, 0, ?MODULE, role_notice_elite_info, [MonIndex, 1]),
				TarScene =/= 0 andalso lib_mon:async_create_mon(MonId, TarScene, ScenePool, X, Y, 1, 0, 1, Args);
				_ ->
					skip
			end;
		_ ->
			skip
	end.

%% 创怪参数
get_mon_args(ModuleArgs, MonId, BornTime) ->
    case data_deserted_boss:get_boss_cfg(MonId) of
        #base_deserted_boss_info{} ->
            [
                {born_handler, {?MODULE, boss_born_callback, ModuleArgs}},
                {hp_change_handler, {?MODULE, boss_hurt_callback, ModuleArgs}},
                {die_handler, {?MODULE, boss_die_callback, ModuleArgs ++ [BornTime]}},
                {origin, ?DROP_ORIGIN_DESERTED_BOSS}
            ];
        _ ->
            []
    end.

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

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

 pack_hurt_list(BossId, BossHp, HurtL) ->
 	HurtList = [pack_hurt_info(HurtInfo)|| HurtInfo <- HurtL],
    {ok, BinData} = pt_461:write(46103, [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, SvrNum, TeamLeaderName, Hurt};
 		{_, RoleId, SvrNum, Hurt, [#mon_atter{name = RoleName}|_]} when RoleId > 0 ->
 			{RoleId, 0, SvrNum, RoleName, Hurt};
 		_ ->
 			{0, 0, 0, <<>>, 0}
 	end.

 pack_mon_info(Level, BossInfos) ->
  	MonL = lists:foldl(fun(#deserted_boss_info{boss_id = BossId, reborn_time = RebornTime, last_killer = Name}, Acc) ->
 		case data_deserted_boss:get_boss_cfg(BossId) of
 			#base_deserted_boss_info{level = Level} ->
 				[{BossId, RebornTime, Name}|Acc];
 			_ ->
 				Acc
 		end
 	end, [], BossInfos),
 	MonL.

role_settlement(ClsType, BossId, BossType, MaxHurtRoles, SupportKlist) ->
    {SupportNum, TeamRoleNum} = calc_top_hurt_support_num(MaxHurtRoles, SupportKlist),
    AllHurt = lists:sum([HurtX || #mon_atter{hurt = HurtX} <- MaxHurtRoles]),
    [begin 
        {HurtPercent, Rank} = calc_role_hurt_and_rank(RoleId, Hurt, AllHurt, MaxHurtRoles),
        role_settlement_do(ClsType, BossId, BossType, RoleId, {SupportNum, TeamRoleNum, HurtPercent, Rank})
    end || #mon_atter{id = RoleId, hurt = Hurt} <- MaxHurtRoles],
    ok.

%% TA数据统计-获取归属玩家的协助人数|队伍人数
calc_top_hurt_support_num(RoleList, SupportKlist) ->
    SupportNum = lists:foldl(fun(#mon_atter{support_id = SupportId}, AccNum) -> 
        case lists:keymember(SupportId, #mon_atter.id, RoleList) of
            true -> AccNum+1;
            _    -> AccNum
        end
    end, 0, SupportKlist),
    {SupportNum, length(RoleList)}.

%% TA数据统计-获取归属玩家的伤害百分比&伤害排名
calc_role_hurt_and_rank(RoleId, RoleHurt, AllHurt, RoleList) ->
    HurtPercent = round(RoleHurt/AllHurt*100),
    SortList = lists:keysort(#mon_atter.hurt, RoleList),
    {_, Rank} = lists:foldr(fun(#mon_atter{id = AtterId}, {HaveFind, Acc}) -> 
        if HaveFind == true -> {HaveFind, Acc};
            true ->
                if AtterId == RoleId -> {true, Acc};
                    true -> {HaveFind, Acc+1}
                end
        end
    end, {false, 1}, SortList),
    {HurtPercent, Rank}.

role_settlement_do(ClsType, BossId, BossType, RoleId, {SupportNum, TeamRoleNum, HurtPercent, Rank}) ->
    if
        ClsType == ?NODE_GAME   -> Node = node();
        ClsType == ?NODE_CENTER -> Node = clusters_center:get_node_by_role_id(RoleId);
        true -> Node = undefined
    end,
     lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE,
      ?MODULE, role_boss_die_handle, [BossId, BossType, {SupportNum, TeamRoleNum, HurtPercent, Rank}]).


 add_log([ClsType, ZoneId, FacId, RoleName, _RoleId, SvrNum, Scene, BossId, GoodsId, Time|_]) ->
    Log = #boss_drop_log{
        name = RoleName, scene = Scene, svr_num = ?IF(ClsType == ?NODE_CENTER, SvrNum, 0),
        boss = BossId, boss_type = ?MON_DESERTED_BOSS, goods_id = GoodsId, time = Time
    },
    if ClsType == ?NODE_CENTER ->
            deserted_boss_sup:zone_fac_apply_cast(ZoneId, FacId, reward_boss_mgr, add_reward_boss_drop_log, [Log]);
        true ->
            reward_boss_mgr:add_reward_boss_drop_log(Log)
    end,
    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.

calc_open_day(?NODE_CENTER, ClsOpenTime) ->
    utime:day_span(utime:unixtime(), ClsOpenTime);
calc_open_day(?NODE_GAME, _) ->
    util:get_open_day().

get_boss_scene(ClsType, MonId) ->
    case data_deserted_boss:get_boss_cfg(MonId) of
        #base_deserted_boss_info{level = Level} ->
            case data_deserted_boss:get_level(Level) of
                #base_deserted_level{scene = Scene, cls_scene = ClsScene} ->
                    if ClsType  == ?NODE_CENTER -> ClsScene;
                        ClsType == ?NODE_GAME   -> Scene
                    end;
                _ -> false
            end;
        _ -> false
    end.

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

%% 发起协助请求
mon_proc_add_support_asker(MonState, [RoleId|_] = RoleInfo) ->
    #ob_act{klist = KList, general_driven = GeneralDriven} = MonState,
    NewKList = case lists:keyfind(RoleId, #mon_atter.id, KList) of
        #mon_atter{} -> KList;
        _   ->
            [
                RoleId, RoleName, RolePid, SvrId, Node, 
                TeamId, TeamLeaderName, GuildId, RoleLv, Career | _
            ] = RoleInfo,
            NewRole = #mon_atter{
                id = RoleId, name = RoleName, pid = RolePid, server_id = SvrId, 
                node = Node, team_id = TeamId, team_leader_name = TeamLeaderName,
                guild_id= GuildId, att_sign = ?BATTLE_SIGN_PLAYER, 
                att_lv = RoleLv, att_career = Career, time = utime:unixtime()
            },
            lists:keystore(RoleId, #mon_atter.id, KList, NewRole)
    end,
    NewGeneralDriven =
    case mon_state_util:check_member_driven_info('hurt_remove', GeneralDriven) of
        true    -> GeneralDriven;
        false   -> 
            if NewKList =/= [] ->
                    DelayDrivenInfo = [{3000, 'hurt_remove'}],
                    mon_state_util:update_general_driven(GeneralDriven, DelayDrivenInfo);
                true ->
                    GeneralDriven
            end
    end,
    MonState#ob_act{general_driven = NewGeneralDriven, klist = NewKList}.

%% 同意协助
mon_proc_role_supporting(MonState, RoleId) ->
	#ob_act{klist = KList} = MonState,
	NewKList = lists:keydelete(RoleId, #mon_atter.id, KList),
	NewState = MonState#ob_act{klist = NewKList},
	if NewKList =/= KList ->
			restat_when_hurt_change(NewState);
		true ->
			NewState
	end.

%% 协助者取消协助清除仇恨伤害
mon_proc_cancel_support(MonState, RoleId) ->
    #ob_act{support_klist = SupportList, klist = Klist} = MonState,
    % {NewSupportList, NewKlist} = mod_mon_active:calc_hurt_support_role_leave(RoleId, Klist, SupportList),
    {NewSupportList, NewKlist} = mon_state_logic:calc_hurt_support_role_leave(RoleId, Klist, SupportList),
    NewState = MonState#ob_act{support_klist = NewSupportList, klist = NewKlist},
    case NewKlist =/= Klist of
        true  -> restat_when_hurt_change(NewState);
        false -> NewState
    end.

%% 检测复活坐标与怪物距离
mon_proc_role_revive(MonState, RoleId, Node, Scene, ScenePool, CopyId, X, Y) ->
	#ob_act{object = SceneObj, klist = KList, support_klist = SupportList, 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, mon = #scene_mon{boss = BossType}} = SceneObj,
	if
		MonSceneId == Scene andalso MonScenePool == ScenePool
		 andalso CopyId == MonCopyId ->
			case abs(Dx - X) =< TraceDistance andalso abs(Dy - Y) =< TraceDistance of
				true ->
					MonState;
				_ -> %% 复活已超追踪距离
					{NewKList, NewSupportList} = mon_state_logic:calc_deserted_support_role_leave(KList, SupportList, [RoleId]),
					NewKList1 = lists:keydelete(RoleId, #mon_atter.id, NewKList),
					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),
					leave_boss_distance_trigger([RoleId], BossType, MonId),
					%% 脱战通知
					lib_server_send:send_to_uid(Node, RoleId, pt_461, 46105, [MonId]),
					NewMonState = MonState#ob_act{klist = NewKList1, support_klist = NewSupportList, 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, Sid, Node) ->
	#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(BossId, Hp, HurtL),
	lib_server_send:send_to_sid(Node, Sid, BinData),
	MonState.

%% 重新计算仇恨列表
restat_when_hurt_change(MonState) ->
	#ob_act{klist = KList, object = SceneObj} = MonState,
	#scene_object{
		config_id = _BossId % d_x = DX, d_y = DY, scene = SceneId, scene_pool_id = ScenePool,
		% copy_id = CopyId, battle_attr = #battle_attr{hp = Hp}
	} = SceneObj,
	NewKList = stat_hurt_list(KList),
	%% 广播
	% BinData = pack_hurt_list(BossId, Hp, NewKList),
	% lib_server_send:send_to_area_scene(SceneId, ScenePool, CopyId, DX, DY, BinData)
	MonState#ob_act{hurt_stat_list = NewKList}.


%% 被协助者脱离boss范围触发协助取消
leave_boss_distance_trigger(LeaveIds, _BossType, MonId) ->
    ClsType = config:get_cls_type(),
	lists:map(fun(Id) ->
        if ClsType == ?NODE_GAME -> Node = node();
            true -> Node = clusters_center:get_node_by_role_id(Id)
        end,
		lib_player:apply_cast(Node, Id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, role_support_cancel_check, [MonId])
	end, LeaveIds).

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

boss_born_callback(init, Minfo, [ClsType, ZoneId, FacId|_]) ->
    #scene_object{id = MonId, config_id = BossId} = Minfo,
    MonMgrPid = self(),
    Msg = {boss_born, BossId, MonMgrPid, MonId},
    if ClsType == ?NODE_CENTER ->
            deserted_boss_mgr:cast(ZoneId, FacId, Msg);
        ClsType == ?NODE_GAME ->
            gen_server:cast(deserted_boss_mgr, Msg);
        true ->
            skip
    end,
    ok;
boss_born_callback(_, _, _) ->
    ok.

boss_hurt_callback(ObjState = #ob_act{object = MonInfo, klist = KList = [TrueAtter|_], 
 support_klist = SupporKlist, hurt_stat_list = HurtList}, MonAtter, [ClsType|_]) ->
    #scene_object{
        mon = #scene_mon{mid = BossId}, battle_attr = #battle_attr{hp = Hp}} = MonInfo,
    #mon_atter{support_id = SupportId, node = SupporterNode, hurt = Hurt} = MonAtter,
    TrueAtter1 = TrueAtter#mon_atter{hurt = Hurt},
    NewHurtList = update_hurt_list(ClsType, TrueAtter1, HurtList),
    F = fun({_, _, _, HurtA, _}, {_, _, _, HurtB, _}) -> HurtA > HurtB end,
    SortedHurtList = lists:sort(F, NewHurtList),
    BinData = pack_hurt_list(BossId, Hp, SortedHurtList),
    [lib_server_send:send_to_uid(Node, RoleId, BinData) || #mon_atter{id = RoleId, node = Node} <- KList ++ SupporKlist],
    if
        SupportId > 0 ->
            case SupporKlist of
                [#mon_atter{id = Id, name = Name, hurt = SupportHurt}|_] ->
                    {ok, BinData1} = pt_461:write(46104, [BossId, Id, Name, SupportHurt]),
                    lib_server_send:send_to_uid(SupporterNode, SupportId, BinData1);
                _ -> ok
            end;
        true -> ok
    end,
    ObjState#ob_act{hurt_stat_list = NewHurtList};
boss_hurt_callback(_, _, _) ->
    ok.

boss_die_callback(#ob_act{object = Minfo = #scene_object{mon = #scene_mon{boss = ?MON_DESERTED_BOSS, mid = BossId}},
    support_klist = SupportKlist},
    [#mon_atter{name = Name, server_id = SvrId}|_] = KList, Atter, _AtterSign,
    [ClsType, ZoneId, FacId, BornTime|_]) ->
    #scene_object{scene = SceneId, scene_pool_id = ScenePool} = Minfo,
    {Args, RoleIds, MaxHurtRoles} = calc_max_hurt_roles(KList),
    not_max_hurt_roles_notice(RoleIds, KList),
    Msg    = {boss_die, BossId, ?MON_DESERTED_BOSS, BornTime, SvrId, Name, SceneId, ScenePool},
    BossName = case data_mon:get(BossId) of
        #mon{name = BName, lv = BossLv} -> BName;
        _                  -> BossLv = 0, <<>>
    end,
    #battle_return_atter{id = KillerId, real_name = KillName, lv = KillLv, server_id = KillSvrId} = Atter,
    NowTime = utime:unixtime(),
    role_settlement(ClsType, BossId, ?MON_DESERTED_BOSS, MaxHurtRoles, SupportKlist),
    if ClsType == ?NODE_CENTER ->
            SvrNum = clusters_center:find_server_num(SvrId),
            TVArgs = [{all}, ?MOD_DESERTED_BOSS, 4, [SvrNum] ++ Args ++ [BossName]],
            Mfa    = {lib_chat, send_TV, TVArgs},
            deserted_boss_sup:zone_fac_apply_cast(ZoneId, FacId, Mfa),
            deserted_boss_mgr:cast(ZoneId, FacId, Msg),
            RoleIds1 = calc_max_hurt_roles_1(KList),
            KillSvrNum = clusters_center:find_server_num(KillSvrId),
            lib_log_api:log_boss_belong([KillerId, KillName, ClsType, KillSvrNum, KillLv, ?MON_DESERTED_BOSS, BossLv, BossId, RoleIds1, 0, NowTime]);
        ClsType == ?NODE_GAME ->
            lib_chat:send_TV({all}, ?MOD_DESERTED_BOSS, 2, Args ++ [BossName]),
            gen_server:cast(deserted_boss_mgr, Msg),
            KillSvrNum = config:get_server_num(),
            lib_log_api:log_boss_belong([KillerId, KillName, ClsType, KillSvrNum, KillLv, ?MON_DESERTED_BOSS, BossLv, BossId, RoleIds, 0, NowTime]);
        true ->
            skip
    end,
    ok;
boss_die_callback(#ob_act{object = #scene_object{mon = #scene_mon{mid = BossId, boss = ?MON_DESERTED_ELITE, create_key = CreateKey}, scene = Scene, scene_pool_id = ScenePool}},
 KList, Atter, _AtterSign, [ClsType, ZoneId, FacId, BornTime|_]) ->
    {_Args, RoleIds, MaxHurtRoles} = calc_max_hurt_roles(KList),
    {_, MonIndex} = CreateKey,
    Msg = {elite_mon_die, BossId, ?MON_DESERTED_ELITE, MonIndex, BornTime},
    #battle_return_atter{id = KillerId, real_name = KillName, lv = KillLv, server_id = KillSvrId} = Atter,
    case data_mon:get(BossId) of
        #mon{lv = BossLv} -> ok;
        _   -> BossLv = 0
    end,
    if length(RoleIds) > 3 ->
            RoleIds1 = ulists:sublist(3, RoleIds);
        true ->
            RoleIds1 = RoleIds
    end,
    NowTime = utime:unixtime(),
    role_settlement(ClsType, BossId, ?MON_DESERTED_ELITE, MaxHurtRoles, []),
    mod_scene_agent:apply_cast_scene_user(Scene, ScenePool, 0, ?MODULE, role_notice_elite_info, [MonIndex, 0]),
    if ClsType == ?NODE_CENTER ->
            deserted_boss_mgr:cast(ZoneId, FacId, Msg),
            KillSvrNum = clusters_center:find_server_num(KillSvrId),
            lib_log_api:log_boss_belong([KillerId, KillName, ClsType, KillSvrNum, KillLv, ?MON_DESERTED_BOSS, BossLv, BossId, RoleIds1, 0, NowTime]);
        ClsType == ?NODE_GAME ->
            gen_server:cast(deserted_boss_mgr, Msg),
            KillSvrNum = config:get_server_num(),
            lib_log_api:log_boss_belong([KillerId, KillName, ClsType, KillSvrNum, KillLv, ?MON_DESERTED_BOSS, BossLv, BossId, RoleIds1, 0, NowTime]);
        true ->
            skip
    end,
    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.

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.


% find_server_num(ServerId)
update_hurt_list(ClsType, Atter, HurtList) ->
    #mon_atter{id = RoleId, team_id = TeamId, hurt = Hurt, server_id = SvrId} = Atter,
    SvrNum = ?IF(ClsType == ?NODE_GAME, 0, clusters_center:find_server_num(SvrId)),
    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.

not_max_hurt_roles_notice(RoleIds, KList) ->
    {ok, BinData} = pt_461:write(46114, []),
    lists:map(fun(#mon_atter{id = MonAtterId, node = Node, support_id = SupportId}) -> 
        case lists:member(MonAtterId, RoleIds) of
            false when SupportId == 0 -> %% 有伤害的非第一非协助的玩家
                lib_server_send:send_to_uid(Node, MonAtterId, BinData);
            _A -> skip
        end
    end, KList).

%% --------------- 场景进程 ---------------------

%% 协助者没有协助攻击指定BOSS
%% 取消协助状态
supporter_attack_check(DerSign, Aer) ->
	#battle_status{id = Id, node = Node, sign = AttSign, scene = Scene, support_id = SupportId} = Aer,
	IsDesertedBossScene = local_boss_api:is_deserted_boss_scene(Scene),
	if
		AttSign == ?BATTLE_SIGN_PLAYER andalso DerSign == ?BATTLE_SIGN_MON andalso IsDesertedBossScene andalso SupportId > 0 ->
			lib_player:apply_cast(Node, Id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_guild_support_mod, cancel_support, []);
		true ->
			skip
	end.


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

role_support_cancel_check(Player, BossId) ->
	#player_status{
		id= RoleId,
		guild = #status_guild{
			id = GuildId,
			support_id = SupportUniqueId,
			is_support_asker = IsAsker,
			is_in_support = IsInSupport}
	} = Player,
	if IsAsker == 1 andalso IsInSupport == 1 ->
			mod_guild_support:apply_cast(guild_support_deserted_boss, guild_proc_support_cancel_check, [RoleId, GuildId, BossId, SupportUniqueId]);
		true ->
			skip
	end,
	ok.

role_boss_die_handle(Player, BossId, ?MON_DESERTED_BOSS, {SupportNum, TeamRoleNum, HurtPercent, Rank}) ->
	#player_status{id = RoleId, guild = Guild, figure = #figure{name = RoleName},
	 local_boss = #status_local_boss{deserted_boss_tired = BossTired, deserted_elite_tired = EliteTired} = LocalBoss
	} = Player,
	%% 触发击杀废都幻魔任务
	phantom_task_api:kill_deserted_boss_trigger(RoleId),
	case Guild of
		#status_guild{id = GuildId, support_id = Sid, is_in_support = IsInSupport, is_support_asker = IsAsker} ->
			if (IsInSupport == 1 andalso IsAsker == 1) orelse IsInSupport == 0 ->
					%% 刷新疲劳值
					UniteNum  = custom_unite_buff:check_times(Player,boss_refresh,?MON_DESERTED_BOSS),
					case UniteNum>0 of
						true->
							custom_unite_buff:cost_times(Player,boss_refresh,?MON_DESERTED_BOSS),
            				custom_unite_buff:scene_cost_times(Player,boss_refresh,?MON_DESERTED_BOSS),
                            NewBossTired = BossTired,
                            lib_log_api:log_boss_change([RoleId, RoleName, ?MON_DESERTED_BOSS, NewBossTired, BossTired, 5, BossId, utime:unixtime()]);
            			_->
							NewBossTired = BossTired + 1,
                            lib_log_api:log_boss_change([RoleId, RoleName, ?MON_DESERTED_BOSS, NewBossTired, BossTired, 1, BossId, utime:unixtime()])
					end,
					lib_daily:set_count(RoleId, ?MOD_DESERTED_BOSS, 1, NewBossTired),
					IsInSupport == 1 andalso IsAsker == 1 andalso
					 mod_guild_support:apply_cast(guild_support_deserted_boss, guild_proc_finish_support, [RoleId, GuildId, BossId, Sid]),
					NewLocalBoss = LocalBoss#status_local_boss{deserted_boss_tired = NewBossTired},
					NewPlayer = Player#player_status{local_boss = NewLocalBoss},
					mod_scene_agent:update(NewPlayer, [{deserted_boss_tired, {NewBossTired, EliteTired}}]),
					local_boss_api:notify_boss_tired(deserted_boss_tired, NewPlayer),
					lib_activitycalen_api:role_success_end_activity(RoleId,?MOD_DESERTED_BOSS,1),
					mod_hi_point:success_end(RoleId, ?MOD_DESERTED_BOSS, 1),
					custom_act_adventure:do_trigger_adventure_task(RoleId, ?MOD_DESERTED_BOSS, 1),
					lib_custom_act_slices:task_event(NewPlayer, ?MOD_DESERTED_BOSS, 1),
					NewPlayer2 = lib_role_legion:trigger_task(NewPlayer,?MOD_DESERTED_BOSS,1),
					custom_act_journey:trigger_act_task(NewPlayer2,boss,1),
					lib_achievement_api:deserted_boss_event(NewPlayer2, 1),
					lib_elite_assess_api:deserted_boss_event(NewPlayer2, BossId),
					custom_act_mobilize:update_mobilize_task(NewPlayer2, killboss, 1),
                    NewPlayer3 = equipment_logic:kill_deserted_boss(NewPlayer2),
                    NewPlayer4 = deserted_boss_ta_data(NewPlayer3, BossId, ?MON_DESERTED_BOSS, {SupportNum, TeamRoleNum, HurtPercent, Rank}),
					{ok, NewPlayer4};
				true ->
					ok
			end;
		_ ->
			ok
	end;
role_boss_die_handle(Player, BossId, ?MON_DESERTED_ELITE, {SupportNum, TeamRoleNum, HurtPercent, Rank}) ->
    #player_status{id = RoleId, figure = #figure{name = RoleName},
	 local_boss = #status_local_boss{deserted_boss_tired = BossTired, deserted_elite_tired = EliteTired} = LocalBoss
	} = Player,
	NewEliteTired = EliteTired + 1,
	lib_daily:set_count(RoleId, ?MOD_DESERTED_BOSS, 2, NewEliteTired),
	NewLocalBoss = LocalBoss#status_local_boss{deserted_elite_tired = NewEliteTired},
	NewPlayer = Player#player_status{local_boss = NewLocalBoss},
	mod_scene_agent:update(NewPlayer, [{deserted_boss_tired, {BossTired, NewEliteTired}}]),
	local_boss_api:notify_boss_tired(deserted_boss_tired, NewPlayer),
	lib_activitycalen_api:role_success_end_activity(RoleId,?MOD_DESERTED_BOSS,2),
	mod_hi_point:success_end(RoleId, ?MOD_DESERTED_BOSS, 2),
	custom_act_adventure:do_trigger_adventure_task(RoleId, ?MOD_DESERTED_BOSS, 2),
    NewPlayer1 = lib_role_legion:trigger_task(NewPlayer, ?MOD_DESERTED_BOSS, 2),
	NewPlayer2 = NewPlayer1,
	lib_achievement_api:deserted_elite_event(NewPlayer2, 1),
    lib_log_api:log_boss_change([RoleId, RoleName, ?MON_DESERTED_ELITE, NewEliteTired, EliteTired, 1, BossId, utime:unixtime()]),
    NewPlayer3 = deserted_boss_ta_data(NewPlayer2, BossId, ?MON_DESERTED_ELITE, {SupportNum, TeamRoleNum, HurtPercent, Rank}),
    {ok, NewPlayer3}.


role_notice_mon_info(Player, MonL) ->
	#player_status{sid = Sid, local_boss = LocalBoss} = Player,
	#status_local_boss{boss_focus = BossFocus} = LocalBoss,
	case lists:keyfind(?MON_DESERTED_BOSS, 1, BossFocus) of
		{_, FocusL} -> ok;
		_ -> FocusL = []
	end,
	MonInfos = lists:foldl(fun({BossId, RebornTime, Name}, Acc) ->
		case lists:member(BossId, FocusL) of
			true -> [{BossId, RebornTime, 1, Name}|Acc];
			_ 	 -> [{BossId, RebornTime, 0, Name}|Acc]
		end
	end, [], MonL),
	{ok, BinData} = pt_461:write(46101, [MonInfos]),
	lib_server_send:send_to_sid(Sid, BinData),
	{ok, Player}.

role_notice_elite_info(Player, Index, Alive) ->
    {ok, Bin} = pt_461:write(46110, [Index, Alive]),
    lib_server_send:send_to_sid(Player#player_status.sid, Bin),
    {ok, Player}.

deserted_boss_ta_data(Player, BossId, BossType, {SupportNum, TeamRoleNum, HurtPercent, Rank}) ->
    #player_status{local_boss = StatusLocBoss, id = RoleId} = Player,
    #status_local_boss{ta_data = TAData} = StatusLocBoss,
    BossTAData  = maps:get(?MON_DESERTED_BOSS, TAData, #{}),
    ReviveCount = maps:get(?REVIVE_TIME, BossTAData, 0),
    EnterTime   = maps:get(?ENTER_TIME, BossTAData, 0),
    LeftCount = lib_counter:get_count(RoleId, ?MOD_LOCAL_BOSS, ?COUNT_REWARD_BOSS_COUNTER_KILL, BossId),
    IsFirstKill = ?IF(LeftCount == 0, true, false),
    case data_deserted_boss:get_boss_cfg(BossId) of
        #base_deserted_boss_info{grade = Grade} -> ok;
        _ -> Grade = 0
    end,
    case data_mon:get(BossId) of
        #mon{lv = BossLv} -> ok;
        _ -> BossLv = 0
    end,
    Now = utime:unixtime(),
    ta_agent_fire:ta_deserted_boss_belong(Player, [BossType, BossId, BossLv, Grade, IsFirstKill, ReviveCount, TeamRoleNum, SupportNum,
        HurtPercent, Rank, round(Now - EnterTime)]),
    Player1 = local_boss_api:kill_boss_refresh_ta_data(Player, ?MON_DESERTED_BOSS, Now),
    lib_counter:increment(RoleId, ?MOD_LOCAL_BOSS, ?COUNT_REWARD_BOSS_COUNTER_KILL, BossId),
    Player1.

%% ------------------------ 游戏服接口 -----------------------------
local_init(State) ->
    MonData = db:get_all(?SQL_GET_LOCAL_DESERTED_BOSS_STATUS, [?MON_DESERTED_BOSS]),
    MonList = [list_to_tuple(Mon) || Mon <- MonData],
    MonIds  = data_deserted_boss:get_all_boss(),
    Now     = utime:unixtime(),
    OpenDay = util:get_open_day(),
    ClsType = config:get_cls_type(),
    BossInfos =
    [begin
        [{_Level, {X, Y}, RebornList}|_] = data_deserted_boss:get_boss_key_info(MonId),
        RebornTime = get_reborn_time(OpenDay, RebornList),
        case lists:keyfind(MonId, 1, MonList) of
            {_, DeadTime, Killer} ->
                NextTime = DeadTime + RebornTime,
                if NextTime > Now ->
                        Ref = erlang:send_after((NextTime - Now)*1000, self(), {create_deserted_boss, MonId, X, Y}),
                        NextTime1 = NextTime;
                    true ->
                        Ref = undefined, NextTime1 = 0,
                        create_deserted_boss([ClsType, 0, 0, MonId, X, Y])
                end;
            _ ->
                Ref = undefined, NextTime1 = 0,
                create_deserted_boss([ClsType, 0, 0, MonId, X, Y]),
                Killer = <<>>
        end,
        #deserted_boss_info{boss_id = MonId, reborn_time = NextTime1, last_killer = Killer, ref_reborn = Ref}
    end || MonId <- MonIds
    ],
    EliteMonInfo =
        [begin
             create_elite_mon([ClsType, EliteMonIndex]),
             {{EliteMonIndex, EliteMonId}, 1}
         end  || {EliteMonIndex, EliteMonId} <- data_deserted_boss:get_mon_index()],
    NewState = State#deserted_boss_state{boss_info = BossInfos, cls_type = ClsType, elite_mon_info = EliteMonInfo},
    NewState.