%%%-------------------------------------------------------------------
%%% @doc    社团 - 社团支援
%%% Module  : lib_guild_support_mod.erl
%%% Created : 2020-02-28
%%% @Author : tyl
%%%-------------------------------------------------------------------
-module(lib_guild_support_mod).

-include("guild.hrl").
-include("guild_support.hrl").
-include("sql_guild.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("figure.hrl").
-include("def_fun.hrl").
-include("def_module.hrl").
-include("def_goods.hrl").
-include("rec_event.hrl").
-include("server.hrl").
-include("team.hrl").
-include("local_boss.hrl").
-include("convoy.hrl").
-include("role.hrl").
-include("goods.hrl").
-include("def_id_create.hrl").
-include("def_act_label.hrl").
-include("def_event.hrl").
-include("predefine.hrl").
-include("battle.hrl").
-include("scene.hrl").
-include("guild_run_assist.hrl").
-include ("attr.hrl").

%% 定制API
-export([
	is_supporting/1                %% 判断是否协助者 是-true 否-false
	,go_to_support_in_scene/5      %% 场景中直接前往协助(玩家进程)
	,finish_normal_game_play/2     %% 玩法结束(玩家进程,每个玩法自行调用)
]).

%% CALLBACK_FUNC 各个玩法自行根据需要使用的接口
%% 在下面有相关接口,可参考 guild_support_boss.erl

%% 与协议相关接口
-export([
	get_support_list/4          %% 获取协助列表
	,ask_for_support/4          %% 发送协助请求
	,reply_support/2            %% 前往协助
]).

%% 其他接口,其他系统调用(玩法禁止调用)
-export([
	logout/1                       %% 掉线退出(玩家进程)
	,active_quit/1                 %% 玩法中途退出
	,handle_event/2                %% 事件触发
	% ,init_load_support/1           %% 加载支援数据
	,get_guild_support_map/1       %% 根据GuidId来获取公会中的支援数据(公会进程)

	%% 以下是赏金boss定制
	,update_team_info/1            %% 更新队伍信息
	,update_scene_info/1           %% 更新场景信息
	,supporter_enter_scene/1       %% 协助者进入场景后更新队伍信息

	,get_support_collect_data/4    %% 获取社团采集宝箱怪唯一Id
	,finish_support_callback/1
	,filter_role_list/2
]).

-compile(export_all).

%% -------------------------------------------------------------------------------------
%% @doc 玩法说明：
%% 1.原地复活的玩法,玩家身上和公会进程的数据不会改变
%% 2.调用change_scene接口切换场景玩家身上的状态和公会进程的数据--可能会改变
%% 3.IMPORTANT!!! 2021-04-15  配置中添加 is_conflict 字段
%% 通用玩法调整后，将请求和协助状态不冲突的玩法，例如社团采集 和 社团跑环
%% 融入进来。此类玩法中：
%% 1）发起协助者的玩家进程状态中协助数据并没有变更。数据只保留在公共管理进程
%% 2）协助者状态则跟冲突玩法没有区别，只要协助就会修改玩家进程中的协助状态数据
%% 新的玩法功能设计者自己留意
%% @end
%% -------------------------------------------------------------------------------------

%% 玩法场景
-define(GAME_PLAY_SCENE, [
	?SCENE_TYPE_WORLD_BOSS       %% 世界boss
	,?SCENE_TYPE_REWARD_BOSS     %% 赏金boss
	,?SCENE_TYPE_GUILD           %% 社团采集
	,?SCENE_TYPE_DESERTED_BOSS	 %% 废都boss
]).

%% 禁止通过协助切换场景的玩法
-define(CAN_NOT_GO_SUPPORT_SCENES, [
	?SCENE_TYPE_DUNGEON
	,?SCENE_TYPE_JUMP_ACT
	,?SCENE_TYPE_ARENA
	,?SCENE_TYPE_GWAR
	,?SCENE_TYPE_CAMP_WAR
	,?SCENE_TYPE_CGW
	,?SCENE_TYPE_1vN
	,?SCENE_TYPE_3v3
	,?SCENE_TYPE_EXP_SEA
	,?SCENE_TYPE_HOME_BOSS
]).

%% 特殊玩法场景Id
-define(GAME_PLAY_SPECIAL_SCENE, []).  %% 护送玩法的场景

%% 护送二段场景(作为结算判断)
-define(HUSONG_SCENE2,  [1006, 1017]).

%% 相关数据记录
%% 请求者发送请求时的状态数据
-record(ask_info, {
	role_id     = 0     %% 角色Id
	,scene      = 0     %% 场景Id
	,pool_id    = 0     %% 场景分线Id
	,copy_id    = 0     %% 副本Id
	,x          = 0     %% X坐标
	,y          = 0     %% Y坐标
	,team_id    = 0     %% 队伍
	,team_leader_name = "" %% 队长名字(请求者所在队伍)
}).

% ---------------------------------------------------------------------------
%% 各个玩法根据Module来增添
get_module_handler(Module, SubModule) ->
	case {Module, SubModule} of
		{?MOD_LOCAL_BOSS, 2} ->
			Handler = guild_support_boss;
		{?MOD_LOCAL_BOSS, 3} ->
			Handler = guild_support_boss;
		{?MOD_GUILD_COLLECT, 0} ->
		 	Handler = guild_support_collect;
		{?MOD_DESERTED_BOSS, 0} ->
			Handler = guild_support_deserted_boss;
		{?MOD_GUILD_RUN_ASSIST, _} ->
			Handler = guild_support_run_assist;
		_ ->
			Handler = default_mfa
	end,
	Handler.
%% ---------------------------------------------------------------------------
%% @doc  CALLBACK_FUN 各个玩法回调接口
%% -- 注意:不必都使用,按需要使用
%% ---------------------------------------------------------------------------
%% 组织协助content格式
make_content(Module, SubModule, Value, _Other) ->
	Handler = get_module_handler(Module, SubModule),
	DefaultReturn = {},
	distribute(Handler, make_content, [Value], DefaultReturn).

%% 获取协助的初始状态
%% 0-未开始 1-正在进行 2-已经结束
%% 一般情况下为 1
get_support_init_status(Module, SubModule) ->
	Handler = get_module_handler(Module, SubModule),
	DefaultReturn = 1,
	distribute(Handler, get_support_init_status, [], DefaultReturn).

%% 获取玩法的场景Id
get_support_scene(SupportInfo) ->
	#guild_support{module = Handler} = SupportInfo,
	DefaultReturn = 1003,
	distribute(Handler, get_support_scene, [SupportInfo], DefaultReturn).

%% 进入玩法前一些推送处理
notice_before_change_scene(Handler, ReplyId, SupportInfo) ->
	DefaultReturn = ok,
	distribute(Handler, notice_before_change_scene, [ReplyId, SupportInfo], DefaultReturn).

%% 进入玩法前的参数作为 enter_game_play 参数 ArgsList使用
before_enter_scene(Handler, SupportInfo) ->
	DefaultArgs = [],
	distribute(Handler, before_enter_scene, [SupportInfo], DefaultArgs).

%% 进入玩法
%% 注意!!!  必须做两种情况的判断：
%% 1 - 本身在玩法场景内(调用go_to_support_in_scene)
%% 2 - 本身不在玩法场景内,根据每个玩法进入场景逻辑自行决定
enter_game_play(Handler, ReplyId, SupportInfo, ArgsList) ->
	lib_player:apply_cast(ReplyId, ?APPLY_CAST_SAVE, ?MODULE, player_enter_game_player,
		[Handler, SupportInfo, ArgsList]),
	ok.
player_enter_game_player(Player, Handler, SupportInfo, ArgsList) ->
	% #player_status{action_lock = ACLock} = Player,
	% Player1 = case ACLock =/= free of
	%	          true -> lib_player:break_action_lock(Player, ACLock);
	%	          _ -> Player
	%          end,
	DefaultArgs = {ok, Player},
	distribute(Handler, player_enter_game_player, [Player, SupportInfo, ArgsList], DefaultArgs).

%% 玩法结束,检查是否符合条件(对finish_normal_game_play传入的参数进行检查)
%% 参数为[]，则不必调用此函数
check_success_finish(Handler, SupportInfo, Args) ->
	DefaultArgs = true,
	distribute(Handler, check_success_finish, [SupportInfo, Args], DefaultArgs).

%% 场景需要需要携带协助内容信息
check_need_content(Handler) ->
	case Handler of
		guild_support_deserted_boss ->
			true;
		_ ->
			false
	end.

%% 协助结束后的处理
-spec after_support_end(Handler, RoleId, FinishType, SupportInfo) -> Return when
	Handler       :: atom(),                % 处理模块
	RoleId        :: non_neg_integer(),     % 请求者或者协助者Id
	FinishType    :: integer(),             % 协助完成类型 0-失败 1-成功 2-取消
	SupportInfo   :: #guild_support{},      % 协助信息
	Return        :: any().
after_support_end(Handler, RoleId, FinishType, SupportInfo) ->
	DefaultArgs = ok,
	distribute(Handler, after_support_end, [RoleId, FinishType, SupportInfo], DefaultArgs).

%% 每日协助次数限制
%% 1. 护送玩法 - 每日3次
get_daily_support_count(Module, SubModule) ->
	case {Module, SubModule} of
		{?MOD_LOCAL_BOSS, 2} ->
			?SUPPORT_MAX_COUNT;
		{?MOD_LOCAL_BOSS, 3} ->
			?SUPPORT_MAX_COUNT;
		{?MOD_GUILD_COLLECT, 0} ->
			?SUPPORT_MAX_COUNT;
		{?MOD_CONVOY, 1} ->
			?SUPPORT_HUSONG_MAX_COUNT;
		_ ->
			?SUPPORT_MAX_COUNT
	end.

%% ---------------------------------------------------------------------------
%% API分发 TODO: MODULE不存在的时候
distribute(Handler, Fun, Args, DefaultReturn) ->
	ArgsNum = length(Args),
	case get_special_api_mod(Handler, Fun, ArgsNum) of
		undefined ->
			distribute_normal(DefaultReturn);
		Mod ->
			apply(Mod, Fun, Args)
	end.

get_special_api_mod(Handler, ApiName, ArgsNum) ->
	Mod = Handler,
	if
		Mod =/= undefined ->
			case lists:member({ApiName, ArgsNum}, Mod:module_info(exports)) of
				true ->
					Mod;
				_ ->
					undefined
			end;
		true ->
			undefined
	end.

distribute_normal({default_mfa, Mod, Fun, Args}) ->
	apply(Mod, Fun, Args);
distribute_normal({default_mfa, Fun, Args}) ->
	apply(lib_guild_support_mod, Fun, Args);
%% 通用返回值
distribute_normal(DefaultReturn) ->
	DefaultReturn.

%% ------------------------------------------------------------------------------------
%% @doc 玩家行为
%% ------------------------------------------------------------------------------------
%% 发送协助
ask_for_support(Player, Module, SubModule, GameInfo) ->  %% 玩法类型
	#player_status{sid = Sid, id = RoleId, scene = Scene, scene_pool_id = PoolId, copy_id = CopyId, x = X, y = Y,
		guild = StatusGuild, team = Team} = Player,
	#status_team{leader_name = LeaderName, team_id = TeamId} = Team,
	#status_guild{id = GuildId, is_in_support = _IsInSupport, is_support_asker = IsAsker} = StatusGuild,
	AskInfo = #ask_info{role_id = RoleId, scene = Scene, pool_id = PoolId, copy_id = CopyId, x = X, y = Y
		,team_id = TeamId, team_leader_name = LeaderName},
	%% 判断是否可以发送协助
	CheckList = [{is_in_guild, GuildId}, {check_param, Module, SubModule, GameInfo}
		% ,{can_ask, IsInSupport, Module, SubModule}, {is_supporting, IsInSupport}
		,{check_mod, Player, Module, SubModule}],   %% boss疲劳度等判断
	CanAsk =
		case check(CheckList) of
			true -> true;
			{false, ErrCode} -> {false, ErrCode}
		end,
	case CanAsk of
		true ->
			mod_guild_support:apply_cast(?MODULE, player_ask_for_support, [GuildId, AskInfo, Module, SubModule, GameInfo, IsAsker]);
		{false, Err} ->
			{ok, Bin} = pt_400:write(40051, [Err, 0, 0, 0]),
			lib_server_send:send_to_sid(Sid, Bin)
	end,
	{ok, Player}.

