%%%-------------------------------------------------------------------
%%% @author ljy
%%% @doc
%%%       幻魔宝典
%%% @end
%%% Created : 21. 9月 2020 17:30
%%%-------------------------------------------------------------------
-module(custom_act_phantom).

-include("custom_act.hrl").
-include("server.hrl").
-include("def_fun.hrl").
-include("errcode.hrl").
-include("phantom.hrl").
-include("predefine.hrl").
-include("common.hrl").
-include("figure.hrl").
-include("def_goods.hrl").
-include("pass_codex.hrl").
-include("def_module.hrl").
-include("goods.hrl").

%% API
-export([
    phantom_info/2
    , phantom_lv_reward/4
    , check/1
    , trigger_phantom_task/2
    , do_trigger_phantom_task/2
    , buy_ace_phantom/2
    , phantom_reward_info/2
    , phantom_task_info/2
    , add_score_by_goods/3
    , use_goods/3
    , reload_config/0
    , gm_add_score/3
    , gm_reset/1
]).

%% 获取幻魔宝典信息
phantom_info(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        #act_info{} ->
            {_CustomData, ActData} = get_act_data(RoleId, SubType),
            {ok, BinData} = pack_phantom_info(SubType, ActData),
            lib_server_send:send_to_sid(Sid, BinData),
            ok;
        _ ->
            {ok, BinData} = pt_332:write(33238, [?ERRCODE(err331_act_closed), SubType, 0, 0, 0, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 打包幻魔宝典信息
pack_phantom_info(SubType, ActData) ->
    #role_phantom{
        score = Score,
        lv = Lv,
        pay_phantom = IsPay,
        normal_reward = NormalReward,
        pay_reward = PayReward
    } = ActData,
    Lvs = data_pass_codex:get_act_lv(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
    F = fun(LvX, Acc) ->
        if
            LvX =< Lv ->
                NormalStatus =
                    case lists:member(LvX, NormalReward) of
                        true -> ?PHANTOM_REWARD_2;
                        _ -> ?PHANTOM_REWARD_1
                    end,
                PayStatus =
                    case lists:member(LvX, PayReward) of
                        true -> ?PHANTOM_REWARD_2;
                        _ ->
                            if IsPay == 1 -> ?PHANTOM_REWARD_1;
                                true -> ?PHANTOM_REWARD_0
                            end
                    end,
                [{LvX, NormalStatus, PayStatus} | Acc];
            true ->
                [{LvX, ?PHANTOM_REWARD_0, ?PHANTOM_REWARD_0} | Acc]
        end
        end,
    RewardInfo = lists:foldl(F, [], Lvs),
    pt_332:write(33238, [?SUCCESS, SubType, Score, Lv, IsPay, RewardInfo]).

%% 幻魔宝典 奖励信息
phantom_reward_info(Player, SubType) ->
    #player_status{sid = Sid} = Player,
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        #act_info{key = {_, SubType}} ->
            {ok, BinData} = pack_reward_info(SubType),
            lib_server_send:send_to_sid(Sid, BinData);
        _ ->
            {ok, BinData} = pt_332:write(33241, [?ERRCODE(err331_act_closed), SubType, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 打包幻魔宝典奖励信息
pack_reward_info(SubType) ->
    Lvs = data_pass_codex:get_act_lv(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
    F = fun(Lv, {Acc, Success}) ->
        case data_pass_codex:get_reward_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType, Lv) of
            #base_pass_rewards{normal_rewards = NormalReward, trump_rewards = TrumpRewards, node_reward = NodeReward} ->
                {[{Lv, util:term_to_string(NormalReward), util:term_to_string(TrumpRewards), NodeReward} | Acc], Success};
            _ -> {Acc, 0}
        end
        end,
    {RewardInfo, IsSuccess} = lists:foldl(F, {[], 1}, Lvs),
    if
        IsSuccess == 1 andalso RewardInfo =/= [] ->
            pt_332:write(33241, [?SUCCESS, SubType, RewardInfo]);
        true ->
            pt_332:write(33241, [?MISSING_CONFIG, SubType, []])
    end.

%% 任务完成情况
phantom_task_info(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = Figure} = Player,
    #figure{lv = RoleLv} = Figure,
    OpenDay = util:get_open_day(),
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        #act_info{key = {_, SubType}} ->
            {_CustomData, ActData} = get_act_data(RoleId, SubType),
            #role_phantom{phantom_task = PhantomTask} = ActData,
            AllTaskId = data_pass_codex:get_phantom_task_ids(),
            F = fun(TaskId, Acc) ->
                IsOpen = check_task_open(RoleLv, OpenDay, TaskId),
                case lists:keyfind(TaskId, #phantom_task.task_id, PhantomTask) of
                    #phantom_task{task_id = TaskId, count = Count} when IsOpen ->
                        [{TaskId, Count} | Acc];
                    _ when IsOpen -> [{TaskId, 0} | Acc];
                    _ -> Acc
                end
                end,
            TaskInfos = lists:foldl(F, [], AllTaskId),
            {ok, BinData} = pt_332:write(33242, [?SUCCESS, SubType, TaskInfos]),
            lib_server_send:send_to_sid(Sid, BinData);
        _ ->
            {ok, BinData} = pt_332:write(33242, [?ERRCODE(err331_act_closed), SubType, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 检查任务是否开放
check_task_open(RoleLv, OpenDay, TaskId) ->
    case data_pass_codex:get_phantom_task_info(TaskId) of
        #base_phantom_task_type{open_lv = CfgLv, open_day = CfgDay} ->
            if
                RoleLv >= CfgLv andalso OpenDay >= CfgDay -> true;
                true -> false
            end;
        _ -> false
    end.

%% 领取等级奖励
phantom_lv_reward(Player, SubType, Type, Lv) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{name = Name}} = Player,
    CheckL = [
        {act_is_open, SubType},
        {lv_reward_check, Type, Lv, SubType}
    ],
    case util:check_lists(?MODULE, CheckL) of
        true ->
            {IsNodeReward, NewLv, RewardLvList, Rewards} = calc_phantom_lv_reward(RoleId, Type, Lv, SubType),
            NewPlayer = lib_goods_api:send_reward(Player, Rewards, phantom_lv_reward),
            if
                RewardLvList == [] ->
                    {ok, BinData} = pt_332:write(33239, [?ERRCODE(err331_phantom_not_reward), SubType, RewardLvList]);
                true ->
                    lib_log_api:custom_act_reward_log(NewPlayer, Player, ?CUSTOM_ACT_TYPE_PHANTOM, SubType, 0, util:term_to_bitstring(RewardLvList), Rewards),
                    {ok, BinData} = pt_332:write(33239, [?SUCCESS, SubType, RewardLvList])
            end,
            if
                IsNodeReward == 1 -> %% 领取节点奖励发传闻
                    #custom_act_cfg{name = ActName} = lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
                    lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 16, [Name, ActName, NewLv, SubType]);
                true ->
                    skip
            end,
            lib_server_send:send_to_sid(Sid, BinData),
            {ok, NewPlayer};
        {false, Errcode} ->
            {ok, BinData} = pt_332:write(33239, [Errcode, SubType, []]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 购买王牌宝典
buy_ace_phantom(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid} = Player,
    case get_role_phantom(RoleId, SubType, true) of
        {true, #act_info{key = {_, SubType}}, ActData} ->
            CheckL = [
                {buy_cost_check, Player, ?CUSTOM_ACT_TYPE_PHANTOM, SubType},
                {payed_check, ActData}
            ],
            case util:check_lists(?MODULE, CheckL) of
                true ->
                    buy_ace_phantom_do(Player, SubType);
                {false, Errcode} ->
                    {ok, BinData} = pt_332:write(33240, [Errcode, SubType, 0]),
                    lib_server_send:send_to_sid(Sid, BinData)
            end;
        {false, Errcode} ->
            {ok, BinData} = pt_332:write(33240, [Errcode, SubType, 0]),
            lib_server_send:send_to_sid(Sid, BinData)
    end.

%% 获取玩家活动数据
get_role_phantom(RoleId, SubType, true) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        ActInfo = #act_info{key = {_, SubType}} ->
            {_CustomData, ActData} = get_act_data(RoleId, SubType),
            {true, ActInfo, ActData};
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end.

buy_ace_phantom_do(Player, SubType) ->
    #player_status{id = RoleId, sid = Sid, figure = #figure{name = Name}} = Player,
    #custom_act_cfg{name = ActName, condition = Condition} = lib_custom_act_util:get_act_cfg_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
    {limit_cost, Price} = lists:keyfind(limit_cost, 1, Condition),
    Cost = [{?TYPE_GOLD, 0, Price}],
    case lib_goods_api:cost_object_list_with_check(Player, Cost, ace_phantom_cost, "") of
        {true, NewPlayer, _} ->
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            NewActData = ActData#role_phantom{pay_phantom = 1},
            NewCustomData = CustomData#custom_act_data{act_data = NewActData},
            lib_custom_act_data:save_custom_data(RoleId, NewCustomData),
            {ok, BinData} = pt_332:write(33240, [?SUCCESS, SubType, 1]),
            {ok, BinData2} = pack_phantom_info(SubType, NewActData),
            lib_server_send:send_to_sid(Sid, <<BinData/binary, BinData2/binary>>),
            lib_chat:send_TV({all}, ?MOD_AC_CUSTOM, 15, [Name, ActName, SubType]),
            lib_log_api:custom_act_reward_log(NewPlayer, Player, ?CUSTOM_ACT_TYPE_PHANTOM, SubType, 0, util:term_to_bitstring([buy,[]]), []),
            {ok, NewPlayer};
        {false, Errcode, _} ->
            {ok, BinData} = pt_332:write(33240, [Errcode, SubType, 0]),
            lib_server_send:send_to_sid(Sid, BinData),
            ok
    end.

%% 计算等级奖励
calc_phantom_lv_reward(RoleId, Type, Lv, SubType) ->
    #custom_act_data{act_data = ActData} = CustomActData = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
    #role_phantom{
        normal_reward = NormalReward,
        pay_reward = PayReward,
        pay_phantom = IsPay,
        lv = NowLv
    } = ActData,
    {NewLvChangeL, NewLvRewards, NewLv, IsNode} =
        if
            Type == 1 ->
                #base_pass_rewards{normal_rewards = Rewards1, trump_rewards = Rewards2, node_reward = NodeReward} = data_pass_codex:get_reward_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType, Lv),
                if IsPay =/= 0 ->
                    NormalCanReward = calc_per_lv_reward(Lv, NormalReward),
                    PayCanReward = calc_per_lv_reward(Lv, PayReward),
                    NewRewards = update_lv_reward(NormalCanReward, Rewards1, []),
                    NewRewards1 = update_lv_reward(PayCanReward, Rewards2, NewRewards),
                    LvChangeL = update_lv_change_list(Lv, NormalCanReward, PayCanReward, []),
                    {LvChangeL, NewRewards1, Lv, NodeReward};
                    true ->
                        NormalCanReward = calc_per_lv_reward(Lv, NormalReward),
                        NewRewards = update_lv_reward(NormalCanReward, Rewards1, []),
                        LvChangeL = update_lv_change_list(Lv, NormalCanReward, false, []),
                        {LvChangeL, NewRewards, Lv, NodeReward}
                end;
            true ->
                LvList = lists:seq(1, NowLv),
                lists:foldl(fun(LvX, {TempLvChangeL, TempRewards, OldLv, IsNodeReward}) ->
                    #base_pass_rewards{normal_rewards = Rewards1, trump_rewards = Rewards2, node_reward = NodeReward} = data_pass_codex:get_reward_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType, LvX),
                    if IsPay =/= 0 ->
                        NormalCanReward = calc_per_lv_reward(LvX, NormalReward),
                        PayCanReward = calc_per_lv_reward(LvX, PayReward),
                        NewTempRewards = update_lv_reward(NormalCanReward, Rewards1, TempRewards),
                        NewTempRewards1 = update_lv_reward(PayCanReward, Rewards2, NewTempRewards),
                        NewTempLvChangeL = update_lv_change_list(LvX, NormalCanReward, PayCanReward, TempLvChangeL),
                        if
                            NodeReward == 1 andalso (NormalCanReward orelse PayCanReward) ->
                                {NewTempLvChangeL, NewTempRewards1, LvX, 1};
                            true -> {NewTempLvChangeL, NewTempRewards1, OldLv, IsNodeReward}
                        end;
                        true ->
                            NormalCanReward = calc_per_lv_reward(LvX, NormalReward),
                            NewTempRewards = update_lv_reward(NormalCanReward, Rewards1, TempRewards),
                            NewTempLvChangeL = update_lv_change_list(LvX, NormalCanReward, false, TempLvChangeL),
                            if
                                NodeReward == 1 andalso NormalCanReward -> {NewTempLvChangeL, NewTempRewards, LvX, 1};
                                true -> {NewTempLvChangeL, NewTempRewards, OldLv, IsNodeReward}
                            end
                    end
                            end, {[], [], 0, 0}, LvList)
        end,
    NewActData = update_phantom_lv_reward_state(NewLvChangeL, ActData),
    ?IF(NewActData =/= ActData, lib_custom_act_data:save_custom_data(RoleId, CustomActData#custom_act_data{act_data = NewActData}), skip),
    {IsNode, NewLv, NewLvChangeL, NewLvRewards}.

calc_per_lv_reward(Lv, LvRewarded) ->
    case lists:member(Lv, LvRewarded) of
        false -> true;
        _ -> false
    end.

update_lv_reward(CanReward, AddRewards, Rewards) ->
    if CanReward ->
        AddRewards ++ Rewards;
        true ->
            Rewards
    end.

update_lv_change_list(LvX, NormalCanReward, PayCanReward, LvChangL) ->
    if NormalCanReward andalso PayCanReward ->
        [{LvX, 3} | LvChangL];
        NormalCanReward ->
            [{LvX, 1} | LvChangL];
        PayCanReward ->
            [{LvX, 2} | LvChangL];
        true ->
            LvChangL
    end.

%% 更新奖励领取状态
update_phantom_lv_reward_state(LvChangeL, ActData) ->
    #role_phantom{normal_reward = NormalReward, pay_reward = PayReward} = ActData,
    {NewNormalReward, NewPayReward} =
        lists:foldl(fun({Lv, ChangeType}, {TempNormalReward, TempPayReward}) ->
            if ChangeType == 1 -> %% 普通
                {[Lv | TempNormalReward], TempPayReward};
                ChangeType == 2 -> %% 王牌
                    {TempNormalReward, [Lv | TempPayReward]};
                true -> %% 都有
                    {[Lv | TempNormalReward], [Lv | TempPayReward]}
            end
                    end, {NormalReward, PayReward}, LvChangeL),
    ActData#role_phantom{normal_reward = NewNormalReward, pay_reward = NewPayReward}.

add_score_by_goods(RoleId, GoodsId, Val) ->
    Type = ?CUSTOM_ACT_TYPE_PHANTOM,
    case lib_custom_act_util:get_open_subtype_list(Type) of
        ActInfos = [_ | _] ->
            case lists:filter(fun(#act_info{key = {_, SubTypeX}}) ->
                case lib_custom_act_util:get_act_cfg_info(Type, SubTypeX) of
                    #custom_act_cfg{condition = Cons} ->
                        case lists:keyfind(goods_id, 1, Cons) of
                            {_, GoodsId} -> true;
                            _ -> false
                        end;
                    _ -> false
                end
                              end, ActInfos) of
                [#act_info{key = {_, SubType}} | _] ->
                    {CustomData, ActData} = get_act_data(RoleId, SubType),
                    add_phantom_exp(RoleId, Type, SubType, Val, ActData, CustomData);
                _ ->
                    skip
            end;
        _ ->
            skip
    end.

%% 使用道具增加积分
use_goods(Player, GoodsInfo, GoodsNum) ->
    Type = ?CUSTOM_ACT_TYPE_PHANTOM,
    #goods{goods_id = GoodsId, player_id = RoleId} = GoodsInfo,
    case lib_custom_act_util:get_open_subtype_list(Type) of
        ActInfos = [_ | _] ->
            F = fun(#act_info{key = {_, SubTypeX}}) ->
                case lib_custom_act_util:get_act_cfg_info(Type, SubTypeX) of
                    #custom_act_cfg{condition = Cons} ->
                        case lists:keyfind(goods_id, 1, Cons) of
                            {_, GoodsId} -> true;
                            _ -> false
                        end;
                    _ -> false
                end
                end,
            case lists:filter(F, ActInfos) of
                [#act_info{key = {_, SubType}} | _] ->
                    lib_goods_api:cost_object_list(Player, [{0, GoodsInfo#goods.goods_id, GoodsNum}], goods_use, ""),
                    {CustomData, ActData} = get_act_data(RoleId, SubType),
                    add_phantom_exp(RoleId, Type, SubType, GoodsNum, ActData, CustomData),
                    {ok, BinData} = pack_phantom_info(SubType, ActData),
                    lib_server_send:send_to_uid(RoleId, BinData),
                    {ok, Player, GoodsNum};
                _ ->
                    {fail, ?FAIL}
            end;
        _ ->
            {fail, ?ERRCODE(err331_act_closed)}
    end.

%% 热更奖励配置后通知客户端刷新奖励数据
reload_config() ->
    case config:get_cls_type() of
        ?NODE_GAME ->
            Pids = lib_player:get_online_pids(),
            ActType = ?CUSTOM_ACT_TYPE_PHANTOM,
            SubTypeList = lib_custom_act_util:get_subtype_list(ActType),
            F = fun(SubType, Acc) ->
                case lib_custom_act_util:get_custom_act_open_info(ActType, SubType) of
                    #act_info{key = {_, SubType}} ->
                        [SubType | Acc];
                    _ -> Acc

                end
                end,
            EffectiveList = lists:foldl(F, [], SubTypeList), %%获取正在开启的活动子类型
            case EffectiveList of
                [EffectiveType | _] ->
                    {ok, BinData} = pack_reward_info(EffectiveType),
                    [lib_server_send:send_to_sid(Pid, BinData) || Pid <- Pids];
                _ -> skip
            end;
        _          -> skip
    end.



check({act_is_open, SubType}) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        #act_info{} ->
            true;
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end;
check({lv_reward_check, Type, Lv, SubType}) ->
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        ActInfo = #act_info{} ->
            CustomData = lib_custom_act_data:custom_act_data(ActInfo),
            case CustomData of
                #custom_act_data{act_data = #role_phantom{
                    lv = NowLv, normal_reward = NormalReward,
                    pay_reward = PayReward, pay_phantom = IsPay}
                } ->
                    if
                        Type == 1 ->
                            if NowLv >= Lv andalso Lv =/= 0 ->
                                IsNormalRewarded = lists:member(Lv, NormalReward),
                                IsPayReward = lists:member(Lv, PayReward),
                                if (not IsNormalRewarded) orelse (IsPay =/= 0 andalso (not IsPayReward)) ->
                                    true;
                                    true ->
                                        {false, ?ERRCODE(err331_contract_lv_rewarded)}
                                end;
                                true ->
                                    {false, ?ERRCODE(err331_contract_lv_limit)}
                            end;
                        Type == 2 ->
                            if NowLv == 0 ->
                                {false, ?ERRCODE(err331_contract_lv_limit)};
                                true ->
                                    LvList = lists:seq(1, NowLv),
                                    case lists:any(fun(LvX) ->
                                        not lists:member(LvX, NormalReward) orelse
                                            not lists:member(LvX, PayReward)
                                                   end, LvList) of
                                        true ->
                                            true;
                                        _ ->
                                            {false, ?ERRCODE(err331_contract_lv_rewarded)}
                                    end
                            end;
                        true ->
                            {false, ?ERRCODE(data_error)}
                    end;
                _ ->
                    {false, ?ERRCODE(err331_contract_task_not_fin)}
            end;
        _ ->
            {false, ?ERRCODE(err331_act_closed)}
    end;
check({buy_cost_check, Player, ActType, SubType}) ->
    case lib_custom_act_util:get_act_cfg_info(ActType, SubType) of
        #custom_act_cfg{condition = Condition} ->
            case lists:keyfind(limit_cost, 1, Condition) of
                {limit_cost, Price} -> skip;
                _ -> Price = -1
            end,
            if
                Price >= 0 ->
                    lib_goods_api:check_object_list(Player, [{?TYPE_GOLD, 0, Price}]);
                true ->
                    {false, ?ERRCODE(config_err)}
            end;
        _ ->
            {false, ?ERRCODE(config_err)}
    end;
check({payed_check, ActData}) ->
    #role_phantom{pay_phantom = IsPay} = ActData,
    if IsPay =/= 0 ->
        {false, ?ERRCODE(err331_contract_haved_buy)};
        true ->
            true
    end;
check(_A) ->
    {false, ?FAIL}.

%% 完成任务触发
trigger_phantom_task(RoleId, TaskType) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, ?MODULE, do_trigger_phantom_task, [TaskType]).

do_trigger_phantom_task(Player, TaskType) ->
    #player_status{id = RoleId, figure = Figure} = Player,
    #figure{lv = RoleLv} = Figure,
    {OpenResult, ActInfos} = check_phantom_open(),
    TaskIds = data_pass_codex:get_phantom_task_id(TaskType),
    case check_task(OpenResult, TaskIds, RoleLv) of
        {true, TaskId, LimitTimes} ->
            [ActInfo | _] = ActInfos,
            #act_info{key = {_, SubType}} = ActInfo,
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            #role_phantom{phantom_task = PhantomTask} = ActData,
            case lists:keyfind(TaskId, #phantom_task.task_id, PhantomTask) of
                TaskInfo = #phantom_task{count = Count} when LimitTimes > Count ->
                    NewPhantomTask = lists:keystore(TaskId, #phantom_task.task_id, PhantomTask, TaskInfo#phantom_task{count = Count + 1}),
                    NewActData = ActData#role_phantom{phantom_task = NewPhantomTask},
                    Score = data_pass_codex:get_phantom_task_score(TaskType),
                    add_phantom_exp(RoleId, ?CUSTOM_ACT_TYPE_PHANTOM, SubType, Score, NewActData, CustomData);
                #phantom_task{} -> %%达到每日最大触发次数
                    skip;
                _ ->  %% 增加了触发类型时，增加新的触发类型数据
                    TaskInfo = #phantom_task{task_id = TaskId, count = 1},
                    NewPhantomTask = lists:keystore(TaskId, #phantom_task.task_id, PhantomTask, TaskInfo),
                    NewActData = ActData#role_phantom{phantom_task = NewPhantomTask},
                    Score = data_pass_codex:get_phantom_task_score(TaskType),
                    add_phantom_exp(RoleId, ?CUSTOM_ACT_TYPE_PHANTOM, SubType, Score, NewActData, CustomData)
            end;
        _ -> skip
    end,
    {ok, Player}.

%% 检查是否开放
check_phantom_open() ->
    BaseType = ?CUSTOM_ACT_TYPE_PHANTOM,
    case lib_custom_act_util:get_open_subtype_list(BaseType) of
        ActInfos = [#act_info{} | _] ->
            {true, ActInfos};
        _ ->
            {false, []}
    end.

check_task(OpenResult, TaskIds, RoleLv) ->
    if
        not OpenResult ->
            false;
        TaskIds == [] ->
            false;
        true ->
            [TaskId | _] = TaskIds,
            ConfigTaskType = data_pass_codex:get_phantom_task_info(TaskId),
            OpenDay = util:get_open_day(),
            if
                not is_record(ConfigTaskType, base_phantom_task_type) ->
                    false;
                ConfigTaskType#base_phantom_task_type.open_lv > RoleLv orelse
                    ConfigTaskType#base_phantom_task_type.open_day > OpenDay ->
                    false; %% 等级不足或开服天数不足
                true ->
                    {true, TaskId, ConfigTaskType#base_phantom_task_type.limit_times}
            end
    end.

%% 增加积分
add_phantom_exp(RoleId, Type, SubType, AddScore, ActData, CustomData) ->
    #role_phantom{score = Score, lv = Lv} = ActData,
    NeedExp = data_pass_codex:get_lv_exp(Type, SubType, Lv + 1),
    if
        is_integer(AddScore) andalso AddScore > 0 ->
            NewScore = Score + AddScore,
            if
                NeedExp == [] ->
                    NewActData = ActData#role_phantom{score = NewScore};
                NeedExp > NewScore ->
                    NewActData = ActData#role_phantom{score = NewScore};
                true ->
                    {NewScore2, NewLv} = add_phantom_lv(Type, SubType, NewScore, NeedExp, Lv + 1),
                    NewActData = ActData#role_phantom{score = NewScore2, lv = NewLv},
                    {ok, BinData} = pack_phantom_info(SubType, NewActData),
                    lib_server_send:send_to_uid(RoleId, BinData)
            end,
            NewCustomData = CustomData#custom_act_data{act_data = NewActData},
            lib_custom_act_data:save_custom_data(RoleId, NewCustomData);
        true ->
            ?ERR("config error AddScore:~p NeedExp ~p", [AddScore, NeedExp])
    end.

%% 增加等级
add_phantom_lv(Type, SubType, Score, NeedExp, Lv) ->
    NowScore = Score - NeedExp,
    NewLv = Lv + 1,
    NextNeedExp = data_pass_codex:get_lv_exp(Type, SubType, NewLv),
    if
        NextNeedExp == [] ->
            {NowScore, Lv};
        is_integer(NextNeedExp) andalso NextNeedExp > 0 andalso NowScore >= NextNeedExp ->
            add_phantom_lv(Type, SubType, NowScore, NextNeedExp, NewLv);
        true ->
            {NowScore, Lv}
    end.

%% 获取活动数据
get_act_data(RoleId, SubType) ->
    #custom_act_data{
        act_data = ActData
    } = CustomData = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
    NowTime = utime:unixtime(),
    NewActData =
        case ActData of
            #role_phantom{time = Time} ->
                ActData;
            _ ->
                Time = 0,
                #role_phantom{time = NowTime}
        end,
    IsSame = utime:is_same_day(NowTime, Time),
    NewData =
        if
            IsSame -> NewActData;
            true ->
                update_task_data(NowTime, NewActData)
        end,
    if
        NewData =/= ActData ->
            NewCustomData = CustomData#custom_act_data{act_data = NewData},
            lib_custom_act_data:save_custom_data(RoleId, NewCustomData);
        true ->
            NewCustomData = CustomData
    end,
    {NewCustomData, NewData}.

update_task_data(NowTime, ActData) ->
    TaskIds = data_pass_codex:get_phantom_task_ids(),
    NewPhantomTask =
        [#phantom_task{task_id = TaskId, count = 0} || TaskId <- TaskIds],
    ActData#role_phantom{time = NowTime, phantom_task = NewPhantomTask}.


%%--------------------------gm--------------------------------
%% 增加积分
gm_add_score(Player, SubType, ScoreAdd) ->
    #player_status{id = RoleId} = Player,
    case lib_custom_act_util:get_custom_act_open_info(?CUSTOM_ACT_TYPE_PHANTOM, SubType) of
        #act_info{} ->
            {CustomData, ActData} = get_act_data(RoleId, SubType),
            add_phantom_exp(RoleId, ?CUSTOM_ACT_TYPE_PHANTOM, SubType, ScoreAdd, ActData, CustomData);
        _ ->
            skip
    end.

%% 重置宝典
gm_reset(Player) ->
    #player_status{id = RoleId} = Player,
    case lib_custom_act_util:get_open_subtype_list(?CUSTOM_ACT_TYPE_PHANTOM) of
        ActInfos = [_ | _] ->
            lists:map(fun(#act_info{key = {_, SubType}}) ->
                CustomData = lib_custom_act_data:custom_act_data(?CUSTOM_ACT_TYPE_PHANTOM, SubType),
                #custom_act_data{act_data = OldActData} = CustomData,
                case OldActData of
                    #role_phantom{} ->
                        ActData = OldActData#role_phantom{
                            score = 0,              %% 积分
                            lv = 0,              %% 等级
                            pay_phantom = 0,              %% 0 普通宝典|非0 王牌宝典
                            normal_reward = [],             %% 普通宝典 已领取等级[lv,...]
                            pay_reward = [],             %% 付费宝典 已领取等级[lv,...]
                            time = 0,              %% 上次任务更新时间戳
                            phantom_task = []              %% [#phantom_task]
                        },
                        NewActData = update_task_data(utime:unixtime(), ActData),
                        lib_custom_act_data:save_custom_data(RoleId, CustomData#custom_act_data{act_data = NewActData});
                    _ ->
                        skip
                end
                      end, ActInfos);
        _ ->
            skip
    end.