%%-----------------------------------------------------------------------------
%% @Module  :       lib_limit_goal.erl
%% @Author  :       WJQ
%% @Created :       2019-03-29
%% @Description:    限时目标
%%-----------------------------------------------------------------------------
-module (lib_limit_goal).

-include("limit_goal.hrl").
-include("common.hrl").
-include("errcode.hrl").
-include("server.hrl").
-include("figure.hrl").
-include("goods.hrl").
-include("vip.hrl").
-include("def_fun.hrl").
-include("predefine.hrl").
-include("def_module.hrl").

-export ([
	login/2					%% 登录
	,logout/2				%% 登出
	,check_open_goal/3		%% 检查是否能开放目标
	,send_info/2			%% 发送主界面信息
	,send_task_reward/3		%% 发送任务奖励
	,active_limit_goal/2	%% 完成激活目标
	,trigger/5				%% 触发器
    ,count_limit_goal_attr/1 %% 统计星魂属性
    ,db_update_limit_goal_task/6
    ,db_insert_limit_goal_task/6
]).

%% =============================================== login start ==================================================
%% @return #{}
login(RoleId, Lv) ->
	GoalList = db_get_all_limit_goal_main(RoleId),
	TaskList = db_get_all_limit_goal_task(RoleId),
	TempMap = init_goal_list(GoalList, #{}),
	LastMap = init_task_list(TaskList, TempMap),
	case TempMap =:= #{} of
		true -> %% 检查是否能开放目标
			check_open_goal(RoleId, Lv, LastMap);
		false ->
			LastMap
	end.

%% 登出检测是否有待写入数据
logout(RoleId, LimitGoal) ->
    F = fun(T, Acc) ->
        case T of
            #task_status{
                goal_id = GoalId,
                task_id = TaskId,
                progress = Progress,
                extra = Extra,
                status = ?UNFINISH,
                write_status = ?WSTATUS_WAIT
            } ->
            	db_update_limit_goal_task(Progress, ?UNFINISH, Extra, RoleId, GoalId, TaskId),
                case Acc rem 20 of
                    0 -> timer:sleep(100);
                    _ -> skip
                end,
                Acc + 1;
            _ ->
            	Acc
        end
    end,
    F1 = fun(MainStatus, Acc) ->
        #main_status{task_list = TaskList, status = Status} = MainStatus,
        case Status of
            ?UNFINISH -> lists:foldl(F, Acc, TaskList);
            _ 	      -> Acc
        end
    end,
    lists:foldl(F1, 1, maps:values(LimitGoal)),
    ok.