%% 前往协助
reply_support(Player, SupportId) ->
	#player_status{sid = Sid, id = RoleId, guild = StatusGuild, scene = Scene,
		team = _Team, figure = Figure, action_lock = ActionLock} = Player,
	#status_guild{
		id               = GuildId,
		is_in_support    = IsInSupport,
		is_support_asker = IsAsker,
		support_cfg_id   = SupportCfgId,
		support_id       = MySupportId
	} = StatusGuild,
	%% 判断是否可以进行社团协助
	CheckList  = [
		{is_in_guild, GuildId},
		{check_list, Player},     %% 玩家状态检测
		{action_lock, Player},    %% 一些玩法中禁止玩家切场景前往协助
		{is_asker, IsAsker, SupportId, MySupportId}           %% 判断是否是自己发送/协助的单
		,{is_supporting, IsInSupport, IsAsker, SupportCfgId}  %% 协助者一次只能协助一个单,冲突的玩法不能去协助
		,{sub_module_check, GuildId, RoleId, SupportId, SupportCfgId, ActionLock, Scene}
	],
	CanSupport =
		case check(CheckList) of
			true         -> true;
			{false, Err} -> {false, Err}
		end,
	case CanSupport of
		true ->
			%% 公会进程处理
			mod_guild_support:apply_cast(?MODULE, player_reply_support, [RoleId, Figure#figure.lv, GuildId, SupportId]);
		{false, ErrCode} ->
			send_msg(Sid, 40052, [ErrCode, SupportId, SupportCfgId])
	end.

%% 取消协助
cancel_support(Player) ->
	#player_status{id = RoleId, guild = StatusGuild} = Player,
	#status_guild{id = GuildId, support_id = SupportId} = StatusGuild,
	case SupportId > 0 of
		true ->
			NewPlayer = reset_player_support_status(Player),
			mod_guild_support:apply_cast(?MODULE, player_cancel_support, [RoleId, GuildId, SupportId]),
			NewPlayer;
		_ ->
			% mod_guild_support:cast_to_guild({player_cancel_support, RoleId, GuildId, SupportId}),
			Player
	end.

%% 掉线离场
logout(Player) ->
	#player_status{id = _RoleId, guild = StatusGuild} = Player,
	#status_guild{
		id               = GuildId,
		support_id       = SupportId,
		is_support_asker = IsAsker
	} = StatusGuild,
	mod_guild_support:apply_cast(?MODULE, player_logout, [Player#player_status.id, GuildId, SupportId, IsAsker]),
	% db_update_support_info(RoleId, 0, 0),
	{ok, Player}.

%% 场景中主动退出
active_quit(Player) ->
	#player_status{id = RoleId, guild = StatusGuild} = Player,
	#status_guild{
		id               = GuildId,
		is_in_support    = IsInSupport,
		support_id       = SupportId,
		is_support_asker = IsAsker
	} = StatusGuild,
	case IsInSupport == 1 of
		true ->
			% {ok, NewPlayer} = lib_player_event:dispatch(Player, ?EVENT_CANCEL_SUPPORT, []);
			mod_guild_support:apply_cast(?MODULE, player_active_quit, [RoleId, GuildId, SupportId, IsAsker]);
		_ ->
			skip
	end,
	case IsAsker of
		1 -> NewPlayer = refresh_player_support_status(Player);
		_ -> NewPlayer = reset_player_support_status(Player)
	end,
	% db_update_support_info(RoleId, 0, 0),
	{ok, NewPlayer}.

%% 玩法结束,请求者被动退出场景(玩法结束被清退出场景)
passive_quit(Player) ->
	#player_status{id = RoleId, guild = StatusGuild} = Player,
	#status_guild{
		id            = GuildId,
		support_id    = SupportId,
		is_in_support = IsInSupport
	} = StatusGuild,
	case IsInSupport == 1 of
		true ->
			{ok, Player1} = lib_player_event:dispatch(Player, ?EVENT_CANCEL_SUPPORT, []),
			mod_guild_support:apply_cast(?MODULE, player_cancel_support, [RoleId, GuildId, SupportId]);
		_ ->
			Player1 = Player
	end,
	NewPlayer = refresh_player_support_status(Player1),
	% db_update_support_info(RoleId, 0, 0),
	{ok, NewPlayer}.

%% ----------------------------------------------------------------
%% @doc 定制API
%% ----------------------------------------------------------------
%% 判断玩家是否在协助玩法中
is_supporting(Player) ->
	#player_status{guild = StatusGuild} = Player,
	#status_guild{
		is_in_support = IsInSupport} = StatusGuild,
	case IsInSupport == 1 of
		true  -> true;
		false -> false
	end.

%% 判断玩家是否协助者
role_is_supporting(Player) ->
	#player_status{guild = StatusGuild} = Player,
	#status_guild{
		is_support_asker = IsAsker,
		is_in_support = IsInSupport
	} = StatusGuild,
	case IsInSupport == 1 andalso IsAsker =:= 0 of
		true  -> true;
		false -> false
	end.

%% 获取协助列表(SupportId & SupportStatus作为传参使用,前端需要知道当前正在协助的单号和状态)
get_support_list(RoleId, GuildId, SupportId, SupportStatus) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	SupportList = maps:to_list(GuildSupportMap),
	FailRoles = guild_run_assist:get_guild_fail_role(GuildId),
	PackList = pack_support_info(SupportList, []),
	PackList1 = filter_fail_role_list(RoleId, PackList, FailRoles),
	HelpSid = 0,
	{ok, Bin} = pt_400:write(40046, [PackList1, SupportId, SupportStatus, HelpSid]),
	lib_server_send:send_to_uid(RoleId, Bin).

%% 剔除玩家无法接取的任务
filter_fail_role_list(RoleId, PackList, FailRoles) ->
	lists:foldl(fun({SupportId, Roles}, TempPackList) -> 
		case lists:member(RoleId, Roles) of
			true ->
				lists:keydelete(SupportId, 1, TempPackList);
			_ ->
				TempPackList
		end
	end, PackList, FailRoles).

%% 获取社团采集指定协助单的宝箱怪唯一Id
get_support_collect_data(RoleId, GuildId, SupportId, EnterRet) ->
	mod_guild_support:apply_cast(?MODULE, get_collect_data, [RoleId, GuildId, SupportId, EnterRet]),
	ok.

get_collect_data(RoleId, GuildId, SupportId, EnterRet) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{content = Content} ->
			case Content of
				{_, {BossId, _}} ->
					% ?INFO_TTY("BossId is ~w~n",[BossId]),
					lib_server_send:send_to_uid(RoleId, pt_408, 40808, [EnterRet, BossId]);
				_ ->
					lib_server_send:send_to_uid(RoleId, pt_408, 40808, [EnterRet, 0])
			end;
		_ ->
			lib_server_send:send_to_uid(RoleId, pt_408, 40808, [EnterRet, 0])
	end,
	ok.

%% ----------------------------------------------------------------
%% @doc 公会进程处理逻辑
%% ----------------------------------------------------------------
%% 公会进程处理玩家协助请求
player_ask_for_support(GuildId, AskInfo, Module, SubModule, GameInfo, IsAsker) ->
	#ask_info{role_id = RoleId, scene = Scene, pool_id = PoolId, copy_id = CopyId,
		x = X, y = Y, team_id = TeamId, team_leader_name = TeamLeaderName} = AskInfo,
	%% 判断协助状态
	SupportCfgId = get_support_cfg_id_by_module(Module, SubModule),
	CheckList = [{is_guild_exits, GuildId}, {has_asker_ask, RoleId, GuildId, GameInfo, IsAsker, SupportCfgId}],
	case check(CheckList) of
		true ->
			AutoId  = mod_id_create:get_new_id(?SUPPORT_ID_CREATE),
			Content = make_content(Module, SubModule, GameInfo, 0),
			case Content of
				{} ->
					send_msg_role(RoleId, 40051, [?ERRCODE(err400_support_has_finish), 0, 0, 0]);
				_ ->
					Status  = get_support_init_status(Module, SubModule),
					Handler = get_module_handler(Module, SubModule),
					% Extra  = [],
					GuildSupport = #guild_support{
						support_sid    = AutoId,
						support_cfg_id = SupportCfgId,
						ask_id         = RoleId,
						ask_scene_id   = Scene,
						ask_pool_id    = PoolId,
						ask_copy_id    = CopyId,
						ask_x          = X,
						ask_y          = Y,
						content        = Content,
						team_id        = TeamId,
						team_leader_name = get_team_leader_name(TeamId, TeamLeaderName, RoleId),
						status  = Status
						,module = Handler
						,create_time = utime:unixtime()
					},
					ReSupportInfo = {Module, SubModule, AutoId, TeamId, TeamLeaderName, #{}},
					if
						Module == ?MOD_GUILD_RUN_ASSIST andalso SubModule == ?GUILD_RUN_ASSIST_BOSS ->
							mod_guild:apply_cast(lib_dungeon_help, after_ask_for_support, [RoleId, GuildId, ReSupportInfo, GameInfo]);
						true ->
							lib_player:apply_cast(
								RoleId, ?APPLY_CAST_SAVE, ?MODULE, after_ask_for_support, [ReSupportInfo, GameInfo])
					end,
					% db_save_guild_support(AutoId, GuildId, SupportCfgId, RoleId, [], Scene, X, Y, Content, Extra, Status),
					%% 日志
					add_ask_log(RoleId, GuildId, AutoId, SupportCfgId, Module, SubModule, GameInfo),
					SupportMap    = get_guild_support_map(GuildId),
					NewSupportMap = maps:put(AutoId, GuildSupport, SupportMap),
					%% 推送给公会所有人
					send_support_list_to_guild(NewSupportMap, GuildId, GuildSupport),
					save_guild_support_map(GuildId, NewSupportMap)
			end;
		{false, Err} ->
			% ?INFO_TTY("ask guild ErrCode is ~w~n",[Err]),
			send_msg_role(RoleId, 40051, [Err, 0, 0, 0])
	end.

%% 请求日志
add_ask_log(RoleId, GuildId, AutoId, SupportCfgId, Module, SubModule, GameInfo) ->
	case GameInfo of
		{_, BossId} -> ok;
		_ -> BossId = 0
	end,
	Content = [{Module, SubModule}, BossId],
	lib_log_api:log_ask_guild_support(RoleId, GuildId, AutoId, SupportCfgId, Content).

%% 玩家请求协助后状态处理(回调函数)
after_ask_for_support(Player, ReSupportInfo, GameInfo) ->
	{Module, SubModule, SupportId, TeamId, TeamLeaderName, ExtraData} = ReSupportInfo,
	{Val1, Val2} = GameInfo,
	#player_status{id = RoleId, figure = Figure, guild = StatusGuild} = Player,
	%% 请求 和 协助不冲突的玩法，请求者玩家进程不设置状态
	%% IsInSupport = 0此时玩家还可以去协助其他人
	SupportCfgId = get_support_cfg_id_by_module(Module, SubModule),
	% ?INFO_TTY("SupportCfgId is ~w~n",[SupportCfgId]),
	case is_conflict(SupportCfgId) of
		true ->
			NewStatusGuild = StatusGuild#status_guild{
				support_cfg_id   = SupportCfgId,
				support_id       = SupportId,
				is_in_support    = 1,
				is_support_asker = 1};
		_ ->
			NewStatusGuild = StatusGuild
	end,
	NewPlayer = Player#player_status{guild = NewStatusGuild},
	NewPlayer1 =
	if 
		Module == ?MOD_DESERTED_BOSS andalso Val1 == ?MON_DESERTED_BOSS
		andalso Val2 =/= 0 ->
			#figure{name = RoleName, guild_id = GuildId, lv = RoleLv,
				career = Career} = Figure,
			RoleInfo = [
				RoleId, RoleName, self(), config:get_server_id(), node(), 
				TeamId, TeamLeaderName, GuildId, RoleLv, Career
			],
			deserted_boss_mgr:add_support_asker(RoleInfo, Val2),
			NewPlayer;
		Module == ?MOD_GUILD_RUN_ASSIST ->
			{ok, TPlayer} = guild_run_assist:role_add_req_run_assist(NewPlayer, SupportId, SubModule, ExtraData),
				TPlayer;
		true -> NewPlayer
	end,
	{ok, Bin} = pt_400:write(40051, [?SUCCESS, Module, SubModule, SupportId]),
	lib_server_send:send_to_uid(RoleId, Bin),
	contract_task_api:request_help_trigger(RoleId, 1),
	{ok, NewPlayer1}.

