%%-----------------------------------------------------------------------------
%% @Module  :       mod_hi_point
%% @Author  :       Fwx
%% @Created :       2018-03-16
%% @Description:    嗨点活动
%%-----------------------------------------------------------------------------
-module(mod_hi_point).

-include("custom_act.hrl").
-include("common.hrl").
-include("errcode.hrl").
-include("def_fun.hrl").
-include("goods.hrl").
-include("scene.hrl").
-include("hi_point.hrl").
-include("figure.hrl").
-include("role.hrl").
-include("server.hrl").
-include("def_module.hrl").
-include("dungeon.hrl").
-include("predefine.hrl").

-behaviour(gen_server).

-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).

-export([
    login/1,
    logout/1,
    get_open_hi_act/0,
    act_info/3,                 %% 活动信息
    act_end/2,                  %% 活动结束
    receive_reward/5,           %% 领取奖励
    send_reward_status/2,       %% 发送奖励领取状态
    success_end/3,              %% 完成目标操作
    success_end/4,              %% 完成目标操作
    gm_add_points/3,            %% 秘籍增加点数
    refresh_recharge/4,         %% 刷新充值数据
    refresh_consume/3,          %% 刷新消费
    use_goods_add/2             %% 使用物品增加嗨点值
    , role_get_award/5
]).
%% 开启中的嗨点类活动
get_open_hi_act() ->
    ActList = [?CUSTOM_ACT_TYPE_HI_POINT, ?CUSTOM_ACT_TYPE_HI_POINT_2],
    lib_custom_act_api:get_custom_act_open_info_by_actids(ActList).
%% -------------------------------------------------------------------------------------------------------------------
%% API
%% -------------------------------------------------------------------------------------------------------------------
%% 玩家上线加载嗨点数据
login(RoleId) ->
    [
        gen_server:cast(?MODULE, {'login', ActInfo, RoleId})
        || ActInfo <- get_open_hi_act()
    ].

%% 下线清除嗨点数据
logout(RoleId) ->
    [
        gen_server:cast(?MODULE, {'logout', Type, SubType, RoleId})
        || #act_info{key = {Type, SubType}} <- get_open_hi_act()
    ].

%% 完成目标
success_end(RoleId, ModId, SubId) ->
    success_end(RoleId, ModId, SubId, 1).
success_end(RoleId, ModId, SubId, Count) ->
    [
        begin
            SuitNum = get_suit_num(Type, SubType),
            case lists:member({ModId, SubId}, data_hi_point:get_keys(SuitNum)) of
                true ->
                    gen_server:cast(?MODULE, {'success_end', Type, SubType, RoleId, ModId, SubId, Count});
                false ->
                    ok
            end
        end
        || #act_info{key = {Type, SubType}} <- get_open_hi_act()
    ].

%% 刷新充值
refresh_recharge(RoleId, Type, ActSub, PayNum) ->
    gen_server:cast(?MODULE, {'refresh_recharge', RoleId, Type, ActSub, PayNum}).

%% 刷新消费
refresh_consume(Player, ActInfos, MoneyMap) ->
    #player_status{id = RoleId, gold = Gold} = Player,
    [
        case maps:find(old_gold, MoneyMap) of
            {ok, OldGold} when OldGold > 0 ->
                gen_server:cast(?MODULE, {'consume', RoleId, Type, SubType, OldGold - Gold});
            _ ->
                ok
        end
        || #act_info{key = {Type, SubType}}<- ActInfos
    ].

