%%%-------------------------------------------------------------------
%%% @doc    废土战场(饥饿游戏)-跨服中心管理进程
%%% Module  : mod_wasteland_war.erl
%%% Created : 2020-08-03
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(mod_wasteland_war).

-include("common.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("errcode.hrl").
-include("def_module.hrl").
-include("predefine.hrl").
-include("wasteland_war.hrl").
-include("def_goods.hrl").
-include("goods.hrl").

%% API
-export([
	start_link/0, recalc_zone/1, act_start/1, act_status/2, sync_status/2, enter_scene/7, quit_scene/3, host_login/3, fetch_score_rank/3,
	create_dummy/3, kill_player/6, hurt_player/4, assist_kill_player/4, kill_crystal/3, record_die_state/3, clean_die_state/3,
	power_change/4, figure_change/5, reconnect/3, notice_round/3, push_role_score_rank/2, notice_act_change_local/2, notice_act_end_local/3
	,notice_combo_tv_local/1, notice_end_combo_tv_local/1, gm_start/1, gm_end/0
]).

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


%% 活动状态
act_status(Node, RoleId) ->
	gen_server:cast(?MODULE, {'act_status', Node, RoleId}).

%% 开放活动
act_start(SubAct) ->
	gen_server:cast(?MODULE, {'act_start', SubAct}).

%% 活动状态改变(跨服推送给游戏服消息，游戏服自己做判断是否推送给玩家)
notice_act_change_local(Stage, StartTime) ->
	gen_server:cast(?MODULE, {'notice_act_change_local', Stage, StartTime}).

%% 活动结束推送(跨服推送给游戏服消息，游戏服自己做判断是否推送给玩家)
notice_act_end_local(ServerNum, RoleName, WarField) ->
	gen_server:cast(?MODULE, {'notice_act_end_local', ServerNum, RoleName, WarField}).

%% 连杀推送(跨服推送给游戏服消息，游戏服自己做判断是否推送给玩家)
notice_combo_tv_local(MFA) ->
	gen_server:cast(?MODULE, {'notice_combo_tv_local', MFA}).

%% 终结连杀推送(跨服推送给游戏服消息，游戏服自己做判断是否推送给玩家)
notice_end_combo_tv_local(MFA) ->
	gen_server:cast(?MODULE, {'notice_end_combo_tv_local', MFA}).

%% 跨服同步状态到游戏服
sync_status(Status, SubAct) ->
	gen_server:cast(?MODULE, {'sync_status', Status, SubAct}).

%% 排行数据上报,上报后销毁分区进程(暂时未使用)
push_role_score_rank(ZoneId, SyncList) ->
	gen_server:cast(?MODULE, {'push_role_score_rank', ZoneId, SyncList}).

%% 查询排行榜数据
fetch_score_rank(Node, RoleId, ServerId) ->
	gen_server:cast(?MODULE, {'fetch_score_rank', Node, RoleId, ServerId}).

%% 进入场景
enter_scene(Node, RoleId, Figure, ServerId, ServerNum, IsHosting, HpLim) ->
	gen_server:cast(?MODULE, {'enter_scene', Node, RoleId, Figure, ServerId, ServerNum, IsHosting, HpLim}).

%% 退出场景
quit_scene(Node, ServerId, RoleId) ->
	gen_server:cast(?MODULE, {'quit_scene', Node, ServerId, RoleId}).

%% 断线重连
reconnect(Node, ServerId, RoleId) ->
	gen_server:cast(?MODULE, {'reconnect', Node, ServerId, RoleId}).

%% 托管玩家登录
host_login(Node, ServerId, RoleId) ->
	gen_server:cast(?MODULE, {'host_login', Node, ServerId, RoleId}).

%% 假人创建,记录数据
create_dummy(ServerId, RoleId, MonId) ->
	gen_server:cast(?MODULE, {'create_dummy', ServerId, RoleId, MonId}).

%% 跨服通知进入混战阶段,托管玩家自由战斗 @doc IMPORTANT

%% 重新分区后(暂时不考虑)
recalc_zone(Map) ->
	gen_server:cast(?MODULE, {'recalc_zone', Map}).

%% 战力变更
power_change(Node, RoleId, ServerId, Power) ->
	gen_server:cast(?MODULE, {'power_change', Node, RoleId, ServerId, Power}).

%% 形象数据变更
figure_change(Node, RoleId, ServerId, Type, ChangeValue) ->
	gen_server:cast(?MODULE, {'figure_change', Node, RoleId, ServerId, Type, ChangeValue}).

%% 成功切换场景之后推送当前轮数
notice_round(Node, ServerId, RoleId) ->
	gen_server:cast(?MODULE, {'notice_round', Node, ServerId, RoleId}).

gm_start(SubAct) ->
	gen_server:cast(?MODULE, {'act_start', SubAct}).

gm_end() ->
	gen_server:cast(?MODULE, {'gm_end'}).

%% -------------------------------
%% 玩法中才会触发的协议
%% 击杀玩家
kill_player(Node, SceneId, KillId, BeKillId, BeKillSrvId, HurtList) ->
	case lib_wasteland_war:is_in_wasteland_scene(SceneId) of
		true ->
			gen_server:cast(?MODULE, {'kill_player', Node, SceneId, KillId, BeKillId, BeKillSrvId, HurtList});
		_ ->
			ignore
	end.

%% 触发伤害(已废弃)
hurt_player(SceneId, HurtId, BeHurtId, BeHurtSrvId) ->
	case lib_wasteland_war:is_in_wasteland_scene(SceneId) of
		true ->
			gen_server:cast(?MODULE, {'hurt_player', HurtId, BeHurtId, BeHurtSrvId});
		_ ->
			ignore
	end.

%% 助攻杀人(已废弃)
assist_kill_player(SceneId, KillId, BeKillId, BeKillSrvId) ->
	case lib_wasteland_war:is_in_wasteland_scene(SceneId) of
		true ->
			gen_server:cast(?MODULE, {'assist_kill_player', KillId, BeKillId, BeKillSrvId});
		_ ->
			ignore
	end.

%% 击杀水晶
kill_crystal(Node, KillId, ServerId) ->
	gen_server:cast(?MODULE, {'kill_crystal', Node, KillId, ServerId}).

%% 死亡,记录死亡状态
record_die_state(Node, ServerId, RoleId) ->
	gen_server:cast(?MODULE, {'record_die_state', Node, ServerId, RoleId}).

%% 复活,清除死亡状态
clean_die_state(Node, ServerId, RoleId) ->
	gen_server:cast(?MODULE, {'clean_die_state', Node, ServerId, RoleId}).

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

%%cast(Msg) ->
%%	gen_server:cast(?MODULE, Msg).
%%
%%call(Msg) ->
%%	gen_server:call(?MODULE, Msg).
%%
%%info(Msg) ->
%%	erlang:send(?MODULE, Msg).

init([]) ->
	process_flag(trap_exit, true),
	case config:get_cls_type() of
		1 ->
			SrvZoneMap = czone:get_svr_zone_map();
		_ ->
			ServerId   = config:get_server_id(),
			SrvZoneMap = #{ServerId => 1}
	end,
	State = #wasteland_war_state{srv_zone_map = SrvZoneMap},
	{ok, State}.

handle_call(Msg, From, State) ->
	try do_handle_call(Msg, From, State) of
		Reply ->
			Reply
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_call error:~p~n", [?MODULE, Error]),
		{error, Reason}
	end.

handle_cast(Msg, State) ->
	try do_handle_cast(Msg, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_cast error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

handle_info(Info, State) ->
	try do_handle_info(Info, State) of
		Result ->
			Result
	catch ?EXCEPTION(Class, Reason, StackTrace) ->
		Error = {Class, Reason, StackTrace},
		?ERR("~w:handle_info error:~p~n", [?MODULE, Error]),
		{noreply, State}
	end.

terminate(_Reason, _State) ->
	ok.

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

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

%% ---------------------------------------------------------------------------
do_handle_cast({'recalc_zone', CBMap}, State)->
	#{svr_zone_map := IndexDict} = CBMap,
	{noreply, State#wasteland_war_state{srv_zone_map = IndexDict}};

%% 活动状态
do_handle_cast({'act_status', Node, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, start_time = StartTime} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, act_status, [Node, RoleId]);
		_ ->
			case config:get_cls_type() of
				0 -> ActType = 1;
				_ -> ActType = 2
			end,
			lib_wasteland_war:send_to_client(Node, RoleId, 60200, [Stage, StartTime, ActType])
	end,
	{noreply, State};

%% 推送活动变更(由跨服控制通知本服,本服需要判断条件来推送。
%% 前端在玩法场景外没有屏蔽,需要服务端多一步发送到管理进程来判断)
do_handle_cast({'notice_act_change_local', Stage, StartTime}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			lib_wasteland_war:notice_act_change_local(Stage, StartTime);
		_ ->
			ignore
	end,
	{noreply, State};

%% 活动结束推送(由跨服控制通知本服,本服需要判断条件来推送。
%% 前端在玩法场景外没有屏蔽,需要服务端多一步发送到管理进程来判断)
do_handle_cast({'notice_act_end_local', ServerNum, RoleName, WarField}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			lib_wasteland_war:notice_act_end_local(ServerNum, RoleName, WarField);
		_ ->
			ignore
	end,
	{noreply, State};

%% 连杀通知(由跨服控制通知本服,本服需要判断条件来推送。
%% 需要服务端多一步发送到管理进程来判断)
do_handle_cast({'notice_combo_tv_local', MFA}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			lib_wasteland_war:notice_combo_tv_local(MFA);
		_ ->
			ignore
	end,
	{noreply, State};

%% 终结连杀通知(由跨服控制通知本服,本服需要判断条件来推送。
%% 需要服务端多一步发送到管理进程来判断)
do_handle_cast({'notice_end_combo_tv_local', MFA}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			lib_wasteland_war:notice_end_combo_tv_local(MFA);
		_ ->
			ignore
	end,
	{noreply, State};

do_handle_cast({'act_start', SubAct}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, zone_work_map = OldWorkerMap,
		round_ref = OldRoundRef, crystal_ref = CryRef
	} = State,
	%% 如果是跨服开了，游戏服就不开
	CanOpen = case config:get_cls_type() of
		          0 when IsOpen == true -> false;
		          _ -> true
	          end,
	case Stage of
		?WASTELAND_REST when CanOpen == true ->
			%?INFO_TTY("PROC msg is ~w~n",[get()]),
			util:cancel_timer(OldRoundRef),
			util:cancel_timer(CryRef),
			case config:get_cls_type() of
				1 ->
					SrvZoneMap = czone:get_svr_zone_map();
				_ ->
					ZoneId   = 1,
					ServerId = config:get_server_id(),
					SrvZoneMap = #{ServerId => ZoneId}
			end,
			ZoneIds = lists:usort(maps:values(SrvZoneMap)),
			OldZoneIds = maps:keys(OldWorkerMap),
			%% 销毁旧的分区管理进程
			F0 = fun(TZoneId) ->
				case maps:get(TZoneId, OldWorkerMap, []) of
					WorkPid when is_pid(WorkPid) ->
						mod_wasteland_worker:close_worker(WorkPid);
					_ ->
						ignore
				end end,
			lists:foreach(F0, OldZoneIds),
			%% 每个分区创建一个管理进程
			F = fun(ZoneId, TWorkerMap) ->
				{_CrateTrue, Pid} = lib_wasteland_war:create_zone_worker(ZoneId),
				%% 创建失败通知分区所有人需要禁止进入
				TWorkerMap1 = maps:put(ZoneId, Pid, TWorkerMap),
				TWorkerMap1
			end,
			WorkerMap = lists:foldl(F, #{}, ZoneIds),
			%% 分区管理进程创建之后再开始托管
			% lib_wasteland_war:end_hosting(SrvZoneMap),
			lib_wasteland_war:start_hosting(SrvZoneMap),
			%% 开启定时器,进入混战阶段
			[{_, ReadyWaitTime}, _] = data_wasteland_war:get_kv_cfg(stage_time),
			RoundRef = util:send_after([], ReadyWaitTime*1000, self(), {'calc_war_field'}),
			%% 清理所有数据 (清除上一轮排行榜)
			StartTime = utime:unixtime(),
			NewState = #wasteland_war_state{stage = ?WASTELAND_READY, round_ref = RoundRef,
			srv_zone_map = SrvZoneMap, zone_work_map = WorkerMap, start_time = StartTime},
			lib_wasteland_war:db_delete_rank(),
			%% 同步跨服玩法节奏到进入分区的服
			case config:get_cls_type() of
				1 ->
					MFA = {?MODULE, sync_status, [1, SubAct]},
					cross_zone:apply_cast(czone, {cross_zone, proc_apply_to_zone, [all, MFA]}),
					lib_wasteland_war:notice_act_start(StartTime, IsOpen, SubAct);
				_ ->
					lib_wasteland_war:notice_act_start(StartTime, IsOpen, SubAct)
			end;
		_ ->
			NewState = State
	end,
	{noreply, NewState};

%% 同步跨服的玩法状态
do_handle_cast({'sync_status', Status, ActSub}, State) ->
	#wasteland_war_state{stage = Stage, zone_work_map = OldWorkerMap} = State,
	case config:get_cls_type() of
		1 ->
			NewState = State;
		_ ->
			%% 需要判断开服天数是否满足
			case czone_api:zone_open_check() of
				{true, _ZoneId} ->
					%% 需要判断满不满足配置里面的开服天数。
					%% 1. 如果游戏服先于跨服开放,屏蔽跨服的控制。
					%% 2. 跨服控制条件下(即IsOpen=true)，需要清空游戏服上一场的数据。
					IsLocalOpen = lib_wasteland_war:is_local_start(ActSub),
					case Status of
						1 when IsLocalOpen =:= true, Stage =:= ?WASTELAND_REST ->
							lib_wasteland_war:close_old_worker(OldWorkerMap),
							NewState = #wasteland_war_state{is_open = true};
						_ ->
							NewState = State#wasteland_war_state{is_open = false}
					end;
				_ ->
					NewState = State
			end
	end,
	{noreply, NewState};

%% gm结束玩法
do_handle_cast({'gm_end'}, State) ->
	#wasteland_war_state{round = Round, round_ref = OldRoundRef, crystal_ref = CryRef
		,srv_zone_map = SrvZoneMap, zone_work_map = WorkerMap
	} = State,
	util:cancel_timer(OldRoundRef),
	util:cancel_timer(CryRef),
	%% 结束托管，清理场景角色
	% lib_wasteland_war:end_hosting(SrvZoneMap),
	ZoneIds = lists:usort(maps:values(SrvZoneMap)),
	F = fun(ZoneId) ->
		case maps:get(ZoneId, WorkerMap, []) of
			WorkPid when is_pid(WorkPid) ->
				mod_wasteland_worker:gm_end(WorkPid, Round);
			_ ->
				ignore
		end end,
	lists:foreach(F, ZoneIds),
	%% 通知所有游戏服活动关闭
	case config:get_cls_type() of
		1 ->
			MFA = {?MODULE, sync_status, [0, 0]},
			cross_zone:apply_cast(czone, {cross_zone, proc_apply_to_zone, [all, MFA]});
		_ ->
			ignore
	end,
	{noreply, State#wasteland_war_state{stage = ?WASTELAND_REST}};

%% 查询分战场积分排行榜
do_handle_cast({'fetch_score_rank', Node, RoleId, ServerId}, State) ->
	%% 重新分区可能分区已经变了,找不到对应的worker_pid
	%% 如果分区改变,旧的分区对应的管理进程还存在,也会找不到自己的数据
	#wasteland_war_state{is_open = IsOpen, zone_work_map = WorkerMap, srv_zone_map = SrvZoneMap} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, fetch_score_rank, [Node, RoleId, ServerId]);
		_ ->
			ZoneId = maps:get(ServerId, SrvZoneMap, 0),
			case maps:get(ZoneId, WorkerMap, []) of
				WorkerPid when is_pid(WorkerPid) ->
					Args = [Node, RoleId, ServerId],
					distribute(State, Node, RoleId, ServerId, fetch_score_rank, Args);
				_ ->
					%% 没有数据就去跨服找找吧(玩法结束后IsOpen标志为会清理为false)
					case ClsType of
						1 -> lib_wasteland_war:send_to_client(Node, RoleId, 60205, [[], 0, 0, 0, 0, 0]);
						_ -> clusters_node:apply_cast(mod_wasteland_war, fetch_score_rank, [Node, RoleId, ServerId])
					end
					% clusters_node:apply_cast(mod_wasteland_war, fetch_score_rank, [Node, RoleId, ServerId])
			end
	end,
	{noreply, State};

do_handle_cast({'enter_scene', Node, RoleId, Figure, ServerId, ServerNum, IsHosting, HpLim}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, round = Round} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			Args = [Node, RoleId, Figure, ServerId, ServerNum, IsHosting, HpLim],
			clusters_node:apply_cast(mod_wasteland_war, enter_scene, Args);
		_ ->
			%% 只有准备和战斗时间可以进入(同时这两个阶段分区管理进程才会存在)
			case Stage of
				?WASTELAND_READY ->
					Args = [Stage, Round, Node, RoleId, Figure, ServerId, ServerNum, IsHosting, HpLim],
					distribute(State, Node, RoleId, ServerId, enter_scene, Args);
				?WASTELAND_RUN ->
					Args = [Stage, Round, Node, RoleId, Figure, ServerId, ServerNum, IsHosting, HpLim],
					distribute(State, Node, RoleId, ServerId, enter_scene, Args);
				?WASTELAND_REST ->
					lib_wasteland_war:send_to_client(Node, RoleId, 60201, [?ERRCODE(err602_not_open)]);
				_ ->
					lib_wasteland_war:send_to_client(Node, RoleId, 60201, [?ERRCODE(err602_in_act)])
			end
	end,
	{noreply, State};

do_handle_cast({'quit_scene', Node, ServerId, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, quit_scene, [Node, ServerId, RoleId]);
		_ ->
			distribute(State, Node, RoleId, ServerId, quit_scene, [RoleId])
	end,
	{noreply, State};

%% 断线重连 {'reconnect', Node, ServerId, RoleId}
do_handle_cast({'reconnect', Node, ServerId, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, round = Round, round_end_time = RoundEndTime} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, reconnect, [Node, ServerId, RoleId]);
		_ ->
			Args = [Stage, Round, RoundEndTime, Node, RoleId],
			case Stage of
				?WASTELAND_REST ->
					lib_wasteland_war:switch_default_scene(Node, RoleId);
				_ ->
					distribute(State, Node, RoleId, ServerId, reconnect, Args)
			end
	end,
	{noreply, State};

%% 托管玩家上线登录
do_handle_cast({'host_login', Node, ServerId, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, round = Round} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, host_login, [Node, ServerId, RoleId]);
		_ ->
			case Stage of
				?WASTELAND_READY ->
					Args = [Round, RoleId],
					distribute(State, Node, RoleId, ServerId, host_login, Args);
				?WASTELAND_REST ->
					ignore;
				_ ->
					ignore
			end
	end,
	{noreply, State};

%% 创建假人
do_handle_cast({'create_dummy', ServerId, RoleId, MonId}, State) ->
	Args = [ServerId, RoleId, MonId],
	distribute(State, undefined, RoleId, ServerId, create_dummy, Args),
	{noreply, State};

%% 切换场景之后推送轮数 & 结晶数
% {'notice_round', Node, ServerId, RoleId}
do_handle_cast({'notice_round', Node, ServerId, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, round = Round, round_end_time = RoundEndTime} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, notice_round, [Node, ServerId, RoleId]);
		_ ->
			Args = [Stage, Round, RoundEndTime, Node, RoleId],
			distribute(State, Node, RoleId, ServerId, notice_round, Args)
	end,
	{noreply, State};

%% 注意:准备阶段战力变更,将影响分战区计算。
do_handle_cast({'power_change', Node, RoleId, ServerId, Power}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = _Stage} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, power_change, [Node, RoleId, ServerId, Power]);
		_ ->
			Args = [RoleId, ServerId, Power],
			distribute(State, Node, RoleId, ServerId, power_change, Args)
	end,
	{noreply, State};

%% 玩家形象改变,排行榜数据相应改变  figure_change
do_handle_cast({'figure_change', Node, RoleId, ServerId, Type, ChangeValue}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, figure_change, [Node, RoleId, ServerId, Type, ChangeValue]);
		_ ->
			Args = [RoleId, ServerId, Type, ChangeValue],
			distribute(State, Node, RoleId, ServerId, figure_change, Args)
	end,
	{noreply, State};

%% 击杀玩家
% kill_player  能互相击杀的玩家必定同分区(因此此处只计算一次分区)
do_handle_cast({'kill_player', Node, SceneId, KillId, BeKillId, BeKillSrvId, HurtList}, State) ->
	#wasteland_war_state{is_open = IsOpen, stage = Stage, round = Round} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, kill_player, [Node, SceneId, KillId, BeKillId, BeKillSrvId, HurtList]);
		_ ->
			Args = [Round, KillId, BeKillId, HurtList],
			case Stage of
				?WASTELAND_RUN -> distribute(State, Node, BeKillId, BeKillSrvId, kill_player, Args);
				_ -> ignore
			end
	end,
	{noreply, State};

%% 击杀(采集)结晶 -- 在游戏服/跨服调用 无需判断跨服开放状态
do_handle_cast({'kill_crystal', Node, KillId, ServerId}, State) ->
	#wasteland_war_state{stage = Stage, round = Round} = State,
	Args = [Round, KillId],
	case Stage of
		?WASTELAND_RUN -> distribute(State, Node, KillId, ServerId, kill_crystal, Args);
		_ ->
			ignore
	end,
	{noreply, State};

%% 记录玩家死亡状态
do_handle_cast({'record_die_state', Node, ServerId, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, record_die_state, [Node, ServerId, RoleId]);
		_ ->
			Args = [RoleId],
			distribute(State, Node, RoleId, ServerId, record_die_state, Args)
	end,
	{noreply, State};

%% 清除玩家死亡状态
do_handle_cast({'clean_die_state', Node, ServerId, RoleId}, State) ->
	#wasteland_war_state{is_open = IsOpen} = State,
	ClsType = config:get_cls_type(),
	case ClsType of
		0 when IsOpen == true ->
			clusters_node:apply_cast(mod_wasteland_war, clean_die_state, [Node, ServerId, RoleId]);
		_ ->
			Args = [RoleId],
			distribute(State, Node, RoleId, ServerId, clean_die_state, Args)
	end,
	{noreply, State};

do_handle_cast(_Msg, State) ->
	?ERR("Handle unknow msg[~w]~n", [_Msg]),
	{noreply, State}.

%% ---------------------------------------------------------------------------
%% 根据战力分战场
do_handle_info({'calc_war_field'}, State) ->
	#wasteland_war_state{is_open = IsOpen, srv_zone_map = SrvZoneMap, zone_work_map = WorkerMap} = State,
	ZoneIds = lists:usort(maps:values(SrvZoneMap)),
	F = fun(ZoneId) ->
		lib_wasteland_war:calc_war_field(ZoneId, WorkerMap)
	end,
	lists:foreach(F, ZoneIds),
	%% 定时刷出结晶
	CreateGapTime = data_wasteland_war:get_kv_cfg(crystal_update),
	CrystalRef = util:send_after([], CreateGapTime, self(), {'create_crystal'}),
	%% 下一轮定时器
	case data_wasteland_war:get_round_cfg(1) of
		#wasteland_round_reward_cfg{duration = Duration} -> skip;
		_ -> Duration = ?WAR_DEFAULT_DURATION
	end,
	RoundRef     = util:send_after([], Duration*1000, self(), {'next_round'}),
	RoundEndTime = utime:unixtime() + Duration,
	NewState   = State#wasteland_war_state{
		stage = ?WASTELAND_RUN, round = 1, crystal_ref = CrystalRef,
		round_ref = RoundRef, round_end_time = RoundEndTime
	},
	%% 推送活动进入进行时
	lib_wasteland_war:notice_act_change(?WASTELAND_RUN, State#wasteland_war_state.start_time, IsOpen),
	{noreply, NewState};

%% 定时刷出结晶
do_handle_info({'create_crystal'}, State) ->
	#wasteland_war_state{crystal_ref = CrystalRef, round = Round, srv_zone_map = SrvZoneMap, zone_work_map = WorkerMap} = State,
	ZoneIds = lists:usort(maps:values(SrvZoneMap)),
	F = fun(ZoneId) ->
		case maps:get(ZoneId, WorkerMap, []) of
			WorkPid when is_pid(WorkPid) ->
				mod_wasteland_worker:create_crystal(WorkPid, Round);
			_ ->
				ignore
		end end,
	lists:foreach(F, ZoneIds),
	CreateGapTime = data_wasteland_war:get_kv_cfg(crystal_update),
	NewCrystalRef = util:send_after(CrystalRef, CreateGapTime*1000, self(), {'create_crystal'}),
	NewState   = State#wasteland_war_state{crystal_ref = NewCrystalRef},
	{noreply, NewState};

%% 结算，进入下一轮
do_handle_info({'next_round'}, State) ->
	#wasteland_war_state{is_open = IsOpen, round = OldRound, round_ref = RoundRef,
	crystal_ref = CrystalRef, srv_zone_map = SrvZoneMap, zone_work_map = WorkerMap
	} = State,
	%% 取消创建结晶定时器
	util:cancel_timer(CrystalRef),
	ZoneIds = lists:usort(maps:values(SrvZoneMap)),
	F = fun(ZoneId) ->
		case maps:get(ZoneId, WorkerMap, []) of
			WorkPid when is_pid(WorkPid) ->
				mod_wasteland_worker:next_round(WorkPid, OldRound);
			_ ->
				ignore
		end end,
	lists:foreach(F, ZoneIds),
	%% 进行排行计算，淘汰玩家
	MaxRound = lists:max(data_wasteland_war:get_all_round()),
	case OldRound >= MaxRound of
		%% 最后一轮,进行终结
		true ->
			util:cancel_timer(RoundRef),
			%% 清理托管玩家
			% lib_wasteland_war:end_hosting(SrvZoneMap),
			%% 推送活动状态变更
			lib_wasteland_war:notice_act_change(?WASTELAND_REST,
				State#wasteland_war_state.start_time, IsOpen),
			%% 清理所有数据 todo
			%% 通知所有游戏服活动关闭
			case config:get_cls_type() of
				1 ->
					clusters_center:apply_to_all_node(mod_wasteland_war, sync_status, [0, 0]);
				_ ->
					ignore
			end,
			NewState = State#wasteland_war_state{stage = ?WASTELAND_REST};
		_ ->
			NewRound = OldRound + 1,
			case data_wasteland_war:get_round_cfg(NewRound) of
				#wasteland_round_reward_cfg{duration = Duration} -> skip;
				_ -> Duration = ?WAR_DEFAULT_DURATION
			end,
			NewRoundRef  = util:send_after(RoundRef, Duration*1000, self(), {'next_round'}),
			RoundEndTime = utime:unixtime() + Duration,
			%% 晋级者2s后进入下一轮 todo：此过程有玩家重新进入？
			util:send_after([], 2*1000, self(), {'take_next_round'}),
			%% 此处将战场状态设置为WASTELAND_TURN，并由take_next_round重新设置
			NewState   = State#wasteland_war_state{stage = ?WASTELAND_TURN, round = NewRound, round_ref = NewRoundRef
				,round_end_time = RoundEndTime
			}
	end,
	{noreply, NewState};

%% 进入下一轮
do_handle_info({'take_next_round'}, State) ->
	#wasteland_war_state{srv_zone_map = SrvZoneMap, zone_work_map = WorkerMap,
		round = Round, round_end_time = _RoundEndTime} = State,
	ZoneIds = lists:usort(maps:values(SrvZoneMap)),
	%% 拉玩家进入下一场
	F = fun(ZoneId) ->
		case maps:get(ZoneId, WorkerMap, []) of
			WorkPid when is_pid(WorkPid) ->
				mod_wasteland_worker:take_next_round(WorkPid, Round);
			_ ->
				ignore
		end end,
	lists:foreach(F, ZoneIds),
	%% 创建结晶
	NewCrystalRef = util:send_after([], 10, self(), {'create_crystal'}),
	{noreply, State#wasteland_war_state{stage = ?WASTELAND_RUN, crystal_ref = NewCrystalRef}};

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

%% ---------------------------  builtin function -------------------------------------
%% 分发玩家行为到各分区管理进程
distribute(State, Node, RoleId, ServerId, Method, Args) ->
	#wasteland_war_state{zone_work_map = ZoneWorkMap, srv_zone_map = SrvZoneMap} = State,
	ZoneId = maps:get(ServerId, SrvZoneMap, 0),
	case maps:get(ZoneId, ZoneWorkMap, []) of
		WorkerPid when is_pid(WorkerPid) ->
			%% 如果worker crash,将玩家踢出场景,避免长期驻留
			case misc:is_process_alive(WorkerPid) of
				true ->
					mod_wasteland_worker:Method([WorkerPid| Args]);
				_ when Method == quit_scene ->
					?ERR("wasteland worker crash ZoneId,ServerId,RoleId quit scene ~w~n",
						[{ZoneId, ServerId, RoleId}]),
					lib_wasteland_war:switch_default_scene(Node, RoleId);
				_ ->
					ignore
			end;
		_ ->
			%% 不是战场行为过滤日志输出
			case lists:member(Method, [power_change, figure_change]) of
				true -> ignore;
				_ ->
					?ERR("ZoneId,ServerId,RoleId: ~w find not wasteland worker Method:~w~n",
						[{ZoneId, ServerId, RoleId}, Method])
			end,
			%% 如果未找到对应管理进程,则推送活动未开启(假人不需要推送)
			Cmd = 60200, Msg = [0, 0, 1],
			case Node of
				undefined -> ignore;
				_ -> lib_wasteland_war:send_to_client(Node, RoleId, Cmd, Msg)
			end
	end.