%% 请求单生成后推送给公会所有人
send_support_list_to_guild(NewSupportMap, GuildId, GuildSupport) ->
	SupportList = maps:to_list(NewSupportMap),
	PackList = pack_support_info(SupportList, []),
	mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, refresh_support_list, [erlang:length(PackList), GuildSupport]),
	ok.

% SupportCount - 协助列表长度
refresh_support_list(Player, SupportCount, GuildSupport) ->
	#player_status{id = RoleId, figure = Figure, sid = Sid, scene = SceneId} = Player,
	#guild_support{support_cfg_id = SupportCfgId} = GuildSupport,
	%% 未到等级不推送
	case data_guild:get_guild_support_cfg(SupportCfgId) of
		#base_guild_support{module_id = Module, sub_mod_id = SubModule} -> ok;
		_ -> Module = 0, SubModule = 0
	end,
	case SubModule == 0 of
		true -> OpenLv = lib_module:get_open_lv(Module);
		_ -> OpenLv = lib_module:get_open_lv(Module, SubModule)
	end,
	case Figure#figure.lv >= OpenLv of
		true ->
			{ok, Bin} = pt_400:write(40056, [1, SupportCount]),
			lib_server_send:send_to_sid(Sid, Bin);
		_ ->
			ignore
	end,
	%% 社团采集给社团驻地里面的玩家推送更新
	case lib_guild:is_guild_scene(SceneId) of
		true ->
			guild_support_collect:update_support(1, GuildSupport, RoleId);
		_ -> ignore
	end,
	{ok, Player}.

%% 公会进程处理协助
player_reply_support(ReplyId, ReplyLv, GuildId, SupportId) ->
	%% 判断是否可以进行社团协助
	SupportMap = get_guild_support_map(GuildId),
	CheckList  = [
		{is_ask_id, SupportMap, SupportId, ReplyId},
		{support_status, SupportMap, SupportId},            %% 协助单的状态
		{is_gameplay_open, ReplyLv, SupportMap, SupportId},
		{is_role_num_max, SupportMap, SupportId}
		,{is_count_enough, ReplyId, SupportMap, SupportId}  %% 每日协助次数控制
		% ,{is_busy, SupportMap, SupportId, ReplyId}
	],
	CanSupport =
	case check(CheckList) of
		true         -> true;
		{false, Err} -> {false, Err}
	end,
	case CanSupport of
		true ->
			case maps:get(SupportId, SupportMap, []) of
				#guild_support{ask_id = AskId, module = Handler} = SupportInfo ->
					%% 先添加玩家，玩家切换场景失败再踢出列表
					%% 修改协助玩家列表
					#guild_support{support_role_list = RoleList} = SupportInfo,
					case ReplyId =/= AskId of
						true ->
							lists:member(ReplyId, RoleList) == false andalso
								add_into_support_role_list(GuildId, SupportId, ReplyId);
						_ ->
							skip
					end,
					notice_before_change_scene(Handler, ReplyId, SupportInfo),
					ArgsList = before_enter_scene(Handler, SupportInfo),
					enter_game_play(Handler, ReplyId, SupportInfo, ArgsList);
				_ ->
					send_msg_role(ReplyId, 40052, [?ERRCODE(err400_support_has_finish), SupportId, 0])
			end;
		{false, ErrCode} ->
			%% 请求者发送了请求,但协助状态为0。可能情况是：
			%% 1. 具体玩法的初始状态应该配置为1,而实际上错误设置为0
			%% 2. 具体玩法初始状态应该配置为0,但请求者实际没有在现场(进入玩法场景后状态变为1,例如非正常离线)
			%% 因此需要借用请求者名义删除请求
			case ErrCode of
				4000189 ->
					player_active_quit(ReplyId, GuildId, SupportId, 1);
				_ ->
					skip
			end,
			send_msg_role(ReplyId, 40052, [ErrCode, SupportId, 0])
	end.

%% 请求协助后推送
notice_after_reply_support(#player_status{sid = Sid, guild = StatusGuild} = Player) ->
	#status_guild{support_id = SupportId, support_cfg_id = SupportCfgId} = StatusGuild,
	send_msg(Sid, 40052, [?SUCCESS, SupportId, SupportCfgId]),
	{ok, Player}.

%% 玩家取消协助退出场景,此时SupportId可能为0,以RoleId做判断
player_cancel_support(RoleId, GuildId, SupportId) ->
	delete_from_support_by_player(RoleId, GuildId, SupportId).

%% 玩家离场,将玩家踢出列表(公会进程)
player_logout(RoleId, GuildId, SupportId, IsAsker) ->
	case IsAsker == 1 of
		true ->
			delete_support_by_asker(GuildId, SupportId);
		_ ->
			delete_from_support_role_list(GuildId, SupportId, RoleId)
	end,
	ok.

%% 主动退出(公会进程)
player_active_quit(RoleId, GuildId, SupportId, IsAsker) ->
	case IsAsker == 1 of
		true ->
			delete_support_by_asker(GuildId, SupportId);
		_ ->
			delete_from_support_role_list(GuildId, SupportId, RoleId)
	end,
	ok.

%% -----------------------------------------------------------------
%% @doc 公会操作-协助单相关操作
%% -----------------------------------------------------------------
%% 退出公会(只处理内存)
quit_guild(Player) ->
	#player_status{guild = StatusGuild} = Player,
	IsInSupport = StatusGuild#status_guild.is_in_support,
	case IsInSupport == 1 of
		true ->
			NewPlayer = cancel_support(Player);
		_ ->
			NewPlayer = Player
	end,
	NewPlayer.

%% 公会合并(只处理内存)
merge_guild(TargetId, GuildId) ->
	SupportMap  = get_guild_support_map(GuildId),
	SupportL    = maps:to_list(SupportMap),
	TSupportMap = get_guild_support_map(TargetId),
	TSupportL   = maps:to_list(TSupportMap),
	SumSupportL = SupportL ++ TSupportL,
	SumSupportMap = maps:from_list(SumSupportL),
	save_guild_support_map(TargetId, SumSupportMap),
	save_guild_support_map(GuildId, #{}).

%% 解散公会(只处理内存)
disband_guild(GuildId) ->
	RoleList = lib_guild_data:get_all_role_in_guild(GuildId),
	[lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, cancel_support, []) || RoleId <- RoleList],
	% spawn(fun()->
	% 	db_delete_guild_all_supports(GuildId) end),
	clean_guild_support_map(GuildId).

%% ------------------------------------------------------------------
%% @doc 玩法过程中
%% ------------------------------------------------------------------
%% 进入场景，改变协助的状态
%% 玩家场景切换回调(只做一些场景更新后的状态变更 和 防御式操作,具体细节由各个玩法完成)
%% 出场景后是否取消 协助请求 由玩法配置判断
change_scene_callback(Player, OldSceneInfo, _OldSceneData, _NewSceneData) ->
	#player_status{
		scene = SceneId, scene_pool_id = PoolId, copy_id = CopyId,
		guild = StatusGuild, id = RoleId, sid = _Sid} = Player,
	#status_guild{
		support_id = SupportId, is_in_support = IsInSupport, is_support_asker = IsAsker,
		support_leader_id = _AskerId, id = GuildId, support_scene_info = SceneInfo
		} = StatusGuild,
	% ?INFO_TTY("SupportId is ~w~n",[SupportId]),
	% ?INFO_TTY("SceneInfo is ~w~n",[SceneInfo]),
	case SupportId > 0 orelse SceneInfo =/= [] of   %% 注意: 前往协助,切换场景前玩家状态会携带上SceneInfo
		true ->
			{OldSceneId, _, _, _, _} = OldSceneInfo,
			OldSceneFlag = is_in_normal_scene(OldSceneId),
			NewSceneFlag = is_in_normal_scene(SceneId),
			OldSpeSceneFlag = is_in_special_scene(OldSceneId),
			NewSpeSceneFlag = is_in_special_scene(SceneId),
			%% 枚举所有情况 返回 1-前往协助 0-离开协助 2-不处理
			%case {{OldSceneFlag, OldSpeSceneFlag}, {NewSceneFlag, NewSpeSceneFlag}, IsInSupport} of
			%	%% 一个场景的玩法
			%	{{false, _}, {true, _},  0} -> 1;
			%	{{false, _}, {true, _},  1} -> 2;
			%	{{true, _}, {true, _},   0} -> 1;
			%	{{true, _}, {true, _},   1} -> 0;
			%	{{true, _}, {false, _},  0} -> 2;
			%	{{true, _}, {false, _},  1} -> 0;

			%	%% 两个场景的玩法(如护送玩法)
			%	{{false, false}, {false, true},  0} -> 1;
			%	{{false, false}, {false, true},  1} -> 2;
			%	{{false, true}, {false, true},   0} -> 1;
			%	{{false, true}, {false, true},   1} -> 2;
			%	{{false, true}, {false, false},  0} -> 2;
			%	{{false, true}, {false, false},  1} -> 0;
			%	{{_, _}, {_, _}, _} -> 2
			%end,
			if
				OldSceneFlag andalso not NewSceneFlag ->
				%% 原本处于玩法场景中 | 新场景不是玩法场景
				% （请求者只有退出情况,协助者分情况讨论）
					case IsInSupport == 1 of
						true ->
							case IsAsker == 1 of
								true ->
									passive_quit(Player);
								_ ->
									active_quit(Player)
							end;
						_  ->
							{ok, Player}
					end;
				OldSceneFlag andalso NewSceneFlag ->
					%% 原本处于玩法场景中 & 新场景也是玩法场景
					% （请求者删除请求,协助者前往协助）
					case IsAsker == 1  of
						true ->
							active_quit(Player); % 请求者主动切换场景,删除请求
						_ ->
							NewPlayer = supporter_change_support_status(Player),
							{ok, NewPlayer}
					end;
				not OldSceneFlag andalso NewSceneFlag ->
					%% 原本不处于玩法场景中 & 新场景在玩法场景
					if
						IsAsker == 1 andalso IsInSupport== 1 ->
							{ok, Player};
						IsAsker == 1 andalso IsInSupport == 0 ->
							%% 请求者进入玩法场景(先请求协助再进入玩法,目前暂时没有这种玩法)
							{ok, Player};
						true ->
							%% 协助者处理
							NewPlayer = supporter_change_support_status(Player),
							{ok, NewPlayer}
					end;
				true ->  %% todo:护送暂时先不处理
					%% 原本不在玩法场景中 & 新场景不在玩法场景
					%% 此处需要特别对特殊玩法场景进行判断

					%% 护送玩法只对协助者进行判断
					case IsAsker == 1  of
						true -> {ok, Player};
						_ ->
							if
								not OldSpeSceneFlag andalso NewSpeSceneFlag ->
									NewPlayer = supporter_change_support_status(Player),
									{ok, NewPlayer};
								OldSpeSceneFlag andalso not NewSpeSceneFlag ->
									NewPlayer = reset_player_support_status(Player),
									mod_guild_support:apply_cast(?MODULE, player_active_quit, [RoleId, GuildId, SupportId, IsAsker]),
									% update_convoy_ets_scene(AskerId, {RoleId, SceneId}, delete),
									{ok, NewPlayer};
								OldSpeSceneFlag andalso NewSpeSceneFlag ->
									case StatusGuild#status_guild.support_scene_info of
										{TSceneId, TPoolId, TCopyId, _, _} -> ok;
										_ -> TSceneId = 0, TPoolId = 0, TCopyId = 0
									end,
									case {SceneId, CopyId, PoolId} == {TSceneId, TCopyId, TPoolId} of
										 true when StatusGuild#status_guild.is_in_support == 0 ->
											lib_player:apply_cast(
												RoleId, ?APPLY_CAST_STATUS, ?MODULE, notice_after_reply_support, []
											),
											NewStatusGuild = StatusGuild#status_guild{is_in_support = 1},
											NewPlayer = Player#player_status{guild = NewStatusGuild};
										_ ->
											NewPlayer = Player
									end,
									% update_convoy_ets_scene(AskerId, {RoleId, SceneId}, update),
									{ok, NewPlayer};
								true ->
									#player_status{role_guild_run_assist = RoleGuildRunAssist} = Player,
									#role_guild_run_assist{extra_data = ExtraData} = RoleGuildRunAssist,
									case maps:get(?GUILD_RUN_ASSIST_BOSS, ExtraData, []) of
										[_, _, _] ->
											{ok, Player};
										_ ->
											NewPlayer = refresh_player_support_status(Player),
											{ok, NewPlayer}
									end
							end
					end
			end;
		_ ->
			{ok, Player}
	end.