%% 初始化目标列表
init_goal_list([[GoalId, Status, OpenTime]|T], AccMap) ->
	NewAccMap = maps:put(GoalId, #main_status{goal_id = GoalId, status = Status, open_time = OpenTime}, AccMap),
	init_goal_list(T, NewAccMap);
init_goal_list([_H|T], AccMap) ->
    init_goal_list(T, AccMap);
init_goal_list([], AccMap) -> AccMap.

%% 初始化任务列表
init_task_list([[GoalId, TaskId, Progress, Status, SExtra]|T], AccMap) ->
	Extra = util:bitstring_to_term(SExtra),
	MainStatus = maps:get(GoalId, AccMap, #main_status{goal_id = GoalId}),
	#main_status{task_list = TaskList} = MainStatus,
	TaskStatus = #task_status{goal_id = GoalId, task_id = TaskId, progress = Progress, status = Status, extra = Extra},
	NewTaskList = lists:keystore(TaskId, #task_status.task_id, TaskList, TaskStatus),
	NewMainStatus = MainStatus#main_status{task_list = NewTaskList},
	NewAccMap = maps:put(GoalId, NewMainStatus, AccMap),
	init_task_list(T, NewAccMap);
init_task_list([_H|T], AccMap) ->
    init_task_list(T, AccMap);
init_task_list([], AccMap) -> AccMap.

%% 检查是否能开放目标
%% @return #{}
check_open_goal(_RoleId, Lv, TempMap) when Lv < ?LIMIT_GOAL_LV -> TempMap;
check_open_goal(RoleId, _Lv, TempMap) ->
	case data_limit_goal:get_all_goal_ids() of
		[FirstGoalId|_] ->
			case data_limit_goal:get_limit_goal_main(FirstGoalId) of
				#limit_goal_main{precondition = []} ->
                    NowTime = utime:unixtime(),
                    db_replace_limit_goal_main(RoleId, FirstGoalId, ?UNFINISH, NowTime),
                    case maps:get(FirstGoalId, TempMap, false) of
                        false ->
        					maps:put(FirstGoalId, #main_status{goal_id = FirstGoalId, open_time = NowTime}, TempMap);
                        MainStatus ->
                            NewMainStatus = MainStatus#main_status{open_time = NowTime},
                            maps:put(FirstGoalId, NewMainStatus, TempMap)
                    end;
				_ ->
					TempMap
			end;
		_ ->
			TempMap
	end.
%% ================================================= login end ====================================================

send_info(RoleId, LimitGoal) when LimitGoal =:= #{} ->
	% ?PRINT("null [PackData]:~p~n", [[0, 0, [], 0]]),
	{ok, Bin} = pt_501:write(50101, [0, 0, [], 0]),
	lib_server_send:send_to_uid(RoleId, Bin);
send_info(RoleId, LimitGoal) ->
	TGoalIds = data_limit_goal:get_all_goal_ids(),
	GoalIds = lists:reverse(TGoalIds),
	PackData = pack_send_info(GoalIds, LimitGoal),
	{ok, Bin} = pt_501:write(50101, PackData),
	lib_server_send:send_to_uid(RoleId, Bin).

%% 打包发送信息
%% @return [GoalId, Status, TaskList, OpenTime]
pack_send_info([GoalId|T], LimitGoal) ->
	MainStatus = maps:get(GoalId, LimitGoal, false),
	case MainStatus of
		#main_status{status = Status, task_list = TaskList, open_time = OpenTime} when Status /= ?HAS_RECEIVE, OpenTime > 0 -> %% 未完成或未激活目标奖励
			PackTaskData = pack_task_list(TaskList, []),
			[GoalId, Status, PackTaskData, OpenTime];
		_ -> %% 未激活目标或已激活目标奖励
			pack_send_info(T, LimitGoal)
	end;
pack_send_info([], _LimitGoal) ->
	[0, 0, [], 0].

pack_task_list([#task_status{task_id = TaskId, progress = Progress, status = Status, extra = Extra}|T], AccList) ->
	NewAccList = [{TaskId, Progress, Status, util:term_to_string(Extra)}|AccList],
	pack_task_list(T, NewAccList);
pack_task_list([], AccList) -> AccList.

%% 发送任务奖励
send_task_reward(PS, GoalId, TaskId) ->
	#player_status{id = RoleId, figure = Figure, vip_status = Vip, limit_goal = LimitGoal} = PS,
    case check_goal_is_unlock(GoalId, LimitGoal) of
        true ->
            MainStatus = maps:get(GoalId, LimitGoal, #main_status{}),
            #main_status{task_list = TaskList} = MainStatus,
            case lists:keyfind(TaskId, #task_status.task_id, TaskList) of
                #task_status{status = ?FINISH} -> %% 可领取
                    case data_limit_goal:get_limit_goal_task(GoalId, TaskId) of
                        #limit_goal_task{reward = Reward} when Reward =/= [] ->
                            case lib_goods_api:can_give_goods(PS, Reward) of
                                true ->
                                    case do_send_task_reward(PS, GoalId, TaskId) of
                                        {ok, _IsFinGoal, NewPS} ->
                                            %% 限时任务奖励领取日志
                                            lib_log_api:log_limit_goal_reward(RoleId, Figure#figure.lv, Vip#vip_status.lv, GoalId, TaskId, Reward),
                                            Produce = #produce{
                                                type = limit_goal_task_reward, reward = Reward,
                                                remark = lists:concat(["GoalId:", GoalId, ", TaskId:", TaskId]), show_tips = 1
                                            },
                                            NewPS2 = lib_goods_api:send_reward(NewPS, Produce),
                                            NewPS3 = count_limit_goal_attr(NewPS2),
                                            LastPS = lib_player:count_player_attribute(NewPS3, ?MOD_LIMIT_GOAL, limit_goal),
                                            lib_player:send_attribute_change_notify(LastPS, ?NOTIFY_ATTR),
                                            {ok, BinData} = pt_501:write(50102, [?SUCCESS, GoalId, TaskId]),
                                            lib_server_send:send_to_uid(RoleId, BinData),
                                            {ok, LastPS};
                                        Err ->
                                            ?ERR("receive_task_reward err:~p", [Err]),
                                            send_error_code(RoleId, ?FAIL)
                                    end;
                                _ -> %% 背包空间不足
                                    send_error_code(RoleId, ?ERRCODE(err150_no_cell))
                            end;
                        _ -> %% 缺失配置
                            send_error_code(RoleId, ?ERRCODE(missing_config))
                    end;
                #task_status{status = ?HAS_RECEIVE} -> %% 奖励已领取
                    send_error_code(RoleId, ?ERRCODE(err501_has_receive_reward));
                _ -> %% 未完成任务
                    send_error_code(RoleId, ?ERRCODE(err501_progress_not_finish))
            end;
        _ -> send_error_code(RoleId, ?ERRCODE(err501_goal_lock))
    end.

do_send_task_reward(PS, GoalId, TaskId) ->
    #player_status{id = RoleId, limit_goal = LimitGoal} = PS,
    MainStatus = maps:get(GoalId, LimitGoal, #main_status{}),
    #main_status{task_list = TaskList, open_time = OpenTime} = MainStatus,
    TaskStatus = lists:keyfind(TaskId, #task_status.task_id, TaskList),
    NewTaskStatus = TaskStatus#task_status{status = ?HAS_RECEIVE},
    NewTaskList = lists:keystore(TaskId, #task_status.task_id, TaskList, NewTaskStatus),
    GoalIsFin = check_goal_is_finish(GoalId, NewTaskList),
    case GoalIsFin of
        true ->
            F = fun() -> %% 更新阶段奖励状态为已领取
            	db_update_limit_goal_task_status(?HAS_RECEIVE, RoleId, GoalId, TaskId),
            	db_replace_limit_goal_main(RoleId, GoalId, ?FINISH, OpenTime),
                ok
            end,
            case db:transaction(F) of
                ok ->
                    send_active_tv(PS#player_status.figure#figure.name, GoalId),
                    LastMainStatus = MainStatus#main_status{task_list = NewTaskList, status = ?FINISH},
                    NewLimitGoal = maps:put(GoalId, LastMainStatus, LimitGoal),
                    NewPS = PS#player_status{limit_goal = NewLimitGoal},
                    {ok, LastPS} = check_goal_already_active(NewPS, GoalId),
                    {ok, GoalIsFin, LastPS};
                Reason -> Reason
            end;
        false -> %% 更新阶段奖励状态为已领取
        	db_update_limit_goal_task_status(?HAS_RECEIVE, RoleId, GoalId, TaskId),
            LastMainStatus = MainStatus#main_status{task_list = NewTaskList},
            NewLimitGoal = maps:put(GoalId, LastMainStatus, LimitGoal),
            NewPS = PS#player_status{limit_goal = NewLimitGoal},
            {ok, GoalIsFin, NewPS}
    end.

%% 所有星魂点亮，发送传闻
send_active_tv(PlayerName, GoalId) ->
    case data_limit_goal:get_limit_goal_main(GoalId) of
        #limit_goal_main{model_name = ModelName} ->
            ok;
        _ ->
            ModelName = ""
    end,
    lib_chat:send_TV({all}, ?MOD_LIMIT_GOAL, 3, [PlayerName, ModelName]),
    ok.

%% 检测目标是否已经提前激活
check_goal_already_active(PS, GoalId) ->
    case data_limit_goal:get_limit_goal_main(GoalId) of
        #limit_goal_main{activate = Condition} ->
            {ok, NewPS} = check_goal_already_active_helper(PS, GoalId, Condition);
        _ ->
            NewPS = PS
    end,
    {ok, NewPS}.

check_goal_already_active_helper(PS, _GoalId, _Condition) ->
    ?ERR("unknow condition:~p~n", [_Condition]),
    {ok, PS}.

%% 完成激活目标
%% @return {ok, #player_status{}}
active_limit_goal(PS, GoalId) ->
	#player_status{id = RoleId, limit_goal = LimitGoal} = PS,
	MainStatus = maps:get(GoalId, LimitGoal, false),
	case MainStatus of
		#main_status{status = Status, open_time = OpenTime} when Status == ?FINISH ->
			F = fun() ->
				NewMainStatus = MainStatus#main_status{status = ?HAS_RECEIVE},
				CheckLimitGoal = maps:put(GoalId, NewMainStatus, LimitGoal),
				db_replace_limit_goal_main(RoleId, GoalId, ?HAS_RECEIVE, OpenTime),
				case check_goal_is_unlock(GoalId+1, CheckLimitGoal) of
					true ->
						NowTime = utime:unixtime(),
                        case maps:get(GoalId+1, LimitGoal, false) of
                            false ->
        						TempLimitGoal = maps:put(GoalId+1, #main_status{goal_id = GoalId+1, open_time = NowTime}, LimitGoal);
                            TMainStatus ->
                                NMainStatus = TMainStatus#main_status{open_time = NowTime},
                                TempLimitGoal = maps:put(GoalId+1, NMainStatus, LimitGoal)
                        end,
						db_replace_limit_goal_main(RoleId, GoalId+1, ?UNFINISH, NowTime);
					false ->
						TempLimitGoal = LimitGoal
				end,
				NewLimitGoal = maps:put(GoalId, NewMainStatus, TempLimitGoal),
				NewPS = PS#player_status{limit_goal = NewLimitGoal},
				{ok, NewPS}
			end,
			case db:transaction(F) of
				{ok, NewPS} ->
					send_info(RoleId, NewPS#player_status.limit_goal),
					{ok, NewPS};
				Error ->
					?ERR("active_limit_goal db error:~p~n", [Error]),
					{ok, PS}
			end;
		_ ->
			{ok, PS}
	end.

%% 检测目标是否达成
check_goal_is_finish(GoalId, TaskList) when is_integer(GoalId) ->
    TaskIds = data_limit_goal:get_all_task_ids(GoalId),
    F = fun(TaskId) ->
        case lists:keyfind(TaskId, #task_status.task_id, TaskList) of
            #task_status{status = ?HAS_RECEIVE} -> true;
            _ -> false
        end
    end,
    lists:all(F, TaskIds);
check_goal_is_finish(LimitGoal, GoalId) when is_map(LimitGoal) ->
    MainStatus = maps:get(GoalId, LimitGoal, #main_status{}),
    #main_status{status = Status, task_list = TaskList} = MainStatus,
    case Status == ?UNFINISH of
        true ->
            TaskIds = data_limit_goal:get_all_task_ids(GoalId),
            F = fun(TaskId) ->
                case lists:keyfind(TaskId, #task_status.task_id, TaskList) of
                    #task_status{status = ?HAS_RECEIVE} -> true;
                    _ -> false
                end
            end,
            lists:all(F, TaskIds);
        _ -> true
    end;
check_goal_is_finish(_, _) -> false.

%% ================
%% 		触发器
%% ================
trigger(RoleId, RoleLv, VipLv, LimitGoal, Args) ->
    F = fun() ->
        put(broadcast_info, []),
        put(finish_task_list, []),
        GoalIds = data_limit_goal:get_all_goal_ids(),
        NewLimitGoal = do_trigger(GoalIds, RoleId, LimitGoal, Args),
        UpdateGoalIds = erase(broadcast_info),
        FinTaskList = erase(finish_task_list),
        {ok, UpdateGoalIds, FinTaskList, NewLimitGoal}
    end,
    case catch db:transaction(F) of
        {ok, UpdateGoalIds, FinTaskList, NewLimitGoal} ->
            %% 完成任务日志
            F1 = fun({TGoalId, TTaskCfg}) ->
                case TTaskCfg of
                    #limit_goal_task{task_id = TTaskId, finish_condition = TCondition} ->
                        lib_log_api:log_limit_goal_task(RoleId, RoleLv, VipLv, TGoalId, TTaskId, TCondition);
                    _ -> skip
                end
            end,
            lists:foreach(F1, FinTaskList),

            case RoleLv >= ?LIMIT_GOAL_LV of
                true ->
                    F2 = fun(T) -> check_goal_is_unlock(T, LimitGoal) end,
                    RealUGoalIds = lists:filter(F2, UpdateGoalIds),
                    case RealUGoalIds =/= [] of
                        true  -> send_info(RoleId, NewLimitGoal);
                        false -> skip
                    end;
                _ -> skip
            end,
            NewLimitGoal;
        Error ->
            ?ERR("trigger limit goal args:~p err:~p~n", [Args, Error]),
            LimitGoal
    end.

do_trigger([], _RoleId, LimitGoal, _Args) -> LimitGoal;
do_trigger([GoalId|T], RoleId, LimitGoal, Args) ->
	MainStatus = maps:get(GoalId, LimitGoal, #main_status{goal_id = GoalId}),
	#main_status{task_list = TaskList, status = Status} = MainStatus,
	case Status == ?UNFINISH of
		true ->
			TaskIds = data_limit_goal:get_all_task_ids(GoalId),
			{NewTaskList, UpdateSign} = do_trigger_task(TaskIds, GoalId, RoleId, TaskList, Args, 0),
			case UpdateSign == 1 of
				true -> broadcast_info_add(GoalId);
				_ 	 -> skip
			end,
			NewMainStatus = MainStatus#main_status{task_list = NewTaskList},
			NewLimitGoal = maps:put(GoalId, NewMainStatus, LimitGoal);
		false ->
			NewLimitGoal = LimitGoal
	end,
	do_trigger(T, RoleId, NewLimitGoal, Args).

do_trigger_task([], _GoalId, _RoleId, TaskList, _Args, UpdateSign) -> {TaskList, UpdateSign};
do_trigger_task([TaskId|T], GoalId, RoleId, TaskList, Args, UpdateSign) ->
    case lists:keyfind(TaskId, #task_status.task_id, TaskList) of
        false ->
            NeedInsert = true,
            OldTaskStatus = #task_status{goal_id = GoalId, task_id = TaskId};
        OldTaskStatus ->
            NeedInsert = false
    end,
    #task_status{status = Status} = OldTaskStatus,
    %% 已经完成不需要重复触发
    case Status == ?UNFINISH of
        true ->
            case data_limit_goal:get_limit_goal_task(GoalId, TaskId) of
                #limit_goal_task{finish_condition = Condition} = TaskCfg ->
                    {NewTaskStatus, NewUpdateSign} = do_trigger_core(Args, Condition, OldTaskStatus, UpdateSign),
                    #task_status{
                        progress = NewProgress,
                        status = NewStatus,
                        extra = NewExtra,
                        write_time = LastWtime
                    } = NewTaskStatus,
                    case NewProgress =/= OldTaskStatus#task_status.progress orelse NewExtra =/= OldTaskStatus#task_status.extra of
                        true ->
                            case NewStatus of
                                ?FINISH -> finish_task_add(GoalId, TaskCfg);
                                _ 		-> skip
                            end,
                            NowTime = utime:unixtime(),
                            SaveDBCD = case Args of
                                [{attr, _}] -> 1800;
                                _ -> ?SAVE_DB_CD
                            end,
                            case NewStatus == ?FINISH orelse LastWtime == 0 orelse NowTime - LastWtime >= SaveDBCD of
                                true ->
                                    case NeedInsert of
                                        true  -> db_insert_limit_goal_task(RoleId, GoalId, TaskId, NewProgress, NewStatus, NewExtra);
                                        false -> db_update_limit_goal_task(NewProgress, NewStatus, NewExtra, RoleId, GoalId, TaskId)
                                    end,
                                    LastTaskStatus = NewTaskStatus#task_status{write_time = NowTime, write_status = ?WSTATUS_SUCCESS};
                                _ ->
                                    LastTaskStatus = NewTaskStatus#task_status{write_status = ?WSTATUS_WAIT}
                            end,
                            NewTaskList = lists:keystore(TaskId, #task_status.task_id, TaskList, LastTaskStatus);
                        false ->
                            NewTaskList = TaskList
                    end;
                _ ->
                    NewUpdateSign = UpdateSign,
                    NewTaskList = TaskList
            end;
        _ ->
            NewUpdateSign = UpdateSign,
            NewTaskList = TaskList
    end,
    do_trigger_task(T, GoalId, RoleId, NewTaskList, Args, NewUpdateSign).

do_trigger_core([], _, TaskStatus, UpdateSign) -> {TaskStatus, UpdateSign};
%% 通关副本次数
do_trigger_core([{dungeon_times, DungeonType}|T], [{dungeon_times, NeedDungeonType, NeedTimes}] = Condition, TaskStatus, UpdateSign) when DungeonType == NeedDungeonType ->
    Times = TaskStatus#task_status.progress + 1,
    case Times >= NeedTimes of
        true -> %% 完成
            NewStatus = ?FINISH,
            NewUpdateSign = 1,
            NewProgress = NeedTimes;
        false -> %% 未完成
            NewStatus = ?UNFINISH,
            NewUpdateSign = UpdateSign,
            NewProgress = Times
    end,
    NewTaskStatus = TaskStatus#task_status{progress = NewProgress, status = NewStatus},
    do_trigger_core(T, Condition, NewTaskStatus, NewUpdateSign);
%% 通关副本层数
do_trigger_core([{dungeon_level, DungeonType, NewLevel}|T], [{dungeon_level, NeedDungeonType, NeedLevel}] = Condition, TaskStatus, UpdateSign) when DungeonType == NeedDungeonType ->
    case NewLevel >= NeedLevel of
        true -> %% 完成
            NewStatus = ?FINISH,
            NewUpdateSign = 1,
            NewProgress = NeedLevel;
        false -> %% 未完成
            NewStatus = ?UNFINISH,
            NewUpdateSign = UpdateSign,
            NewProgress = NewLevel
    end,
    NewTaskStatus = TaskStatus#task_status{progress = NewProgress, status = NewStatus},
    do_trigger_core(T, Condition, NewTaskStatus, NewUpdateSign);
%% 转职次数
do_trigger_core([{turn, Level}|T], [{turn, NeedLevel}] = Condition, TaskStatus, UpdateSign) ->
    case Level >= NeedLevel of
        true ->
            NewStatus = ?FINISH,
            NewUpdateSign = 1,
            NewProgress = NeedLevel;
        false ->
            NewStatus = ?UNFINISH,
            NewUpdateSign = UpdateSign,
            NewProgress = Level
    end,
    NewTaskStatus = TaskStatus#task_status{progress = NewProgress, status = NewStatus},
    do_trigger_core(T, Condition, NewTaskStatus, NewUpdateSign);
%% 累计登录天数
do_trigger_core([{login_days}|T], [{login_days, NeedDays}] = Condition, TaskStatus, UpdateSign) ->
    #task_status{progress = Days, extra = Extra} = TaskStatus,
    NowTime = utime:unixtime(),
    case Extra of
        [RefreshTime] when is_integer(RefreshTime) -> %% 检测是否是同一天触发
            case utime:is_same_day(NowTime, RefreshTime) orelse NowTime =< RefreshTime of
                true -> %% 同一天触发或者服务器时间被改动
                    NewTaskStatus = TaskStatus,
                    NewUpdateSign = UpdateSign;
                false ->
                    NewDays = Days + 1,
                    case NewDays >= NeedDays of
                        true -> %% 完成
                            NewStatus = ?FINISH,
                            NewUpdateSign = 1,
                            NewProgress = NeedDays;
                        false -> %% 未完成
                            NewStatus = ?UNFINISH,
                            NewUpdateSign = UpdateSign,
                            NewProgress = NewDays
                    end,
                    NewTaskStatus = TaskStatus#task_status{progress = NewProgress, status = NewStatus, extra = [NowTime]}
            end;
        _ -> %% 首次触发
            NewDays = 1,
            case NewDays >= NeedDays of
                true -> %% 完成
                    NewStatus = ?FINISH,
                    NewUpdateSign = 1,
                    NewProgress = NeedDays;
                false -> %% 未完成
                    NewStatus = ?UNFINISH,
                    NewUpdateSign = UpdateSign,
                    NewProgress = NewDays
            end,
            NewTaskStatus = TaskStatus#task_status{progress = NewProgress, status = NewStatus, extra = [NowTime]}
    end,
    do_trigger_core(T, Condition, NewTaskStatus, NewUpdateSign);

%% 本服boss击杀归属次数
do_trigger_core([{local_boss, BossType, BossLv}|T], [{local_boss, NeedBossType, NeedBossLv, NeedKillTimes}] = Condition, TaskStatus, UpdateSign) ->
    #task_status{progress = KillTimes} = TaskStatus,
    NeedBossTypes = case is_list(NeedBossType) of
        true  -> NeedBossType;
        false -> [NeedBossType]
    end,
    case lists:member(BossType, NeedBossTypes) andalso BossLv >= NeedBossLv of
        true ->
            case KillTimes+1 >= NeedKillTimes of
                true -> %% 完成
                    NewStatus = ?FINISH,
                    NewUpdateSign = 1,
                    NewProgress = NeedKillTimes;
                false -> %% 未完成
                    NewStatus = ?UNFINISH,
                    NewUpdateSign = UpdateSign,
                    NewProgress = KillTimes + 1
            end,
            NewTaskStatus = TaskStatus#task_status{status = NewStatus, progress = NewProgress};
        false ->
            NewTaskStatus = TaskStatus,
            NewUpdateSign = UpdateSign
    end,
    do_trigger_core(T, Condition, NewTaskStatus, NewUpdateSign);
do_trigger_core([_|T], Condition, TaskStatus, UpdateSign) ->
    do_trigger_core(T, Condition, TaskStatus, UpdateSign).

%% 检测限时目标是否已解锁
check_goal_is_unlock(GoalId, LimitGoal) ->
	case data_limit_goal:get_limit_goal_main(GoalId) of
		#limit_goal_main{precondition = Precondition} ->
			F = fun(Id) ->
				case maps:get(Id, LimitGoal, false) of
					#main_status{status = ?HAS_RECEIVE} ->
						true;
					_ ->
						false
				end
			end,
			lists:all(F, Precondition);
		_ ->
			false
	end.

broadcast_info_add(GoalId) ->
    case get(broadcast_info) of
        List when is_list(List) ->
            case lists:member(GoalId, List) of
                false -> put(broadcast_info, [GoalId|List]);
                _ 	  -> skip
            end;
        _ -> skip
    end.

finish_task_add(GoalId, TaskCfg) ->
    case get(finish_task_list) of
        List when is_list(List) ->
            put(finish_task_list, [{GoalId, TaskCfg}|List]);
        _ ->
        	skip
    end.

%% 统计星魂属性
count_limit_goal_attr(PS) ->
    #player_status{limit_goal = LimitGoal} = PS,
    CountFinNum = fun(TaskStatus, Acc) ->
        case TaskStatus of
            #task_status{status = ?HAS_RECEIVE} ->
                Acc + 1;
            _ ->
                Acc
        end
    end,
    F2 = fun(MainStatus, AccList) ->
        #main_status{goal_id = GoalId, task_list = TaskList} = MainStatus,
        FinishNum = lists:foldl(CountFinNum, 0, TaskList),
        lists:keystore(GoalId, 1, AccList, {GoalId, FinishNum})
    end,
    FinishList = lists:foldl(F2, [], maps:values(LimitGoal)),
    LimitGoalSoul = count_limit_goal_attr_helper(FinishList, #limit_goal_soul_status{}),
    LastLimitGoalSoul = count_sum_soul_attr(LimitGoalSoul),
    NewPS = PS#player_status{limit_goal_soul = LastLimitGoalSoul},
    NewPS.

count_limit_goal_attr_helper([], LimitGoalSoul) -> LimitGoalSoul;
count_limit_goal_attr_helper([{GoalId, FinishNum}|T], LimitGoalSoul) ->
    #limit_goal_soul_status{soul_list = SoulList} = LimitGoalSoul,
    SoulIds = data_limit_goal:get_all_goal_soul_id(GoalId),
    F = fun(SoulId, AttrList) ->
        case data_limit_goal:get_limit_goal_soul(GoalId, SoulId) of
            #limit_goal_soul{need_finish = NeedFinish, attr = Attr} when FinishNum >= NeedFinish ->
                lists:keystore(SoulId, #limit_goal_soul_attr.soul_id, AttrList, #limit_goal_soul_attr{soul_id = SoulId, attr = Attr});
            _ ->
                AttrList
        end
    end,
    SoulAttrList = lists:foldl(F, [], SoulIds),
    NewSoulList = lists:keystore(GoalId, #limit_goal_soul_list.goal_id, SoulList, #limit_goal_soul_list{goal_id = GoalId, soul_attr = SoulAttrList}),
    NewLimitGoalSoul = LimitGoalSoul#limit_goal_soul_status{soul_list = NewSoulList},
    count_limit_goal_attr_helper(T, NewLimitGoalSoul);
count_limit_goal_attr_helper([_H|T], LimitGoalSoul) ->
    ?ERR("bad args _H:~p~n", [_H]),
    count_limit_goal_attr_helper(T, LimitGoalSoul).

%% 统计星魂总属性（需要先初始化各个星魂属性）
count_sum_soul_attr(LimitGoalSoul) ->
    #limit_goal_soul_status{soul_list = SoulList} = LimitGoalSoul,
    F1 = fun(#limit_goal_soul_attr{attr = Attr}, AccList) ->
        [Attr|AccList]
    end,
    F2 = fun(#limit_goal_soul_list{soul_attr = SoulAttrList}, AccList) ->
        lists:foldl(F1, [], SoulAttrList) ++ AccList
    end,
    SumAttr = lists:foldl(F2, [], SoulList),
    LastSumAttr = ?IF(SumAttr =:= [], [], lib_player_attr:add_attr(list, SumAttr)),
    NewLimitGoalSoul = LimitGoalSoul#limit_goal_soul_status{sum_attr = LastSumAttr},
    NewLimitGoalSoul.

%% ================
%% 	SQL 数据库操作
%% ================
db_get_all_limit_goal_main(RoleId) ->
	ReSql = io_lib:format(?SELECT_LIMIT_GOAL_MAIN, [RoleId]),
	db:get_all(ReSql).

db_get_all_limit_goal_task(RoleId) ->
	ReSql = io_lib:format(?SELECT_LIMIT_GOAL_TASK, [RoleId]),
	db:get_all(ReSql).

db_insert_limit_goal_task(RoleId, GoalId, TaskId, Progress, Status, Extra) ->
	SExtra = util:term_to_bitstring(Extra),
	ReSql = io_lib:format(?INSERT_LIMIT_GOAL_TASK, [RoleId, GoalId, TaskId, Progress, Status, SExtra]),
	db:execute(ReSql).

db_replace_limit_goal_main(RoleId, GoalId, Status, OpenTime) ->
	ReSql = io_lib:format(?REPLACE_LIMIT_GOAL_MAIN, [RoleId, GoalId, Status, OpenTime]),
	db:execute(ReSql).

db_update_limit_goal_task(Progress, Status, Extra, RoleId, GoalId, TaskId) ->
	SExtra = util:term_to_bitstring(Extra),
	ReSql = io_lib:format(?UPDATE_LIMIT_GOAL_TASK, [Progress, Status, SExtra, RoleId, GoalId, TaskId]),
	db:execute(ReSql).

db_update_limit_goal_task_status(Status, RoleId, GoalId, TaskId) ->
	ReSql = io_lib:format(?UPDATE_LIMIT_GOAL_TASK_STATUS, [Status, RoleId, GoalId, TaskId]),
	db:execute(ReSql).

%% 发送错误码
send_error_code(RoleId, ErrCode) ->
	{ok, Bin} = pt_501:write(50100, [ErrCode]),
	lib_server_send:send_to_uid(RoleId, Bin).