%% 活动信息
act_info(PS, Type, SubType) when is_record(PS, player_status)->
    act_info(Type, SubType, PS#player_status.id),
    {ok, PS};
act_info(Type, SubType, RoleId) ->
    gen_server:cast(?MODULE, {'act_info', Type, SubType, RoleId}).

%% 活动结束
act_end(EndType, ActInfo) ->
    gen_server:cast(?MODULE, {'act_end', EndType, ActInfo}).

%% 奖励领取状态
send_reward_status(RoleId, #act_info{key = {Type, SubType}}) ->
    gen_server:cast(?MODULE, {'send_reward_status', Type, SubType, RoleId}).

%% 领取累计嗨点奖励
receive_reward(RoleId, Type, SubType, GradeId, Reward) ->
    case lib_custom_act_api:is_open_act(Type, SubType) of
        true -> gen_server:cast(?MODULE, {'receive_reward', RoleId, Type, SubType, GradeId, Reward});
        false -> lib_custom_act:send_error_code(RoleId, ?ERRCODE(err331_act_closed))
    end.

%% 使用物品增加嗨点值
use_goods_add(RoleId, Value) ->
    [
        gen_server:cast(?MODULE, {'use_goods_add', RoleId, Value, Type, SubType})
        || #act_info{key = {Type, SubType}} <- get_open_hi_act()
    ].

gm_add_points(_SubType, Num, RoleId) ->
    [
        gen_server:cast(?MODULE, {'gm_add_points', Type, SubType, Num, RoleId})
        || #act_info{key = {Type, SubType}} <- get_open_hi_act()
    ].
%% -------------------------------------------------------------------------------------------------------------------
%% -------------------------------------------------------------------------------------------------------------------
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        {ok, NewState} when is_record(NewState, act_state) ->
            {noreply, NewState};
        Err ->
            ?ERR("handle_cast Msg:~p error:~p~n", [Msg, Err]),
            {noreply, State}
    end.

handle_info(Info, State) ->
    case catch do_handle_info(Info, State) of
        {ok, NewState} when is_record(NewState, act_state) ->
            {noreply, NewState};
        Err ->
            ?ERR("handle_info Info:~p error:~p~n", [Info, Err]),
            {noreply, State}
    end.

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

handle_call(Request, _From, State) ->
    case catch do_handle_call(Request, State) of
        {ok, Reply} ->
            {reply, Reply, State};
        Err ->
            ?ERR("handle_call Request:~p error:~p~n", [Request, Err]),
            {noreply, State}
    end.

do_handle_call(_Request, _State) -> {ok, ok}.

terminate(_Reason, _State) ->
    ok.

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


%% -------------------------------------------------------------------------------------------------------------------
init([]) ->
    {ok, #act_state{}}.

%% ---------------------------------------------------------------------------------------------------------------
%% 上线初始化
do_handle_cast({login, #act_info{key = {Type, SubType}, stime = STime, etime = ETime}, RoleId}, State) ->
    SQL = io_lib:format(?SELECT_HI_DATA, [RoleId, Type, SubType]),
    case db:get_row(SQL) of
        [Points, ExtraPoints, TaskInfo, RewardInfo, Utime]
            when Utime >= STime andalso Utime =< ETime ->
            RoleInfo = #role_info{
                sum_points = Points,                %% 总狂欢值(各模块总狂欢值)
                extra_points = ExtraPoints,         %% 使用物品额外获得的狂欢值
                points_list = util:bitstring_to_term(TaskInfo),       %% 各模块对应狂欢值列表 [#hi_points{}]
                reward_status = util:bitstring_to_term(RewardInfo),     %% [{GradeId, Status}]  0:不可领 1；可领 2：已领
                utime = Utime               %% 更新时间
            },
            #act_state{act_maps = ActMap} = State,
            RoleMap = maps:get({Type, SubType}, ActMap, #{}),
            NewRoleMap = RoleMap#{RoleId => RoleInfo},
            NewActMap = maps:put({Type, SubType}, NewRoleMap, ActMap),
            {ok, State#act_state{act_maps = NewActMap}};
        _ ->
            {ok, State}
    end;

%% 离线清理
do_handle_cast({logout, Type, SubType, RoleId}, State) ->
    #act_state{act_maps = ActMap} = State,
    RoleMap = maps:get({Type, SubType}, ActMap, #{}),
    NewRoleMap = maps:remove(RoleId, RoleMap),
    NewActMap = maps:put({Type, SubType}, NewRoleMap, ActMap),
    {ok, State#act_state{act_maps = NewActMap}};

%% 嗨点信息-嗨点值/任务情况
do_handle_cast({'act_info', Type, SubType, RoleId}, State) ->
    #act_state{act_maps = ActMaps} = State,
    RoleMap = maps:get({Type, SubType}, ActMaps, #{}),
    #role_info{sum_points = SumPots, points_list = PotList}
        = maps:get(RoleId, RoleMap, #role_info{}),
    SuitNum = get_suit_num(Type, SubType),
    F = fun({ModId, SubId}, Acc) ->
        case data_hi_point:get_hi_point_cfg(SuitNum,ModId, SubId) of
            #base_hi_point{name = Name, one_points = OnePots, max_count = MaxCount, order_id = OrderId, jump_id = JumpId} ->
                case ModId =:= ?MOD_RECHARGE of
                    true ->
                        case lists:keyfind({ModId, 0}, #hi_points.key, PotList) of
                            false -> ActCount = 0;
                            #hi_points{count = Count} -> ActCount = Count
                        end,
                        %% 充值最大值为子Id
                        MaxPots = SubId;
                    false ->
                        case lists:keyfind({ModId, SubId}, #hi_points.key, PotList) of
                            false -> Count = 0;
                            #hi_points{count = Count} -> skip
                        end,
                        ActCount = min(MaxCount, Count),
                        MaxPots = OnePots * MaxCount
                end,
                % ?INFO_TTY("~w~n", [{ModId, SubId, OnePots, MaxPots, ActCount}]),
                [{ModId, Name, OnePots, MaxPots, ActCount, OrderId, util:term_to_string(JumpId), SubId} | Acc];
            _ ->
                ?ERR("hi point config error:[~p, ~p]~n", [ModId, SubId]), Acc
        end end,
    SendList = lists:foldl(F, [], data_hi_point:get_keys(SuitNum)),
    % ?INFO_TTY("Sum Status {Type, SumPots} is ~w~n", [{SubType, SumPots}]),
    lib_server_send:send_to_uid(RoleId, pt_331, 33140, [Type, SubType, SumPots, SendList]),
    {ok, State};

%% 完成任务
do_handle_cast({'success_end', Type, SubType, RoleId, ModId, SubId, Count}, State) ->
    %?INFO_TTY("'success_end' RoleId, ModId, SubId is ~w~n",[{Type, SubType, RoleId, ModId, SubId}]),
    #act_state{act_maps = ActMap} = State,
    SuitNum = get_suit_num(Type, SubType),
    NowTime = utime:unixtime(),
    RoleMap = maps:get({Type, SubType}, ActMap, #{}),
    #role_info{sum_points = OldPots, points_list = PotL}
        = RoleInfo = maps:get(RoleId, RoleMap, #role_info{}),
    #base_hi_point{max_count = MaxCount, one_points = OnePoint} = data_hi_point:get_hi_point_cfg(SuitNum, ModId, SubId),
    TaskInfo = lists:keyfind({ModId, SubId}, #hi_points.key, PotL),
    if
        is_record(TaskInfo, hi_points) andalso TaskInfo#hi_points.count >= MaxCount ->
            %% 任务已经全部完成了
            {ok, State};
        true ->
            OldTask =
                case is_record(TaskInfo, hi_points) of
                    true  -> TaskInfo;
                    false -> #hi_points{key = {ModId, SubId}}
                end,
            %% 更新任务进度/统计总嗨点值
            NewTask = OldTask#hi_points{count = min(MaxCount, OldTask#hi_points.count + Count)},
            NewPotL = lists:keystore({ModId, SubId}, #hi_points.key, PotL, NewTask),
            NewRoleInfo = RoleInfo#role_info{points_list = NewPotL, sum_points = OldPots + OnePoint*Count, utime = NowTime},
            %% 更新可领取奖励状态
            LastRoleInfo = refresh_reward_status(Type, SubType, NewRoleInfo),
            %% 实时保存
            db_save_hi_data(RoleId, Type, SubType, LastRoleInfo),
            
            #base_hi_point{name = Name} = data_hi_point:get_hi_point_cfg(SuitNum, ModId, SubId),
            NewSumPoints = LastRoleInfo#role_info.sum_points,
            %% 推送累计热点
            notice_hi_point(RoleId, Type, SubType, NewSumPoints),
            lib_log_api:log_custom_act_hi_point(RoleId, OldPots, max(0, NewSumPoints - OldPots), NewSumPoints, Name),
            NewRoleMap = maps:put(RoleId, LastRoleInfo, RoleMap),
            NewActMap  = maps:put({Type, SubType}, NewRoleMap, ActMap),
            {ok, State#act_state{act_maps = NewActMap}}
    end;

%% 完成任务特殊处理-充值
do_handle_cast({'refresh_recharge', RoleId, Type, SubType, PayNum}, State) ->
    NowTime = utime:unixtime(),
    #act_state{act_maps = ActMap} = State,
    RoleMap  = maps:get({Type, SubType}, ActMap, #{}),
    RoleInfo = maps:get(RoleId, RoleMap, #role_info{}),
    OldPotL = RoleInfo#role_info.points_list,
    OldPayNum = case lists:keyfind({?MOD_RECHARGE, 0}, #hi_points.key, OldPotL) of
                    false -> 0;
                    #hi_points{count = Count} -> Count
                end,
    NewPotL = lists:keystore({?MOD_RECHARGE, 0}, #hi_points.key, OldPotL, #hi_points{key = {?MOD_RECHARGE, 0}, count = PayNum}),
    AddPots =  get_charge_add_pots(Type, SubType, OldPayNum, PayNum),
    case AddPots > 0 of
        true  ->
            NewRoleInfo = RoleInfo#role_info{
                points_list = NewPotL,
                sum_points  = RoleInfo#role_info.sum_points + AddPots,
                utime = NowTime
            },
            OldSumPoints = RoleInfo#role_info.sum_points,
            NewSumPoints = NewRoleInfo#role_info.sum_points,
            notice_hi_point(RoleId, Type, SubType, NewSumPoints),
            Name = io_lib:format("recharge_act:~p", [PayNum]),
            lib_log_api:log_custom_act_hi_point(RoleId, OldSumPoints, max(0, NewSumPoints - OldSumPoints), NewSumPoints, Name),
            LastRoleInfo = refresh_reward_status(Type, SubType, NewRoleInfo);
        false ->
            LastRoleInfo = RoleInfo#role_info{points_list = NewPotL, utime = NowTime}
    end,
    %% 实时保存
    db_save_hi_data(RoleId, Type, SubType, LastRoleInfo),
    NewRoleMap = maps:put(RoleId, LastRoleInfo, RoleMap),
    NewActMap  = maps:put({Type, SubType}, NewRoleMap, ActMap),
    NewState = State#act_state{act_maps = NewActMap},
    {ok, NewState};

%% 完成任务特殊处理-消费
do_handle_cast({'consume', RoleId, Type, SubType, Cost}, State) ->
    SuitNum = get_suit_num(Type, SubType),
    KeyList =  data_hi_point:get_keys(SuitNum),
    case lists:keyfind(?MOD_CONSUME, 1, KeyList) of
        {ModId, SubId} ->
            #base_hi_point{
                max_count = MaxCount
            } = data_hi_point:get_hi_point_cfg(SuitNum, ModId, SubId),
            #act_state{act_maps = ActMap} = State,
            RoleMap  = maps:get({Type, SubType}, ActMap, #{}),
            RoleInfo = maps:get(RoleId, RoleMap, #role_info{}),
            OldPotL = RoleInfo#role_info.points_list,
            OldCost = case lists:keyfind({?MOD_CONSUME, 0}, #hi_points.key, OldPotL) of
                          false -> 0;
                          #hi_points{count = Count} -> Count
                      end,
            MaxAddCost = MaxCount * SubId,
            case OldCost >= MaxAddCost of
                true  ->
                    %% 这个任务已经完成了
                    {ok, State};
                false ->
                    NewCost = min(OldCost + Cost, MaxAddCost),
                    NewPotL = lists:keystore({?MOD_CONSUME, 0}, #hi_points.key, OldPotL, #hi_points{key = {?MOD_CONSUME, 0}, count = NewCost}),
                    LastRoleInfo = RoleInfo#role_info{points_list = NewPotL},
                    NewRoleMap = maps:put(RoleId, LastRoleInfo, RoleMap),
                    NewActMap  = maps:put({Type, SubType}, NewRoleMap, ActMap),
                    NewState = State#act_state{act_maps = NewActMap},
    
                    OldTaskInfo =
                        case lists:keyfind({ModId, SubId}, #hi_points.key, OldPotL) of
                            false  -> #hi_points{key = {ModId, SubId}};
                            TaskInfo -> TaskInfo
                        end,
                    %% 子id就是消耗单位
                    AddTimes = (NewCost div SubId) - OldTaskInfo#hi_points.count,
                    case AddTimes > 0 of
                        true  ->
                            do_handle_cast({'success_end', Type, SubType, RoleId, ModId, SubId, AddTimes}, NewState);
                        false ->
                            %% 实时保存
                            db_save_hi_data(RoleId, Type, SubType, LastRoleInfo),
                            {ok, NewState}
                    end
            end;
        _ ->
            {ok, State}
    end;

%% 使用物品增加嗨点值
do_handle_cast({'use_goods_add', RoleId, Num, Type, SubType}, State) ->
    %% 有活动开启才增加
    #act_state{act_maps = ActMap} = State,
    RoleMap  = maps:get({Type, SubType}, ActMap, #{}),
    RoleInfo = maps:get(RoleId, RoleMap, #role_info{}),
    TmpRoleInfo = RoleInfo#role_info{
        extra_points = RoleInfo#role_info.extra_points + Num,
        sum_points = RoleInfo#role_info.sum_points + Num,
        utime = utime:unixtime()
    },
    NewRoleInfo = refresh_reward_status(Type, SubType, TmpRoleInfo),
    %% 实时保存
    db_save_hi_data(RoleId, Type, SubType, NewRoleInfo),
    NewRoleMap  = maps:put(RoleId, NewRoleInfo, RoleMap),
    
    OldSumPoints = RoleInfo#role_info.sum_points,
    NewSumPoints = NewRoleInfo#role_info.sum_points,
    notice_hi_point(RoleId, Type, SubType, NewSumPoints),
    lib_log_api:log_custom_act_hi_point(RoleId, OldSumPoints,
        max(0, NewSumPoints - OldSumPoints), NewSumPoints, "use_goods_add"),
    NewActMap = maps:put({Type, SubType}, NewRoleMap, ActMap),
    NewState = State#act_state{act_maps = NewActMap},
    {ok, NewState};

%% 奖励领取状态
do_handle_cast({'send_reward_status', Type, SubType, RoleId}, State) ->
    #act_state{act_maps = ActMap} = State,
    RoleMap = maps:get({Type, SubType}, ActMap, #{}),
    send_33104(RoleMap, Type, SubType, RoleId),
    {ok, State};

%% 领奖
do_handle_cast({'receive_reward', RoleId, Type, SubType, GradeId, Reward}, State) ->
    NowTime = utime:unixtime(),
    #act_state{act_maps = ActMap} = State,
    RoleMap = maps:get({Type, SubType}, ActMap, #{}),
    case maps:get(RoleId, RoleMap, false) of
        #role_info{} = RoleInfo ->
            case get_hi_reward(Type, SubType, GradeId, RoleInfo) of
                {ok, NewRoleInfo} ->
                    %% 实时保存
                    db_save_hi_data(RoleId, Type, SubType, NewRoleInfo),
                    notice_hi_point(RoleId, Type, SubType, NewRoleInfo#role_info.sum_points),
                    send_reward(RoleId, Type, SubType, GradeId, Reward),
                    WorldLv = util:get_world_lv(),
                    lib_log_api:log_custom_act_reward(RoleId, Type, SubType,
                        0, WorldLv, Reward, [], 0, 0, 0, 0, 0, 0, utime:unixtime()
                    ),
                    lib_server_send:send_to_uid(RoleId, pt_331, 33105, [?SUCCESS, Type, SubType, GradeId]),
                    NewRoleMap = maps:put(RoleId, NewRoleInfo#role_info{utime = NowTime}, RoleMap),
                    NewActMap  = maps:put({Type, SubType}, NewRoleMap, ActMap),
                    NewState = State#act_state{act_maps = NewActMap};
                {false, Error} ->
                    lib_server_send:send_to_uid(RoleId, pt_331, 33105, [Error, Type, SubType, GradeId]),
                    NewState = State
            end;
        _ ->
            lib_server_send:send_to_uid(RoleId, pt_331, 33105, [?ERRCODE(err331_hi_points_subtype_err), Type, SubType, GradeId]),
            NewState = State
    end,
    {ok, NewState};

%% 活动结束-清除数据
do_handle_cast({'act_end', _EndType, #act_info{key = {Type, SubType}} = _ActInfo}, State) ->
    %?PRINT("~p~n", [SubType]),
    #act_state{act_maps = ActMap} = State,
    spawn(fun() -> db:execute(?CLEAN_HI_DATA, [Type, SubType]) end),
    NewActMap = maps:remove({Type, SubType}, ActMap),
    NewState  = State#act_state{act_maps = NewActMap},
    {ok, NewState};

%% GM增加嗨点值
do_handle_cast({'gm_add_points', Type, SubType, Num, RoleId}, State) ->
    #act_state{act_maps = ActMap} = State,
    RoleMap = maps:get({Type, SubType}, ActMap, #{}),
    RoleInfo = maps:get(RoleId, RoleMap, #role_info{}),
    TmpRoleInfo = RoleInfo#role_info{sum_points = RoleInfo#role_info.sum_points + Num, utime = utime:unixtime()},
    NewRoleInfo = refresh_reward_status(Type, SubType, TmpRoleInfo),
    %% 实时保存
    db_save_hi_data(RoleId, Type, SubType, NewRoleInfo),
    notice_hi_point(RoleId, Type, SubType, NewRoleInfo#role_info.sum_points),
    NewRoleMap = maps:put(RoleId, NewRoleInfo, RoleMap),
    NewActMap = maps:put({Type, SubType}, NewRoleMap, ActMap),
    NewState = State#act_state{act_maps = NewActMap},
    {ok, NewState};

do_handle_cast(_Msg, State) -> {ok, State}.

%% --------------------- Builtin Function ----------------------------
%% 获取本期活动对应的活动套数
get_suit_num(Type, SubType) ->
    case lib_custom_act_util:get_act_cfg_info(Type, SubType) of
        #custom_act_cfg{condition = Condition} ->
            case lists:keyfind(suit, 1, Condition) of
                {_, Suit} -> ok;
                _ -> Suit = 1
            end;
        _ ->
            Suit = 1
    end,
    Suit.

%% 更新累计热点值可领奖励
refresh_reward_status(?CUSTOM_ACT_TYPE_HI_POINT, SubType, RoleInfo) ->
    #role_info{sum_points = SumPots, reward_status = StatusList} = RoleInfo,
    GradeList = lib_custom_act_util:get_act_reward_grade_list(?CUSTOM_ACT_TYPE_HI_POINT, SubType),
    ForFun = fun(GradeId, TList) ->
        case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_HI_POINT, SubType, GradeId) of
            #custom_act_reward_cfg{condition = Condition} ->
                case lists:keyfind(hi_points, 1, Condition) of
                    false -> Status = ?ACT_REWARD_CAN_NOT_GET;
                    {_, CfgPots} ->
                        case lists:keyfind(GradeId, 1, StatusList) of
                            false ->
                                Status = ?IF(SumPots >= CfgPots, ?ACT_REWARD_CAN_GET, ?ACT_REWARD_CAN_NOT_GET);
                            {_, ?ACT_REWARD_HAS_GET} -> Status = ?ACT_REWARD_HAS_GET;
                            {_, _OldStatus} ->
                                Status = ?IF(SumPots >= CfgPots, ?ACT_REWARD_CAN_GET, ?ACT_REWARD_CAN_NOT_GET)
                        end
                end,
                [{GradeId, Status}|TList];
            _ ->
                TList
        end end,
    NewStatusL = lists:foldl(ForFun, [], GradeList),
    RoleInfo#role_info{reward_status = NewStatusL};
refresh_reward_status(_Type, _SubType, RoleInfo) ->
    RoleInfo.

%% 推送累计热点奖励状态
send_33104(RoleMap, ?CUSTOM_ACT_TYPE_HI_POINT, SubType, RoleId) ->
    OpenActList = lib_custom_act_util:get_custom_act_open_list(),
    F = fun(GradeId, Acc) ->
        case lib_custom_act_util:get_act_reward_cfg_info(?CUSTOM_ACT_TYPE_HI_POINT, SubType, GradeId) of
            #custom_act_reward_cfg{name = Name, desc = Desc, condition = Condition, format = Format, reward = Reward} ->
                case lists:keyfind({?CUSTOM_ACT_TYPE_HI_POINT, SubType}, #act_info.key, OpenActList) of
                    false -> ?ERR("hi point act not open!~n", []), Acc;
                    _ ->
                        Status = case maps:get(RoleId, RoleMap, false) of
                                     false -> ?ACT_REWARD_CAN_NOT_GET;
                                     #role_info{reward_status = StatusList} ->
                                         case lists:keyfind(GradeId, 1, StatusList) of
                                             false -> ?ACT_REWARD_CAN_NOT_GET;
                                             {_, TmpStatus} -> TmpStatus
                                         end
                                 end,
                        ConditionStr = util:term_to_string(Condition),
                        RewardStr    = util:term_to_string(Reward),
                        [{GradeId, Format, 0, Status, 1, Name, Desc, ConditionStr, RewardStr} | Acc]
                end;
            _ -> Acc
        end end,
    SendList = lists:foldl(F, [], lib_custom_act_util:get_act_reward_grade_list(?CUSTOM_ACT_TYPE_HI_POINT, SubType)),
    lib_server_send:send_to_uid(RoleId, pt_331, 33104, [?CUSTOM_ACT_TYPE_HI_POINT, SubType, lists:reverse(SendList)]);
send_33104(RoleMap, Type = ?CUSTOM_ACT_TYPE_HI_POINT_2, SubType, RoleId) ->
    OpenActList = lib_custom_act_util:get_custom_act_open_list(),
    F = fun(GradeId, Acc) ->
        case lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId) of
            #custom_act_reward_cfg{name = Name, desc = Desc, condition = Condition, format = Format, reward = Reward} ->
                case lists:keyfind({Type, SubType}, #act_info.key, OpenActList) of
                    false -> ?ERR("hi point act not open!~n", []), Acc;
                    _ ->
                        case maps:get(RoleId, RoleMap, false) of
                            false ->
                                Points = 0,
                                ReceiveTimes = 0;
                            #role_info{reward_status = StatusList, sum_points = Points} ->
                                case lists:keyfind(GradeId, 1, StatusList) of
                                    false ->
                                        ReceiveTimes = 0;
                                    {_, TmpStatus} ->
                                        ReceiveTimes = TmpStatus
                                end
                        end,
                        case lists:keyfind(limit_times, 1, Condition) of
                            {_, CfgLimit} -> MaxNum = CfgLimit;
                            _ -> MaxNum = 0
                        end,
                        case lists:keyfind(hi_points, 1, Condition) of
                            {_, CfgPots} -> NeedPoints = CfgPots;
                            _ -> NeedPoints = max
                        end,
                        if
                            ReceiveTimes >= MaxNum -> Status = ?ACT_REWARD_HAS_GET;
                            Points >= NeedPoints ->  Status = ?ACT_REWARD_CAN_GET;
                            true -> Status = ?ACT_REWARD_CAN_NOT_GET
                        end,
                        ConditionStr = util:term_to_string(Condition),
                        RewardStr    = util:term_to_string(Reward),
                        [{GradeId, Format, 0, Status, ReceiveTimes, Name, Desc, ConditionStr, RewardStr} | Acc]
                end;
            _ -> Acc
        end end,
    SendList = lists:foldl(F, [], lib_custom_act_util:get_act_reward_grade_list(Type, SubType)),
    lib_server_send:send_to_uid(RoleId, pt_331, 33104, [Type, SubType, lists:reverse(SendList)]).

%% 领取嗨点奖励
get_hi_reward(?CUSTOM_ACT_TYPE_HI_POINT, _SubType, GradeId, RoleInfo) ->
    #role_info{reward_status = StatusList} = RoleInfo,
    case lists:keyfind(GradeId, 1, StatusList) of
        {_, ?ACT_REWARD_CAN_GET} ->
            
            NewStatusL  = lists:keystore(GradeId, 1, StatusList, {GradeId, ?ACT_REWARD_HAS_GET}),
            NewRoleInfo = RoleInfo#role_info{reward_status = NewStatusL},
            {ok, NewRoleInfo};
        _ ->
            {false, ?ERRCODE(err331_hi_points_not_receive)}
    end;
get_hi_reward(Type = ?CUSTOM_ACT_TYPE_HI_POINT_2, SubType, GradeId, RoleInfo) ->
    #role_info{reward_status = StatusList, sum_points = Points} = RoleInfo,
    case lists:keyfind(GradeId, 1, StatusList) of
        {_, GetNum} -> GetNum;
        _ -> GetNum = 0
    end,
    #custom_act_reward_cfg{condition = Condition} =
        lib_custom_act_util:get_act_reward_cfg_info(Type, SubType, GradeId),
    case lists:keyfind(limit_times, 1, Condition) of
        {_, CfgLimit} -> MaxNum = CfgLimit;
        _ -> MaxNum = 0
    end,
    case lists:keyfind(hi_points,1 , Condition) of
        {_, CfgPots} -> NeedPots = CfgPots;
        _ -> NeedPots = max
    end,
    if
        GetNum >= MaxNum -> {false, ?ERRCODE(err331_count_limit)};
        NeedPots > Points -> {false, ?ERRCODE(err331_act_can_not_get)};
        true ->
            NewNum = GetNum + 1,
            NewStatusL  = lists:keystore(GradeId, 1, StatusList, {GradeId, NewNum}),
            NewRoleInfo = RoleInfo#role_info{reward_status = NewStatusL, sum_points = max(0, Points - NeedPots)},
            {ok, NewRoleInfo}
    end.

%% 统计充值增加的嗨点值
get_charge_add_pots(Type, SubType, OldNum, Num) ->
    SuitNum = get_suit_num(Type, SubType),
    F = fun({ModId, SubId}, Acc) ->
        case Num >= SubId of
            true ->
                case data_hi_point:get_hi_point_cfg(SuitNum, ModId, SubId) of
                    #base_hi_point{one_points = OddPots} -> Acc + OddPots;
                    _ -> Acc
                end;
            _ -> Acc
        end end,
    lists:foldl(F, 0, [{ModId, CfgNum} || {ModId, CfgNum} <- data_hi_point:get_keys(SuitNum), CfgNum > OldNum, CfgNum =< Num, ModId =:= ?MOD_RECHARGE]).

%% 刷新新的嗨点值
notice_hi_point(RoleId, Type, SubType, Point) ->
    {ok, Bin} = pt_332:write(33289, [Type, SubType, Point]),
    lib_server_send:send_to_uid(RoleId, Bin).

%% 保存嗨点数据
db_save_hi_data(RoleId, Type, SubType, RoleInfo) ->
    #role_info{
        sum_points = SumPoint,         %% 总狂欢值(各模块总狂欢值)
        extra_points = ExtraPoint,       %% 使用物品额外获得的狂欢值
        points_list = TaskList,       %% 各模块对应狂欢值列表 [#hi_points{}]
        reward_status = RewardStatus,     %% [{GradeId, Status}]  0:不可领 1；可领 2：已领
        utime = UTime               %% 更新时间
    } = RoleInfo,
    SQL = io_lib:format(?SAVE_HI_DATA, [RoleId, Type, SubType, SumPoint, ExtraPoint, util:term_to_bitstring(TaskList), util:term_to_bitstring(RewardStatus), UTime]),
    db:execute(SQL),
    ok.

send_reward(RoleId, Type, SubType, Grade, Award) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_get_award, [Type, SubType, Grade, Award]).

role_get_award(Player, Type, SubType, Grade, Award) ->
    #player_status{
        figure = Figure
    } = Player,
    Player1 = lib_goods_api:send_reward(Player, Award, hi_points),
    lib_log_api:log_custom_act_reward(Player#player_status.id, Type, SubType, Grade, 0, Award, "", Figure#figure.vip, Figure#figure.lv,
        Player#player_status.gold, Player1#player_status.gold, Player#player_status.bgold, Player1#player_status.bgold, utime:unixtime()),
    Player1.