%% 协助者更新状态
supporter_change_support_status(Player) ->
	#player_status{
		sid = _Sid, id = RoleId, guild = StatusGuild,
		scene = SceneId, copy_id = CopyId, scene_pool_id = PoolId
	} = Player,
	#status_guild{
		id = GuildId, support_id = SupportId, is_in_support = IsInSupport,
		support_scene_info = SceneInfo} = StatusGuild,
	case SceneInfo =/= [] of
		true ->
			case IsInSupport == 1 of
				%% 协助中切换到同类玩法场景,退出协助
				true ->
					NewPlayer = cancel_support(Player);
				_ ->
					{TSceneId, TPoolId, TCopyId, _, _} = SceneInfo,
					case {SceneId, CopyId, PoolId} of
						{TSceneId, TCopyId, TPoolId}  ->
							%% 需要将52协议延后发送，前端拿到准确的SupportCfgId判断是否请求40046协议
							lib_player:apply_cast(
								RoleId, ?APPLY_CAST_STATUS, ?MODULE, notice_after_reply_support, []
							),
							NewStatusGuild = StatusGuild#status_guild{is_in_support = 1},
							NewPlayer = Player#player_status{guild = NewStatusGuild};
						_ ->
							%% 切换失败,通知公会进程更新协助列表
							mod_guild_support:apply_cast(?MODULE, delete_from_support_role_list, [GuildId, SupportId, RoleId]),
							NewPlayer = reset_player_support_status(Player)
					end
			end;
		_ ->
			NewPlayer = Player
	end,
	NewPlayer.

%% 请求者更新场景信息(先请求协助再进入玩法,暂时没有这类玩法)
asker_update_support_info(_RoleId, NewSceneInfo, GuildId, SupportId) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{} = GuildSupport ->
			case get_support_scene(GuildSupport) of
				Scene when Scene > 0 ->
					{SceneId, PoolId, CopyId, X, Y} = NewSceneInfo,
					case Scene == SceneId of
						true ->
							NewGuildSupport = GuildSupport#guild_support{
								ask_scene_id = SceneId, ask_copy_id = CopyId,
								ask_pool_id = PoolId, ask_x = X, ask_y = Y,
								status = 1
							},
							NewGuildSupportMap = maps:put(SupportId, NewGuildSupport, GuildSupportMap),
							% db_update_support_status(GuildId, SupportId, 1),
							% db_update_support_asker_scene_info(GuildId, SupportId, NewSceneInfo),
							save_guild_support_map(GuildId, NewGuildSupportMap);
						_  ->
							skip
					end;
				_ ->
					skip
			end;
		_ ->
			skip
	end.

%% 玩家掉线重登处理,清理管理进程中的协助单子
handle_event(Player, #event_callback{type_id = ?EVENT_LOGIN_CAST}) when is_record(Player, player_status) ->
	#player_status{id = RoleId, guild = StatusGuild} = Player,
	mod_guild_support:apply_cast(?MODULE, login_refresh, [RoleId, StatusGuild#status_guild.id]),
	{ok, Player};
handle_event(Player, #event_callback{type_id = ?EVENT_FIN_CHANGE_SCENE}) when is_record(Player, player_status) ->
	#player_status{id = RoleId, guild = StatusGuild} = Player,
	(StatusGuild#status_guild.support_id > 0 andalso StatusGuild#status_guild.is_support_asker == 0) andalso supporter_enter_scene(RoleId),
	case StatusGuild#status_guild.support_id > 0 of
		true when StatusGuild#status_guild.is_support_asker == 0 ->
			lib_scene:change_act_label(RoleId, ?ACT_LABEL_SUPPORT, 1);
		true -> ignore;
		_ ->
			ignore % lib_scene:change_act_label(RoleId, ?ACT_LABEL_SUPPORT, 0)
	end,
	{ok, Player};
handle_event(Player, _EventCallback) ->
	{ok, Player}.

login_refresh(RoleId, GuildId) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	SupportIds = maps:keys(GuildSupportMap),
	F = fun(SupportId, Ack) ->
		case maps:get(SupportId, GuildSupportMap, []) of
			#guild_support{support_cfg_id = SupportCfgId, ask_id = RoleId, support_role_list = RoleList
			} = GuildSupport ->
				%% 请求 和 协助状态冲突的才取消
				case is_conflict(SupportCfgId) of
					true ->
						case RoleList of
							[_|_] ->
								%% 更新协助者协助状态
								F1 = fun(TSupporterId, TAck) ->
									lib_player:apply_cast(
										TSupporterId, ?APPLY_CAST_SAVE, ?MODULE, reset_player_support_status, []),
									TAck
								end,
								lists:foldl(F1, ok, RoleList);
							_ ->
								skip
						end,
						NewSupportMap = maps:remove(SupportId, GuildSupportMap),
						mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, send_to_guild_member,
							[GuildSupport, maps:size(NewSupportMap)]
						),
						% db_delete_guild_support(SupportId),
						save_guild_support_map(GuildId, NewSupportMap),
						Ack;
					_ ->
						Ack
				end;
			_ ->
				Ack
		end
	end,
	lists:foldl(F, ok, SupportIds).

%% ---------------------------------------------------------------
%% @doc 更新协助信息
%% 1. update_team_info  --- 更新队伍信息
%%  param: Player
%% 说明: 在boss类玩法中协助者伤害需要计算到请求者队伍当中，因此队伍
%%        信息发生变更时需要同步变更协助中的队伍信息 和 场景协助信息
%%
%% 2. update_scene_info --- 更新场景信息
%%  param: RoleId/Player
%% ---------------------------------------------------------------
%% 请求者
update_team_info(Player) ->
	#player_status{id = RoleId, guild = StatusGuild, team = StatusTeam} = Player,
	#status_guild{
		id          = GuildId
		,support_id = SupportId
		,is_support_asker = IsAsker
	} = StatusGuild,
	%% 更新公会协助单数据
	#status_team{
		team_id = TeamId,
		leader_name = LeaderName
	} = StatusTeam,
	TeamInfo = {TeamId, LeaderName},
	IsAsker == 1 andalso mod_guild_support:apply_cast(?MODULE, update_support_team, [RoleId, SupportId, GuildId, TeamInfo]),
	ok.

%% 更新队伍信息(公会进程处理)
update_support_team(RoleId, SupportId, GuildId, TeamInfo) ->
	SupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, SupportMap, []) of  %% 必须是协助单的请求者
		#guild_support{ask_id = RoleId, support_role_list = RoleList, content = Content} = SupportInfo ->
			{TeamId, LeaderName} = TeamInfo,
			NewSupportInfo = SupportInfo#guild_support{
			    team_id           = TeamId,
			    team_leader_name  = LeaderName
			},
			%% 更新其他协助者的队伍信息
			lists:map(fun(SupporterId) ->
				update_local_boss_team_info(SupporterId, TeamInfo, Content)
			      end, RoleList),
			NewSupportMap = maps:put(SupportId, NewSupportInfo, SupportMap),
			save_guild_support_map(GuildId, NewSupportMap);
		_ ->
			skip
	end.

%% 协助者
update_local_boss_team_info(RoleId, TeamInfo, Content) when is_integer(RoleId) ->
	lib_player:apply_cast(
		RoleId, ?APPLY_CAST_SAVE, ?MODULE, update_local_boss_team_info_do, [TeamInfo, Content]),
	ok.

update_local_boss_team_info_do(Player, TeamInfo, Content) ->
	%% 1> 更新玩家身上数据
	#player_status{id = RoleId, guild = StatusGuild,
		scene = SceneId, scene_pool_id = PoolId} = Player,
	#status_guild{support_leader_id = AskId} =StatusGuild,
	AskName = lib_role:get_role_name(AskId),
	{TeamId, LeaderName} = TeamInfo,
	NewStatusGuild = StatusGuild#status_guild{
		support_team_id = TeamId,
		support_leader_name = LeaderName
	},
	Arg = [{support_id, AskId},
		{support_name, AskName},
		{support_team, TeamId},
		{support_team_name, LeaderName},
		{support_content, Content}
	],
	%% 2> 更新场景数据
	mod_scene_agent:update(SceneId, PoolId, RoleId, Arg),
	{ok, Player#player_status{guild = NewStatusGuild}}.

%% 协助者进入场景后更新队伍信息
supporter_enter_scene(RoleId) when is_integer(RoleId) ->
	lib_player:apply_cast(
		RoleId, ?APPLY_CAST_STATUS, ?MODULE, supporter_enter_scene, []);

supporter_enter_scene(Player) ->
	#player_status{scene = SceneId, scene_pool_id = PoolId, id = RoleId, guild = #status_guild{id = GuildId}} = Player,
	lib_guild_support_mod:is_supporting(Player) andalso
		mod_guild_support:apply_cast(?MODULE, fetch_my_support_info, [RoleId, GuildId, SceneId, PoolId]),
	{ok, Player}.

%% 查找我的协助对象和信息(公会进程处理)
fetch_my_support_info(RoleId, GuildId, SceneId, PoolId) ->
	GuildMaps = lib_guild_support_mod:get_guild_support_map(GuildId),
	Values = maps:values(GuildMaps),
	fetch_my_support_info_do(Values, RoleId, SceneId, PoolId).
fetch_my_support_info_do([SupportInfo|T], RoleId, SceneId, PoolId) ->
	#guild_support{
		ask_id = AskId,
		team_id = TeamId,
		team_leader_name = LeaderName,
		support_role_list = RoleList,
		content = Content,
		module = Handler
	} = SupportInfo,
	case lists:member(RoleId, RoleList) of
		true  ->
			ContentArgs =
			case check_need_content(Handler) of
				true -> [{support_content, Content}];
				_ 	 -> []
			end,
			Arg = [
				{support_id, AskId},
				{support_name, lib_role:get_role_name(AskId)},
				{support_team, TeamId},
				{support_team_name, LeaderName}
			],
			mod_scene_agent:update(SceneId, PoolId, RoleId, ContentArgs ++ Arg);
		false ->
			fetch_my_support_info_do(T, RoleId, SceneId, PoolId)
	end;
fetch_my_support_info_do(_, _, _, _) -> ok.

%% ----------------------------------------------------------------
%% 请求协助者更新场景信息(例如护送玩法有两段场景)
update_scene_info(RoleId) when is_integer(RoleId) ->
	lib_player:apply_cast(
		RoleId, ?APPLY_CAST_SAVE, ?MODULE, update_scene, []),
	ok.

update_scene(Player) ->
	#player_status{id = RoleId, scene = Scene, scene_pool_id = PoolId,
		copy_id = CopyId, x = X, y = Y, guild = StatusGuild} = Player,
	#status_guild{
		id               = GuildId,
		is_in_support    = IsInSupport,
		is_support_asker = IsAsker,
		support_id       = SupportId
	} = StatusGuild,
	case GuildId > 0 andalso IsInSupport > 0 andalso IsAsker > 0 of
		true ->
			SceneInfo = {Scene, PoolId, CopyId, X, Y},
			mod_guild_support:apply_cast(?MODULE, update_support_scene, [RoleId, SupportId, GuildId, SceneInfo]);
		_ ->
			skip
	end,
	{ok, Player}.

%% 更新场景信息(公会进程处理)
update_support_scene(RoleId, SupportId, GuildId, SceneInfo) ->
	SupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, SupportMap, []) of  %% 必须是协助单的请求者
		#guild_support{ask_id = RoleId} = SupportInfo ->
			{Scene, PoolId, CopyId, X, Y} = SceneInfo,
			NewSupportInfo = SupportInfo#guild_support{
				ask_scene_id = Scene,
				ask_pool_id  = PoolId,
				ask_copy_id  = CopyId,
				ask_x        = X,
				ask_y        = Y
			},
			NewSupportMap = maps:put(SupportId, NewSupportInfo, SupportMap),
			save_guild_support_map(GuildId, NewSupportMap);
		_ ->
			skip
	end.

%% ---------------------------------------------------------------------------
%% 公会进程处理的一些逻辑
%% ---------------------------------------------------------------------------
%% 请求者删除请求
delete_support_by_asker(GuildId, SupportId) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		SupportInfo = #guild_support{
			ask_id = AskId, support_cfg_id = SupportCfgId,
			module = Handler, support_role_list = RoleList
		} ->
			case is_conflict(SupportCfgId) of
				true ->
					%% 更新协助者协助状态
					F = fun(TSupporterId) ->
						lib_player:apply_cast(
							TSupporterId, ?APPLY_CAST_SAVE, ?MODULE, reset_player_support_status, []),
							after_support_end(Handler, TSupporterId, ?SUPPORT_CANCEL, SupportInfo),
							lib_log_api:log_guild_support_reward(
								TSupporterId, GuildId, SupportId, SupportCfgId, ?SUPPORT_CANCEL
							)
					    end,
					lists:map(F, RoleList),
					NewGuildSupportMap = maps:remove(SupportId, GuildSupportMap),
					after_support_end(Handler, AskId, ?SUPPORT_CANCEL, SupportInfo),
					% db_delete_guild_support(SupportId),
					save_guild_support_map(GuildId, NewGuildSupportMap),
					mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, send_to_guild_member,
						[SupportInfo, maps:size(NewGuildSupportMap)]
					);
				_ ->
					skip
			end;
		_ ->
			skip
	end.

%% 更新支援角色列表(协助者进入场景)
add_into_support_role_list(GuildId, SupportId, RoleId) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{support_role_list = RoleList} = GuildSupport ->
			NewGuildSupport = GuildSupport#guild_support{
				support_role_list = [RoleId|RoleList]
			},
			NewGuildSupportMap = maps:put(SupportId, NewGuildSupport, GuildSupportMap),
			% db_update_support_role_list(GuildId, SupportId, [RoleId|RoleList]),
			save_guild_support_map(GuildId, NewGuildSupportMap);
		_ ->
			skip
	end.

%% 将协助者从协助列表中删除(协助者退出场景)
delete_from_support_role_list(GuildId, SupportId, RoleId) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{
			module = Handler, support_cfg_id = SupportCfgId,
			support_role_list = RoleList, status = Status
		} = GuildSupport ->
			case Status == 2 of
				true ->
					NewGuildSupportMap = maps:remove(SupportId, GuildSupportMap),
					save_guild_support_map(GuildId, NewGuildSupportMap),
					mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, send_to_guild_member,
						[GuildSupport, maps:size(NewGuildSupportMap)]
					);
					% db_delete_guild_support(SupportId);
				_ ->
					case lists:member(RoleId, RoleList) of
						true ->
							NewRoleList = lists:delete(RoleId, RoleList),
							NewGuildSupport = GuildSupport#guild_support{support_role_list = NewRoleList},
							NewGuildSupportMap = maps:put(SupportId, NewGuildSupport, GuildSupportMap),
							after_support_end(Handler, RoleId, ?SUPPORT_CANCEL, GuildSupport),
							lib_log_api:log_guild_support_reward(
								RoleId, GuildId, SupportId, SupportCfgId, ?SUPPORT_CANCEL
							),
							% db_update_support_role_list(GuildId, SupportId, NewRoleList),
							save_guild_support_map(GuildId, NewGuildSupportMap);
						_ ->
							skip
					end
			end;
		_ ->
			skip
	end.

%% 请求者/协助者 取消协助/退出场景
delete_from_support_by_player(RoleId, GuildId, _SupportId) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	SupportList = maps:keys(GuildSupportMap),
	F = fun(TSupportId, Ack) ->
		case maps:get(TSupportId, GuildSupportMap, []) of
			%% 1> 请求者取消协助/退出
			#guild_support{
				support_cfg_id = SupportCfgId, support_sid = SupportId,
				ask_id = RoleId, support_role_list = RoleList, module = Handler
			} = SupportInfo ->
				case is_conflict(SupportCfgId) of
					true ->
						%% 更新协助者协助状态
						F1 = fun(TSupporterId) ->
							lib_player:apply_cast(
								TSupporterId, ?APPLY_CAST_SAVE, ?MODULE, reset_player_support_status, []),
								after_support_end(Handler, TSupporterId, ?SUPPORT_CANCEL, SupportInfo),
								lib_log_api:log_guild_support_reward(
									TSupporterId, GuildId, SupportId, SupportCfgId, ?SUPPORT_CANCEL
								)
						    end,
						lists:map(F1, RoleList),
						NewGuildSupportMap = maps:remove(TSupportId, GuildSupportMap),
						% db_delete_guild_support(TSupportId),
						save_guild_support_map(GuildId, NewGuildSupportMap),
						%% 取消协助后的处理
						after_support_end(Handler, RoleId, ?SUPPORT_CANCEL, SupportInfo),
						{ok, Bin} = pt_400:write(40053, [?SUCCESS, SupportId, SupportCfgId]),
						lib_server_send:send_to_uid(RoleId, Bin),
						mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, send_to_guild_member,
							[SupportInfo, maps:size(NewGuildSupportMap)]
						),
						Ack;
					_ ->
						Ack
				end;
			%% 2> 协助者取消协助/退出
			#guild_support{
				support_sid = SupportId, support_cfg_id = SupportCfgId,
				support_role_list = RoleList, ask_id = AskId, module = Handler
			} = GuildSupport ->
				case lists:member(RoleId, RoleList) of
					true ->
						NewRoleList = lists:delete(RoleId, RoleList),
						NewGuildSupport = GuildSupport#guild_support{support_role_list = NewRoleList},
						NewGuildSupportMap = maps:put(TSupportId, NewGuildSupport, GuildSupportMap),
						% db_update_support_role_list(GuildId, TSupportId, NewRoleList),
						save_guild_support_map(GuildId, NewGuildSupportMap),
						%% 取消协助后的处理
						after_support_end(Handler, RoleId, ?SUPPORT_CANCEL, GuildSupport),
						lib_log_api:log_guild_support_reward(
							RoleId, GuildId, SupportId, SupportCfgId, ?SUPPORT_CANCEL
						),
						%% 取消头标
						lib_scene:change_act_label(RoleId, ?ACT_LABEL_SUPPORT, 0),
						%% 退出推送更新协议
						{ok, Bin0} = pt_400:write(40055, [1, 0, SupportId]),
						{ok, Bin1} = pt_400:write(40053, [?SUCCESS, SupportId, SupportCfgId]),
						lib_server_send:send_to_uid(RoleId, <<Bin0/binary, Bin1/binary>>),
						%% 推送给请求者
						{ok, Bin2} = pt_400:write(40061, [RoleId]),
						lib_server_send:send_to_uid(AskId, Bin2),
						Ack;
					_ ->
						Ack
				end;
			_ ->
				Ack
		end
	end,
	lists:foldl(F, ok, SupportList).

%% ---------------------------------------------------------------------------
%% 玩家进程处理协助状态
%% ---------------------------------------------------------------------------
%% 重置协助者协助状态为非协助态
reset_player_support_status(Player) ->
	#player_status{id = RoleId, sid = Sid, guild = StatusGuild, scene = SceneId,
		scene_pool_id = PoolId} = Player,
	% ?INFO_TTY("reset_player_support_status ~w~n",[RoleId]),
	NewStatusGuild = change_support_status(
		StatusGuild, 0, 0, 0, [], 0),
	send_msg(Sid, 40055, [1, 0, 0]),
	Arg = [
		{support_id, 0},
		{support_name, ""},
		{support_team, 0},
		{support_team_name, ""},
		{support_content, []}
	],
	mod_scene_agent:update(SceneId, PoolId, RoleId, Arg),
	lib_scene:change_act_label(RoleId, ?ACT_LABEL_SUPPORT, 0),
	{ok, NewPlayer} = lib_player_event:dispatch(Player#player_status{guild = NewStatusGuild}, ?EVENT_CANCEL_SUPPORT, []),
	NewPlayer.

%% 更新玩家协助状态(协助者/请求者)
refresh_player_support_status(Player) ->
	#player_status{guild = StatusGuild} = Player,
	NewStatusGuild = change_support_status(
		StatusGuild, 0, 0, 0, [], 0),
	Player#player_status{guild = NewStatusGuild}.

change_support_status(StatusGuild, SupportId, IsInSupport, IsAsker, SceneInfo, LeaderId) ->
	NewStatusGuild = StatusGuild#status_guild{
		support_id         = SupportId,
		is_in_support      = IsInSupport,
		is_support_asker   = IsAsker,
		support_scene_info = SceneInfo,
		support_leader_id  = LeaderId
		,support_cfg_id    = 0
	},
	NewStatusGuild.

%% 玩法结束推送
finish_send_msg_to_supporter(RoleId, AskFigure, SupportCfgId, BossId) ->
	send_msg_role(RoleId, 40054, [1, SupportCfgId, AskFigure, BossId]).

%% ------------------------------------------------------------
%% @doc 前往协助 - 在场景中直接前往协助，
%%                  其他由各玩法自行管理
%% ------------------------------------------------------------
go_to_support_in_scene(Player, SceneInfo, SupportId, AskerId, SupportCfgId) ->
	#player_status{id = RoleId, sid = Sid,  guild = StatusGuild} = Player,
	NewStatusGuild = StatusGuild#status_guild{
		support_id = SupportId, is_in_support = 1,
		support_scene_info = SceneInfo
		,support_leader_id = AskerId
		,support_cfg_id    = SupportCfgId
	},
	NewPlayer = Player#player_status{guild = NewStatusGuild},
	% db_update_support_info(RoleId, SupportId, 0),
	%% 更改头标
	ActLabel = ?ACT_LABEL_SUPPORT,
	lib_scene:change_act_label(RoleId, ActLabel, 1),
	send_msg(Sid, 40052, [?SUCCESS, SupportId, SupportCfgId]),
	supporter_enter_scene(NewPlayer),
	NewPlayer.

%% ------------------------------------------------------------------
%% @doc 玩法结束 - 各个玩法调用接口
%% ------------------------------------------------------------------
finish_normal_game_play(Player, Args) ->
	#player_status{id = RoleId, guild = StatusGuild, scene = _SceneId,
		scene_pool_id = _PoolId, copy_id = _CopyId, x = _X, y = _Y} = Player,
	#status_guild{
		id               = GuildId,
		support_id       = SupportId,
		is_in_support    = IsInSupport,
		is_support_asker = IsAsker
	} = StatusGuild,
	case SupportId > 0 of
		true when IsInSupport == 1 ->
			case IsAsker == 1 of
				true ->
					mod_guild_support:apply_cast(?MODULE, asker_finish_support, [RoleId, GuildId, SupportId, Args]);
				_ ->
					%% 协助者
					mod_guild_support:apply_cast(?MODULE, supporter_finish_support, [RoleId, GuildId, SupportId, Args]),
					lib_achievement_api:support_event(Player, 1)
			end;
		_ ->
			skip
	end,
	Player.

%% ------------------------------------------------------------------
asker_finish_support(RoleId, GuildId, SupportId, Args) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{
			ask_id = RoleId, support_role_list = RoleList, module = Handler, support_cfg_id = CfgId
		} = GuildSupport ->
			case check_success_finish(Handler, GuildSupport, Args) of
				false -> %% 击杀非自己召唤的入侵怪,跳过
					skip;
				_ ->
					NewGuildSupport = GuildSupport#guild_support{
						status = ?SUPPORT_FINISH
					},
					case RoleList == [] of
						true ->
							NewGuildSupportMap = maps:remove(SupportId, GuildSupportMap),
							save_guild_support_map(GuildId, NewGuildSupportMap),
							mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, send_to_guild_member,
								[NewGuildSupport, maps:size(NewGuildSupportMap)]
							),
							after_support_end(Handler, RoleId, ?SUPPORT_FAIL, GuildSupport);
							% db_delete_guild_support(SupportId);
						_ ->
							NewGuildSupportMap = maps:put(SupportId, NewGuildSupport, GuildSupportMap),
							save_guild_support_map(GuildId, NewGuildSupportMap),
							thank_guild_support(RoleId, GuildId, SupportId, Args),
							after_support_end(Handler, RoleId, ?SUPPORT_SUCCESS, GuildSupport)
					end,
					%% 1> 请求 和 协助冲突的玩法，请求者修改状态，
					%%    协助者有另外的逻辑清理状态
					%% 2> 不冲突的玩法，请求者不修改状态(有可能在进行其他协助)，
					%%    协助者修改状态(因为单子完成只触发了请求者的逻辑)
					case is_conflict(CfgId) of
						true ->
							lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, finish_support_callback, []);
						_ ->
							F = fun(TRoleId) ->
								lib_player:apply_cast(TRoleId, ?APPLY_CAST_SAVE, ?MODULE, finish_support_callback, [])
							end,
							lists:map(F, RoleList)
					end
			end;
		_ ->
			skip
	end,
	ok.

supporter_finish_support(RoleId, GuildId, SupportId, Args) ->
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{
			ask_id = AskId, content = Content,
			support_cfg_id = CfgId, module = Handler
		} = GuildSupport->
			case check_success_finish(Handler, GuildSupport, Args) of
				false -> %% 击杀非请求者召唤的入侵怪,跳过
					skip;
				_ ->
					AskFigure =
						case lib_role:get_role_show(AskId) of
							#ets_role_show{figure = Figure} ->
								Figure;
							_ ->
								#figure{}
						end,
					case Content of
						{_, {_BossType, BossId}} ->
							finish_send_msg_to_supporter(RoleId, AskFigure, CfgId, BossId);
						{_, ObjectId} ->
							finish_send_msg_to_supporter(RoleId, AskFigure, CfgId, ObjectId);
						_ ->
							skip
					end,
					% after_support_end(Handler, RoleId, ?SUPPORT_SUCCESS, GuildSupport),
					%% 修改头标 & 状态数据
					lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, finish_support_callback, []),
					%% 修改协助进度
					NewGuildSupport = GuildSupport#guild_support{status = ?SUPPORT_FINISH},
					%% 日志
					% lib_log_api:log_guild_support_reward(RoleId, GuildId, SupportId, CfgId),
					NewSupportMap   = maps:put(SupportId, NewGuildSupport, GuildSupportMap),
					save_guild_support_map(GuildId, NewSupportMap)
			end;
		_ ->
			%% 保底处理
			lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, finish_support_callback, []),
			skip
	end.

finish_support_callback(Player) ->
	NewPlayer = reset_player_support_status(Player),
	{ok, NewPlayer}.

%% ------------------------------------------------------------------
%% @doc 玩法结束,协助结算
%% ------------------------------------------------------------------
%% 感谢协助(协助结束后公会进程触发)
%% 1.请求者和协助者均得到名望值  2.请求者得到一个感谢礼包(有感谢协助者)
thank_guild_support(RoleId, GuildId, SupportId, Args) ->
	mod_guild:apply_cast(lib_guild_tribe_mod, update_guild_assist, [GuildId]),
	GuildSupportMap = get_guild_support_map(GuildId),
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{
			ask_id = AskId, support_cfg_id = SupportCfgId, module = Handler,
			support_role_list = RoleList, content = Content
		} = GuildSupport when RoleId == AskId ->
			% {_Key, _ExtraValue} = Content,
			NewRoleList = filter_role_list(Args, RoleList),
			case NewRoleList of
				[] ->
					skip;
				_ ->
					lib_player:apply_cast(AskId, ?APPLY_CAST_STATUS, ?HAND_OFFLINE,
						guild_thank, add_thank_packet,
						[GuildId, SupportId, AskId, NewRoleList, SupportCfgId, Content]
					)
			end,
			%% 增加社团声望 & 触发成就 & 记录日志
			F = fun(TRoleId, Ask) ->
				TRoleId =/= AskId andalso lib_player:apply_cast(
					TRoleId, ?APPLY_CAST_SAVE, ?MODULE, add_reputation, [SupportCfgId, AskId]
				),
				TRoleId =/= AskId andalso contract_task_api:response_help_trigger(TRoleId, 1),
				lists:member(TRoleId, NewRoleList) andalso
				begin
					after_support_end(Handler, TRoleId, ?SUPPORT_SUCCESS, GuildSupport),
					lib_log_api:log_guild_support_reward(TRoleId, GuildId, SupportId, SupportCfgId, ?SUPPORT_SUCCESS)
				end,
				(SupportCfgId =:= 2 andalso TRoleId =/= RoleId) andalso begin
					lib_achievement_api:async_event(TRoleId, lib_achievement_api, guild_collect_support_event, 1),
					lib_guild_collect:collect_assist_count_increment(TRoleId)
				end,
				Ask
			end,
			spawn(fun() -> lists:foldl(F, ok, NewRoleList++[RoleId]) end),
			NewGuildSupportMap = maps:remove(SupportId, GuildSupportMap),
			% db_delete_guild_support(SupportId),
			save_guild_support_map(GuildId, NewGuildSupportMap),
			mod_guild:apply_cast_guild_member(GuildId, 1, ?MODULE, send_to_guild_member,
				[GuildSupport, maps:size(NewGuildSupportMap)]
			);
		_A ->
			skip
	end.

%% 发送协助单取消状态
send_to_guild_member(Player, GuildSupport, SupportCount) ->
	#player_status{
		id = RoleId, sid = Sid, scene = SceneId
	} = Player,
	%% 当协助列表为空的时候需要推送56，前端取消sos
	case SupportCount > 0 of
		true -> ignore;
		_ ->
			lib_server_send:send_to_sid(Sid, pt_400, 40056, [1, 0])
	end,
	%% 社团采集取消，给驻地玩家推送
	case lib_guild:is_guild_scene(SceneId) of
		true ->
			guild_support_collect:update_support(2, GuildSupport, RoleId);
		_ ->
			ignore
	end,
	{ok, Player}.

%% 筛选不符合条件的玩家
%% 1. 护送玩法,协助者必须在第二段场景
filter_role_list(EtsRoleList, RoleList) ->
	case EtsRoleList of
		[{_, _}|_] ->
			[RoleId||{RoleId, Scene}<-EtsRoleList, lists:member(Scene, ?HUSONG_SCENE2) == true];
		% [RoleId1||RoleId1<-RoleList, lists:member(RoleId1, FilterList)]
		_ ->
			RoleList
	end.

%% 协助者&请求者增加社团声望
add_reputation(Player, SupportCfgId, _AskId) ->
	case data_guild:get_guild_support_cfg(SupportCfgId) of
		#base_guild_support{reward_reputation = AddReputation} ->
			%% 公会徽章加成
			Effect = lib_guild_badge:badge_ability_for_repution(Player#player_status.guild#status_guild.badges),
			NewAddReputation = util:ceil(AddReputation*(1+Effect/100)),
			Produce = #produce{reward = [{?TYPE_HONOUR, 0, NewAddReputation}], type = guild_support, remark = "社团协助"},
			{ok, NewPlayer} = lib_goods_api:send_reward_with_mail(Player, Produce, ?MOD_GUILD),
			%% 发放经验
			% case SupportCfgId of
			% 	4 when RoleId =/= AskId -> %% 护送玩法且是协助者才加经验
			% 		case data_convoy:get_convoy_exp(Figure#figure.lv) of
			% 			[_, AddExp] ->
			% 				Count = lib_daily:get_count(RoleId, ?MOD_CONVOY, ?CONVOY_COUNTER_DAILY_SUPPORT),
			% 				case Count >= 3 of
			% 					true -> NewPlayer1 = NewPlayer;
			% 					_ -> NewPlayer1 = lib_player:add_exp(NewPlayer, AddExp)
			% 				end;
			% 			_ -> NewPlayer1 = NewPlayer
			% 		end,
			% 		lib_daily:increment(RoleId, ?MOD_CONVOY, ?CONVOY_COUNTER_DAILY_SUPPORT);
			% 	_ ->
			% 		NewPlayer1 = NewPlayer
			% end,
			% send_msg(Sid, 40015, [GuildId, GuildName, GuildLv, Position,PositionName, NewReputation]),
			{ok, NewPlayer};
		_ ->
			{ok, Player}
	end.

%% -------------------------- builtin function ---------------------
%% 获取队长名字
get_team_leader_name(TeamId, LeaderName, RoleId) ->
	case TeamId > 0 of
		true ->
			LeaderName;
		_ ->
			case lib_role:get_role_show(RoleId) of
				#ets_role_show{figure = Figure} ->
					Figure#figure.name;
				_ ->
					""
			end
	end.

%% 判断是普通玩法场景中
is_in_normal_scene(SceneId) ->
	case data_scene:get(SceneId) of
		#ets_scene{type = SceneType} ->
			case lists:member(SceneType, ?GAME_PLAY_SCENE) of
				true -> true;
				_    -> false
			end;
		_ ->
			false
	end.

%% 判断是否在特殊玩法场景中(多段自由切换)
%% 1. 护送需要切换两个场景
is_in_special_scene(SceneId) ->
	case lists:member(SceneId, ?GAME_PLAY_SPECIAL_SCENE) of
		true -> true;
		_ -> false
	end.

%% 请求 和 协助是否冲突
is_conflict(SupportCfgId) ->
	case data_guild:get_guild_support_cfg(SupportCfgId) of
		#base_guild_support{is_conflict = ?IS_CONFLICT} -> true;
		_ -> false
	end.

%% 退出场景是否取消协助
is_out_scene_cancel(SupportCfgId) ->
	case data_guild:get_guild_support_cfg(SupportCfgId) of
		#base_guild_support{out_scene_cancel = ?OUT_SCENE_CANCEL} -> true;
		_ -> false
	end.

%% 判断请求者能否发多条请求(根据配置)
check_can_ask_by_config(Module, SubModule) ->
	F = fun(CfgId) ->
		case data_guild:get_guild_support_cfg(CfgId) of
			#base_guild_support{
				module_id = Module, sub_mod_id = SubModule, is_conflict = ?NOT_CONFLICT
			} -> true;
			_ -> false
		end end,
	lists:any(F, data_guild:get_all_support_cfg()).

%% 判断请求者能否发多条请求(根据已有数据)
check_can_ask_by_data(RoleId, GuildSupport, GameInfo, SupportCfgId) ->
	case GuildSupport of
		%% 只需要判断相同玩法的
		#guild_support{ask_id = AskId, support_role_list = SupportList,
			content = Content, support_cfg_id = SupportCfgId
		} = GuildSupport ->
			%% 1> 请求者和协助者互斥状态不在玩家进程判断了，需要在管理进程进行判断
			%% 2> 请求者是否能发起多次请求/协助者能否发起请求判断(同一boss单不能重复)
			case data_guild:get_guild_support_cfg(SupportCfgId) of
				#base_guild_support{is_conflict = ?IS_CONFLICT} ->
					case RoleId =:= AskId orelse lists:member(RoleId, SupportList) of
						true -> false;
						_ -> true
					end;
				_ ->
					case RoleId =:= AskId orelse lists:member(RoleId, SupportList) of
						true ->
							{_, BossId} = GameInfo,
							case Content of
								{_, BossId} -> false;
								_ -> true
							end;
						_ -> true
					end
			end;
		_ -> true
	end.

%% 获得社团协助数据
get_guild_support_map(GuildId) ->
	case get(?P_GUILD_SUPPORT(GuildId)) of
		undefined -> GuildSupportMap = maps:new();
		GuildSupportMap -> ok
	end,
	GuildSupportMap.

%% 保存社团协助数据
save_guild_support_map(GuildId, SupportMap) ->
	put(?P_GUILD_SUPPORT(GuildId), SupportMap).

%% 清理社团协助数据
clean_guild_support_map(GuildId) ->
	erase(?P_GUILD_SUPPORT(GuildId)).

get_support_cfg_id_by_module(Module, SubModule) ->
	CfgList = data_guild:get_all_support_cfg(),
	F = fun(TCfgId, TList) ->
		case data_guild:get_guild_support_cfg(TCfgId) of
			#base_guild_support{
				module_id  = Module,
				sub_mod_id = SubModule
			} ->
				[TCfgId|TList];
			_ ->
				TList
		end end,
	case lists:foldl(F, [], CfgList) of
		[CfgId|_] ->
			CfgId;
		_ ->
			0
	end.

pack_support_info([], PackList) -> PackList;
pack_support_info([SupportInfo|L], TPackList) ->
	{SupportSId, GuildSupport} = SupportInfo,
	#guild_support{
		support_cfg_id = SupportCfgId,
		ask_id         = AskId,
		status         = Status,
		content        = Content,
		extra_data 	   = ExtraData,
		create_time    = CreateTime
	} = GuildSupport,
	case lib_role:get_role_show(AskId) of
		#ets_role_show{figure = Figure} ->
			skip;
		_ -> Figure = #figure{}
	end,
	case Content of
		{_, {_, BossId}} -> skip;
		{_, BossId}      -> skip;
		_                -> BossId = 0
	end,
	case SupportCfgId == 0 orelse Status >= 2 of
		true ->
			PackList = TPackList;
		_ ->
			if SupportCfgId == 5 orelse SupportCfgId == 6 ->
					PackList = [{SupportSId, SupportCfgId, Figure, Status, BossId, CreateTime, util:term_to_string(ExtraData)}|TPackList];
				true ->
					PackList = [{SupportSId, SupportCfgId, Figure, Status, BossId, CreateTime, ""}|TPackList]
			end
	end,
	pack_support_info(L, PackList).

%% 发送消息
send_msg(Sid, Cmd, Msg) ->
	{ok, Bin} = pt_400:write(Cmd, Msg),
	lib_server_send:send_to_sid(Sid, Bin).

%% 发送消息
send_msg_role(RoleId, Cmd, Msg) ->
	{ok, Bin} = pt_400:write(Cmd, Msg),
	lib_server_send:send_to_uid(RoleId, Bin).

%% 发送错误消息
send_error(RoleId, ErrCode) ->
	{ok, Bin} = pt_400:write(40000, [ErrCode]),
	lib_server_send:send_to_uid(RoleId, Bin).

%% 条件判断
check([]) -> true;
check([Check|L]) ->
	case do_check(Check) of
		true         -> check(L);
		{false, Err} -> {false, Err}
	end.

%% 1. 请求协助相关
%% 1) 玩家进程
do_check({is_guild_exits, GuildId}) ->
	case GuildId > 0 of
		true ->
			true;
		_ ->
			{false, ?ERRCODE(err400_guild_not_exists)}
	end;
%% 玩法控制能不能发多条协助 以及 协助者能不能发送请求
do_check({can_ask, IsInSupport, Module, SubModule}) ->
	case check_can_ask_by_config(Module, SubModule) of
		true -> true;
		_ ->
			case IsInSupport > 0 of
				true -> {false, ?ERRCODE(err400_has_ask)};
				_ -> true
			end
	end;
%% 2) 公会进程
%% 控制参数,因为有可能是各玩法内部调用而不是协议发起
do_check({check_param, Module, SubModule, GameInfo}) ->
	case get_support_cfg_id_by_module(Module, SubModule) of
		CfgId when is_integer(CfgId), CfgId > 0 ->
			case GameInfo of
				{Value1, Value2} when is_integer(Value1), is_integer(Value2) ->
					true;
				_ -> {false, ?ERRCODE(err400_support_input_err)}
			end;
		_ -> {false, ?ERRCODE(err400_support_input_err)}
	end;
%% 数据判断能不能发多条协助(一个boss不能同时发多次/协助者不能再发自己协助的单)
do_check({has_asker_ask, RoleId, GuildId, GameInfo, IsAsker, SupportCfgId}) ->
	SupportMap  = get_guild_support_map(GuildId),
	SupportList = maps:to_list(SupportMap),
	IsConflict = is_conflict(SupportCfgId),
	%% 已经发送过请求的 或 协助状态会产生冲突的，就不能再发送
	case IsAsker of
		1 when IsConflict -> {false, ?ERRCODE(err400_has_ask)};
		_ ->
			F = fun({_Id, Support}, TList) ->
				case Support of
					#guild_support{support_sid = TSupportId} ->  %% 强化判断，防止发包的可能
						case check_can_ask_by_data(RoleId, Support, GameInfo, SupportCfgId) of
							false ->
								[TSupportId|TList];
							_ ->
								TList
						end;
					_ ->
						TList
				end end,
			case lists:foldl(F, [], SupportList) of
				[_SupportId|_] ->
					case IsAsker of  %% todo: 社团采集如果IsAsker==0时(因为玩家状态不设置)
						1 -> {false, ?ERRCODE(err400_has_ask)};
						_ -> {false, ?ERRCODE(err400_is_supporting)}
					end;
				_ ->
					true
			end
	end;

%% 2. 前往协助相关
%% 1) 玩家进程
do_check({is_in_guild, GuildId}) ->
	case GuildId > 0 of
		false  ->
			{false, ?ERRCODE(err400_not_in_guild)};
		_ ->
			true
	end;
do_check({check_list, Player}) ->
	case lib_player_check:check_list(Player, [alive]) of
		{false, Res}  ->
			{false, Res};
		_ ->
			#player_status{battle_attr = BattleAttr} = Player,
			if
				is_record(BattleAttr, battle_attr) andalso BattleAttr#battle_attr.ghost =/= 0 ->
					{false, ?ERRCODE(err120_ghost_state_limit)};
				true ->
					true
			end
	end;
do_check({action_lock, Player}) ->
	#player_status{scene = SceneId} = Player,
	%% 先判断锁再判断场景
	SceneRet = data_scene:get(SceneId),
	IsConvoying = convoy_api:is_convoying(Player),
	if
		not is_record(SceneRet, ets_scene) ->
			{false, ?ERRCODE(err400_cannot_support)};
		IsConvoying ->
			{false, ?ERRCODE(err400_cannot_support)};
		true ->
			#ets_scene{type = Type} = SceneRet,
			case lists:member(Type, ?CAN_NOT_GO_SUPPORT_SCENES) of
				true -> {false, ?ERRCODE(err400_cannot_support)};
				_ 	 -> true
			end
	end;
do_check({is_asker, IsAsker, SupportId, MySupportId}) ->
	case SupportId == MySupportId of
		true when IsAsker >0 ->
			{false, ?ERRCODE(err400_can_not_be_asker)};
		true ->
			{false, ?ERRCODE(err400_is_supporting)};
		_ ->
			true
	end;
do_check({is_supporting, IsInSupport, IsAsker, SupportCfgId}) ->
	case is_conflict(SupportCfgId) of
		%% 如果当前正在冲突玩法中
		true ->
			case IsAsker =< 0 of
				true -> {false, ?ERRCODE(err400_is_supporting)};
				_ -> {false, ?ERRCODE(err400_is_asker)}
			end;
		%% 如果当前正在非冲突(社团采集,社团跑环)玩法中
		_ ->
			case IsInSupport > 0 of
				true when IsAsker =< 0 ->
					{false, ?ERRCODE(err400_is_supporting)};
				true -> % 理论上这个分支不会执行
					{false, ?ERRCODE(err400_is_asker)};
				_ ->
					true
			end
	end;

%% 1) 公会进程
%% 根据玩法是否需要判断请求和协助互斥状态，来进行判断
%% 1> 请求 和 协助互斥的，如果玩家是请求者，不能去协助。也不能协助自己的单
%% 2> 请求 和 协助不互斥的，唯一需要判断的是，是不是自己的单
do_check({is_ask_id, SupportMap, SupportId, ReplyId}) ->
	SupportList = maps:values(SupportMap),
	case maps:get(SupportId, SupportMap, []) of
		#guild_support{ask_id = AskId, support_cfg_id = SupportCfgId} ->
			case data_guild:get_guild_support_cfg(SupportCfgId) of
				#base_guild_support{is_conflict = ?IS_CONFLICT} ->
					%% 有没同类的单子
					F = fun(#guild_support{
						support_cfg_id = TCfgId, support_role_list = TSupportRoleLIst, ask_id = TAskId
					}) ->
						case lists:member(ReplyId, TSupportRoleLIst) orelse ReplyId == TAskId of
							true when TCfgId =:= SupportCfgId -> true;
							_ -> false
						end end,
					Result = lists:any(F, SupportList),
					case Result of
						true -> {false, ?ERRCODE(err400_is_supporting)};
						_ ->
							case ReplyId == AskId of
								true -> {false, ?ERRCODE(err400_can_not_be_asker)};
								_ -> true
							end
					end;
				_ ->
					case ReplyId == AskId of
						true -> {false, ?ERRCODE(err400_can_not_be_asker)};
						_ -> true
					end
			end;
		_ ->
			{false, ?ERRCODE(err400_support_has_finish)}
	end;
% do_check({is_busy, SupportMap, SupportId, ReplyId}) ->
% 	case maps:get(SupportId, SupportMap, []) of
% 		#guild_support{} ->
% 			case convoy_api:is_convoying(ReplyId) of
% 				true  ->
% 					{false, ?ERRCODE(err500_husong_start)};
% 				false ->
% 					true
% 			end;
% 		_ ->
% 			true
% 	end;
do_check({support_status, SupportMap, SupportId}) ->
	case maps:get(SupportId, SupportMap, []) of
		#guild_support{status = Status} ->
			if
				Status > 1 ->
					{false, ?ERRCODE(err400_support_has_finish)};
				Status < 1 ->
					{false, ?ERRCODE(err400_support_not_action)};
				true ->
					true
			end;
		_ ->
			{false, ?ERRCODE(err400_support_has_finish)}
	end;
do_check({is_gameplay_open, ReplyLv, GuildSupportMap, SupportId}) ->
	case maps:get(SupportId, GuildSupportMap, []) of
		#guild_support{support_cfg_id = SupportCfgId} ->
			case data_guild:get_guild_support_cfg(SupportCfgId) of
				#base_guild_support{module_id = Module, sub_mod_id = SuModule} ->
					case SuModule == 0 of
						true -> OpenLv = lib_module:get_open_lv(Module);
						_ -> OpenLv = lib_module:get_open_lv(Module, SuModule)
					end,
					case ReplyLv >= OpenLv of
						true -> true;
						_    -> {false, ?ERRCODE(err400_lv_not_enough)}
					end;
				_ ->
					{false, ?ERRCODE(err400_support_not_exit)}
			end;
		_ ->
			{false, ?ERRCODE(err400_support_not_exit)}
	end;
do_check({is_role_num_max, SupportMap, SupportId}) ->
	case maps:get(SupportId, SupportMap, []) of
		#guild_support{support_cfg_id = CfgId, support_role_list = RoleList} ->
			#base_guild_support{support_limit = NumLimit} = data_guild:get_guild_support_cfg(CfgId),
			case length(RoleList) >= NumLimit of
				true -> {false, ?ERRCODE(err400_support_role_num_max)};
				_    ->  true
			end;
		_ ->
			{false, ?ERRCODE(err400_support_has_finish)}
	end;
do_check({check_mod, Player, ?MOD_LOCAL_BOSS, 3}) ->
	%% 疲劳了不能发，但是如果是首杀情况则可以发
	case local_boss_api:reward_boss_is_tired(Player) of
		true  ->
			%% 分线id就是BOSSid
			LeftCount = lib_counter:get_count(Player#player_status.id, ?MOD_LOCAL_BOSS,
				?COUNT_REWARD_BOSS_COUNTER_KILL, Player#player_status.scene_pool_id),
			case LeftCount == 0 of
				true  ->
					true;
				false ->
					{false, ?ERRCODE(err460_tried_max)}
			end;
		false -> true
	end;
do_check({check_mod, Player, ?MOD_DESERTED_BOSS, 0}) ->
	case local_boss_api:deserted_boss_is_tired(Player) of
		true  -> {false, ?ERRCODE(err461_tire_max)};
		false -> true
	end;
do_check({check_mod, _Player, _, _}) ->
	true;
do_check({is_count_enough, _RoleId, SupportMap, SupportId}) ->
	case maps:get(SupportId, SupportMap, []) of
		#guild_support{support_cfg_id = CfgId} ->
			%% 每日协助次数
			case data_guild:get_guild_support_cfg(CfgId) of
				#base_guild_support{module_id = Mod, sub_mod_id = SubMod} ->
					% DailyCount = lib_daily:get_count(RoleId, Mod, SubMod, 1),
					DailyCount = 0,
					case DailyCount < get_daily_support_count(Mod, SubMod) of
						true -> true;
						_ -> {false, ?ERRCODE(err400_support_count_not_enough)}
					end;
				_ ->
					true
			end;
		_ ->
			{false, ?ERRCODE(err400_support_has_finish)}
	end;
do_check({sub_module_check, GuildId, RoleId, SupportId, _SupportCfgId, ActionLock, Scene}) ->
	case ets:lookup(?ETS_GUILD_RUN_ASSIST, GuildId) of
		[#guild_run_assist_data{data = Map}|_] ->
			case maps:get(SupportId, Map, false) of
				#assist_instance{assist_type = AssistType, fail_role = FailRoles} ->
					case lists:member(RoleId, FailRoles) of
						true ->
							{false, ?ERRCODE(err417_have_failed)};
						_ ->
							InGuild = lib_guild_api:check_in_guild_scene(Scene),
							if
								AssistType == ?GUILD_RUN_ASSIST_BOSS andalso (ActionLock =/= free orelse InGuild) ->
									{false, ?ERRCODE(err417_not_receive)};
								ActionLock =/= free ->
									{false, ?ERRCODE(err417_not_receive)};
								true -> true
							end
					end;
				_ ->
					true
			end;
		_ ->
			true	
	end;
do_check(_Check) ->
	?ERR("lib_guild_support_mod check err: ~w~n",[_Check]),
	true.

%% 数据库字段
%%db_save_guild_support(SupportSid, GuildId, SupportCfgid, AskId, SupportList, Scene, X, Y, Content, Extra, Status) ->
%%	Sql = io_lib:format(?sql_guild_support_insert, [SupportSid, GuildId, SupportCfgid, AskId, util:term_to_string(SupportList), Scene, X, Y, util:term_to_string(Content), util:term_to_string(Extra), Status, utime:unixtime()]),
%%	db:execute(Sql).
%%
%%db_get_guild_support(GuildId) ->
%%	Sql = io_lib:format(?sql_guild_support_select, [GuildId]),
%%	db:get_all(Sql).
%%
%%db_delete_guild_support(SupportId) ->
%%	Sql = io_lib:format(?sql_guild_support_delete, [SupportId]),
%%	db:execute(Sql).
%%
%%db_update_support_role_list(GuildId, SupportId, RoleList) ->
%%	Sql = io_lib:format(?sql_guild_support_role_list_update, [util:term_to_string(RoleList), GuildId, SupportId]),
%%	db:execute(Sql).
%%
%%db_update_support_status(GuildId, SupportId, Status) ->
%%	Sql = io_lib:format(?sql_guild_support_status_update, [Status, GuildId, SupportId]),
%%	db:execute(Sql).
%%
%%db_update_support_asker_scene_info(GuildId, SupportId, NewSceneInfo) ->
%%	{SceneId, _, _, X, Y} = NewSceneInfo,
%%	Sql = io_lib:format(?sql_guild_support_asker_scene_info, [SceneId, X, Y, GuildId, SupportId]),
%%	db:execute(Sql).
%%
%%db_delete_guild_all_supports(GuildId) ->
%%	Sql = io_lib:format(?sql_guild_delete_supports, [GuildId]),
%%	db:execute(Sql).
%%
%%%% 玩家公会数据添加字段 support_id, is_support_asker, guild_reputation
%%db_update_support_info(RoleId, SupportId, IsSupportAsk) ->
%%	Sql = io_lib:format(?sql_guild_update_support, [SupportId, IsSupportAsk, RoleId]),
%%	db:execute(Sql).
%%
%%db_update_guild_reputation(RoleId, GuildReputation) ->
%%	Sql = io_lib:format(?sql_guild_update_guild_reputation, [GuildReputation, RoleId]),
%%	db:execute(Sql).
