%%%------------------------------------
%%% @Module  : mod_arena_cast
%%% @Author  :  xiaoxiang
%%% @Created :  2017-03-23
%%% @Description: arena  sys:get_state(mod_arena).erlang:process_info(whereis(mod_arena),dictionary).
%%%------------------------------------
-module(mod_arena_cast).

-include("figure.hrl").
-include("errcode.hrl").
-include("common.hrl").
-include("arena.hrl").
-include("predefine.hrl").
-include("def_event.hrl").
-include("def_fun.hrl").
-include("def_goods.hrl").
-include("rec_event.hrl").
-include("def_module.hrl").
-include("def_vip.hrl").
-include("role.hrl").
-include("daily.hrl").
-include("goods.hrl").
-include("language.hrl").
-include("server.hrl").
-include("transform.hrl").
-include("sys_setting.hrl").

-export([
    get_arena_role/12       %% 获取玩家arena信息
    , get_sp_list/2         %% 大神列表
    , random_rival_role/2   %% 随机对手
    , create_battle/4       %% 创建战场
    , get_reward/2          %% 获取每日奖励
    , get_sp_reward/2       %% 获取大神奖励
    , get_rank_list/4       %% 榜单数据
    , challenge_image_role/5        %% 战斗结算
    , set_battle_status/3           %% 设置位置战斗状态
    , clean_redundancy/1            %% 清理冗余数据
    , get_rank_role/2               %% 获取maps里排名信息
    , cancel_battle/2
    , gm_release_battle_status/2    %% GM命令：释放战斗状态
]).

%% @doc 获取玩家arena信息
get_arena_role(State, RoleId, Combat, UseNum, BuyNum, IsReward, FirstWin, FiveBattle, SPNum, SPAward, Trigger, NowCoolTime) ->
    %% 获取免费挑战次数
    MaxNum = case data_arena:get_arena_value(?ARENA_FREE_NUM_MAX) of
        [] -> 0;
        [TmpMaxNum] -> TmpMaxNum
    end,
    %% 可战斗次数 = 免费次数 + 购买次数- 使用次数
    ARENANum = max(MaxNum + BuyNum - UseNum, 0),
    #real_role{
        rank = Rank,
        history_rank = HistoryRank
    } = RealRole = get_real_role(State, RoleId),
    RewardRank = get_daily_reward_rank(RealRole),
    %% 每日奖励领取状态 0-不可领取 1-可领取 2-已领取
    DailyStatus =
    case get_rank_reward(State#arena_state.season, RewardRank) of
        [] -> 0;
        _  -> IsReward + 1
    end,
    %% 5战奖励领取状态 0-不可领取 1-可领取 2-已领取
    FiveBattleStatus =
    case UseNum + SPNum < ?ARENA_BATTLE_REWARD_NUM of
        true  -> 0;
        false -> FiveBattle + 1
    end,
    ProData = [
        Rank, HistoryRank, RewardRank, Combat
        ,DailyStatus, FirstWin, FiveBattleStatus, ARENANum, SPNum, SPAward
        ,Trigger, NowCoolTime
    ],
    lib_server_send:send_to_uid(RoleId, pt_280, 28001, ProData),
    State.

%% @doc 大神列表
get_sp_list(State, Sid) ->
    RankList =
        [
            begin
                #figure{
                    id = RoleId
                } = Figure = get_rival_figure(State, Rank),
                {Rank, RoleId, Figure}
            end
            || Rank <- lists:seq(1, lib_arena_util:get_arena_cfg(?ARENA_SP_ROLE_NUM, 9))
        ],
    lib_server_send:send_to_sid(Sid, pt_280, 28009, [RankList]),
    State.
%% @doc 随机对手：这里保证排名大于3000的玩家一定是假人
random_rival_role(State, RoleId) ->
    #real_role{rank = Rank} = get_real_role(State, RoleId),
    List = do_random_rival(State, Rank, RoleId),
    F = fun(RankTemp, TempList) ->
        #figure{
            id = RivalId
        } = Figure = get_rival_figure(State, RankTemp),
        [{RankTemp, RivalId, Figure} | TempList]
    end,
    InfoList = lists:foldl(F, [], List),
    lib_server_send:send_to_uid(RoleId, pt_280, 28002, [InfoList]),
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, lib_arena, after_random_rival_role, [List]),
    State.
do_random_rival(_State, Rank, _RoleId) ->
    %% 排名区间
    RId = get_rank_id(Rank),
    RankId = ?IF(RId == 0, lists:max(data_arena:get_id_list()), RId),
    %% 最大排名
    MaxRank = ?ARENA_MAX_RANK_TRULY,
    {_Min, MinRange, MaxRange} = case data_arena:get_search_cfg(RankId) of
                                     #arena_search_cfg{
                                         min = TmpMin, min_range = TmpMinRange, max_range = TmpMaxRange
                                     } ->
                                         {TmpMin, TmpMinRange, TmpMaxRange};
                                     _ ->
                                         {0, 0}
                                 end,
    %% 对手排名列表 排名前3和未上榜的情况特殊处理
    RandRankL = if
                    Rank =:= 1 -> [5, 4, 3, 2];
                    Rank =:= 2 -> [5, 4, 3, 1];
                    Rank =:= 3 -> [5, 4, 2, 1];
                    Rank =:= 4 -> [5, 3, 2, 1];
    %% Rank =:= 5 -> [6, 4, 3, 2, 1];
                    Rank > MaxRank -> %% 名次超出3000，说明是打完了第一次的特殊情况，超出3000直接按3000给推荐
                        [
                            urand:rand(MaxRank - util:ceil(MaxRange*0.2), MaxRank)
                            %,urand:rand(MaxRank - util:ceil(MaxRange*0.4), MaxRank - util:ceil(0.2*(MaxRange+MinRange)))
                            ,urand:rand(MaxRank - util:ceil(MaxRange*0.6), MaxRank - util:ceil(0.4*(MaxRange+MinRange)))
                            ,urand:rand(MaxRank - util:ceil(MaxRange*0.8), MaxRank - util:ceil(0.5*(MaxRange+MinRange)))
                            ,urand:rand(MaxRank - MaxRange, MaxRank - util:ceil(0.7*(MaxRange+MinRange)))
                        ];
                    Rank =:= 0 -> %% 第一次打开,给一个不在榜单上的数据，保证全部是假人
                        Extra = 500,
                        Ave = Extra div 4,
                        [
                            urand:rand(MaxRank + 1, MaxRank + Ave)
                            ,urand:rand(MaxRank + Ave + 1, MaxRank + Ave * 2)
                            ,urand:rand(MaxRank + Ave * 2 + 1, MaxRank + Ave * 3)
                            ,urand:rand(MaxRank + Ave * 3 + 1, MaxRank + Extra)
                        ];
                    true -> %% 普遍情况
                        [
                            urand:rand(
                                ?IF(Rank + MinRange > MaxRank - MaxRange, Rank - MinRange + 1, Rank + MinRange)
                                ,?IF(Rank + MaxRange > MaxRank, Rank - 1, Rank + MaxRange)
                            )
                            %,urand:rand(Rank - MaxRange, Rank - MinRange)
                            ,urand:rand(Rank - 2*MaxRange, Rank - MaxRange - MinRange)
                            ,urand:rand(Rank - 3*MaxRange, Rank - 2*MaxRange - MinRange)
                            ,urand:rand(Rank - 4*MaxRange, Rank - 3*MaxRange - MinRange)
                        ]
                end,
    LastList = lists:reverse(
        [RandRank || RandRank <- RandRankL, RandRank > 0]
    ),
    LastList.

%% 根据Rank，获得排名区间
get_rank_id(Rank) ->
    IdList = data_arena:get_id_list(),
    do_get_rank_id(Rank, IdList).

do_get_rank_id(_Rank, []) -> 0;
do_get_rank_id(Rank, [H | T]) ->
    case data_arena:get_search_cfg(H) of
        #arena_search_cfg{max = Max, min = Min} -> ok;
        _ -> Max = Min = 0
    end,
    case Max >= Rank andalso Rank >= Min of
        true ->
            H;
        _ ->
            do_get_rank_id(Rank, T)
    end.

%% @doc 创建战场 一方战死或按跳过时再结算
create_battle(State, ChallengeRole, Code, IsQuick) ->
    #challenge_role{
        role_id      = RoleId,
        self_rank    = SelfRank,
        rival_rank   = RivalRank,
        self_power   = SelfCombat
    } = ChallengeRole,
    %% 这里检测的时候，如果对手排名大于3000，则算假人
    ChencList = [rival_rank, self_rank, self_battle_status, rival_battle_status],
    case check_challenge(State, ChallengeRole, ChencList) of
        {true, NewState} ->
            #figure{power = RivalCombat} = get_rival_figure(State, RivalRank),
            ChallengeRole2 = ChallengeRole#challenge_role{rival_power = RivalCombat},
            put({RoleId, challenge_image}, ChallengeRole2),
            
            %% 秒杀条件 old: 玩家有排名且玩家排位和战力比被挑战者高  new:(宠物生活技能) 战力比自己低的
            % case  IsQuick andalso SelfCombat > RivalCombat andalso SelfRank =/= 0 andalso Code == ?SUCCESS of
            case IsQuick andalso SelfCombat > RivalCombat andalso SelfRank =/= 0 andalso Code == ?SUCCESS of
                true -> %% 直接结算
                    LastState = NewState,
                    EndType = ?ARENA_BATTLE_END_TYPE_FORCE,
                    mod_arena:cast_to_arena(challenge_image_role, [RoleId, ?ARENA_WIN, EndType, 1]);
                false ->
                    case Code == ?SUCCESS of
                        true ->
                            %% 锁定两个排名位置
                            NewState2 = set_battle_status(NewState, [SelfRank, RivalRank], ?BATTLE_STATUS),
                            LastState =
                                try
                                    lib_arena:ready_create_fake_battle(ChallengeRole2)
                                of
                                    _Reply ->
                                        NewState2
                                catch Class:Reason ->
                                    Error = {Class, Reason, erlang:get_stacktrace()},
                                    ?ERR("~w: error:~p~n", [?MODULE, Error]),
                                    lib_server_send:send_to_uid(RoleId, pt_280, 28000, [?FAIL]),
                                    NewState
                                end;
                        _ ->
                            LastState = NewState,
                            lib_server_send:send_to_uid(RoleId, pt_280, 28000, [Code])
                    end
            end;
        {false, Errcode, NewState} ->
            LastState = NewState,
            lib_server_send:send_to_uid(RoleId, pt_280, 28000, [Errcode])
    end,
    LastState.

%% @doc 获取每日奖励
get_reward(State, RoleId) ->
    RealRole = get_real_role(State, RoleId),
    YesterdayRank = get_daily_reward_rank(RealRole),
    case get_rank_reward(State#arena_state.season, YesterdayRank) of
        Reward when Reward =/= [] ->
            lib_daily:increment_offline(RoleId, ?MOD_ARENA, ?ARENA_DAILY),
            %% 发奖励
            Produce = #produce{reward = Reward, type = arena_break_reward, show_tips = 1},
            lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_ARENA),
            %日志
            lib_log_api:log_arena_daily_reward(
                [RoleId, lib_role:get_role_name(RoleId), 0, YesterdayRank, util:term_to_bitstring(Reward), utime:unixtime()]
            ),
            lib_server_send:send_to_uid(RoleId, pt_280, 28008, [?SUCCESS, ?ARENA_AWARD_DAILY]);
        _ ->
            lib_server_send:send_to_uid(RoleId, pt_280, 28000, [?ERRCODE(err280_none_reward)])
    end,
    State.

%% @doc 获取大神奖励
get_sp_reward(State, RoleId) ->
    RealRole = get_real_role(State, RoleId),
    NeedRank = lib_arena_util:get_arena_cfg(?ARENA_SP_ROLE_NUM, 9),
    Reward = data_arena:get_arena_ap_award(RealRole#real_role.rank),
    if
        RealRole#real_role.rank > NeedRank  ->
            lib_server_send:send_to_uid(RoleId, pt_280, 28000, [?ERRCODE(err280_sp_award_only)]);
        Reward == [] ->
            lib_server_send:send_to_uid(RoleId, pt_280, 28000, [?ERRCODE(err280_none_reward)]);
        true ->
            lib_daily:increment_offline(RoleId, ?MOD_ARENA, ?ARENA_SP_AWARD),
            %% 发奖励
            lib_server_send:send_to_uid(RoleId, pt_280, 28008, [?SUCCESS, ?ARENA_AWARD_SP]),
            Produce = #produce{reward = Reward, type = arena_sp_reward, show_tips = 1},
            lib_goods_api:send_reward_with_mail(RoleId, Produce, ?MOD_ARENA)
    end,
    State.

%% 根据Rank，获得排名奖励
get_rank_reward(SeasonId, Rank) ->
    case data_arena:get_season_award(lib_arena_util:get_conf_season_id(SeasonId), Rank) of
        #arena_season_award{daily_award = Reward} ->
            Reward;
        _ ->
            []
    end.

%% @doc 榜单数据
get_rank_list(State, RoleId, PageNum, Num) ->
    RankStartId = max(0, PageNum - 1) * Num + 1,
    RankEndId = PageNum * Num,
    RankIdList = lists:seq(RankStartId, RankEndId),
    Fun = fun(RankNum, RankList) ->
        #figure{name = Name} = RoleFigure = get_rival_figure(State, RankNum),
        lists:append(RankList, [{RankNum, Name, RoleFigure}])
    end,
    RankList = lists:foldl(Fun, [], RankIdList),
    lib_server_send:send_to_uid(RoleId, pt_280, 28006, [PageNum, Num, RankList]),
    State.

%% @doc 战斗结算
challenge_image_role(State, RoleId, Result, _EndType, IsQuick) ->
    ChangeInfo = erase({RoleId, challenge_image}),
    if
        not is_record(ChangeInfo, challenge_role) -> ignore;
        true ->
            #challenge_role{
                role_id = RoleId,
                rival_id = RivalId,
                rival_rank = RivalRank,
                self_rank = SelfRank,
                self_name = SelfName
            } = ChangeInfo,
            #figure{name = RivalName} = RivalPicture = get_rival_figure_do(RivalId, RivalRank),
            %% 更新战斗状态，解锁两个位置,战斗进程销毁的时候会进行解锁
            %NewState = set_battle_status(State, [RivalRank, SelfRank], ?NOT_BATTLE_STATUS),
            OldRR = get_real_role(State, RoleId),
            #real_role{history_rank = HistoryRank} = OldRR,
            case Result of
                ?ARENA_WIN ->
                    %% 打赢了
                    %% 如果我之前没上榜，则替换双方排名
                    %% 如果对方排名比我靠前，则替换双方排名
                    %% 其他情况，保持不变
                    case SelfRank == 0 orelse SelfRank > RivalRank of
                        true  ->
                            LastRank = RivalRank,
                            LastRivalRank = SelfRank,
                            NewHistoryRank =
                                case HistoryRank > 0 of
                                    true  -> min(RivalRank, HistoryRank);
                                    false -> RivalRank
                                end,
                            Change = true;
                        false ->
                            LastRank = SelfRank,
                            LastRivalRank = RivalRank,
                            NewHistoryRank = HistoryRank,
                            Change = false
                    end;
                ?ARENA_FAIL ->
                    %% 打输了，保持不变
                    LastRank = SelfRank,
                    LastRivalRank = RivalRank,
                    NewHistoryRank = HistoryRank,
                    Change = false
            end,
            Now = utime:unixtime(),
            MaxRank = ?ARENA_MAX_RANK_TRULY,
            %% 更新昨日排名
            {RR1, IsFirst} = update_reward_rank(OldRR, Now),
            RR2 = RR1#real_role{role_id = RoleId, rank = LastRank, history_rank = NewHistoryRank},
            %% 更新挑战者数据
            State1 = put_real_role(State, RoleId, RR2, Change, IsFirst),
            %% 更新排名对应的玩家数据, 如果我是3000多名，也没必要保存
            State2 =
                case Change andalso LastRank =< MaxRank of
                    true  -> put_rank_role(State1, LastRank, RoleId);
                    false -> State1
                end,
            %% 更新对手数据
            StateRival =
                case RivalId =:= 0 of
                    true  ->
                        %% 对手是假人，如果我赢了，直接把我的旧排名数据删掉
                        case Change of
                            true  -> remove_rank_role(State2, SelfRank);
                            false -> State2
                        end;
                    false ->
                        RivalRR  = get_real_role(State2, RivalId),
                        %% 更新昨日排名
                        {RivalRR1, RivalIsFirst} = update_reward_rank(RivalRR, Now),
                        RivalRR2 = RivalRR1#real_role{rank = LastRivalRank},
                        %% 更新玩家数据
                        State3 = put_real_role(State2, RivalId, RivalRR2, Change, RivalIsFirst),
                        %% 更新排名对应的玩家数据
                        State4 =
                            case Change of
                                true  -> put_rank_role(State3, LastRivalRank, RivalId);
                                false -> State3
                            end,
                        State4
                end,
            %% 传闻
            SpNum = lib_arena_util:get_arena_cfg(?ARENA_SP_ROLE_NUM, 9),
            Change andalso
                if
                    LastRank =< SpNum andalso LastRank > 0 ->
                        lib_chat:send_TV({all}, ?MOD_ARENA, 2, [SelfName, RoleId, RivalName, RivalId, RivalRank]);
                    LastRank =< 50 andalso LastRank > 0 ->
                        lib_chat:send_TV({all}, ?MOD_ARENA, 1, [SelfName, RoleId, RivalName, RivalId, RivalRank]);
                    true ->
                        ignore
                end,
            %% 日志
            lib_log_api:log_arena(
                [RoleId, SelfName, SelfRank, RivalId, RivalName, RivalRank, Result, LastRank, Now]
            ),
            %% 对手排名变更，则邮件通知
            Change andalso RivalId > 0 andalso
                lib_mail_api:send_sys_mail(
                    [RivalId],
                    ?MOD_ARENA,
                    utext:get(?LAN_TITLE_ARENA_RANK_REPLACE),
                    utext:get(?LAN_CONTENT_ARENA_RANK_OUT, [SelfName, RoleId]),
                    []
                ),
            %% 最后回到挑战者进程，处理发奖等其他逻辑
            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, lib_arena, after_challenge,
                [Result, RR2, SelfRank, HistoryRank, RivalPicture, RivalRank, IsQuick, ChangeInfo#challenge_role.sp]),
            LastState = StateRival,
            LastState
    end.

%% 更新昨日排名
update_reward_rank(RR, Now) ->
    #real_role{rank_time = RankTime, rank = Rank} = RR,
    case RankTime > 0 andalso (not utime:is_logic_same_day(RankTime, Now)) of
        true  ->
            {RR#real_role{rank_time = Now, reward_rank = Rank}, true};
        false ->
            {RR#real_role{rank_time = Now}, false}
    end.

%% 取消战斗，
cancel_battle(State, RoleId) ->
    erase({RoleId, challenge_image}),
    State.

%% @doc 设置位置战斗状态
set_battle_status(State, RankList, ?NOT_BATTLE_STATUS) ->
    #arena_state{battle_status_maps = BStatusMaps} = State,
    F = fun(Rank, AccMap) ->
        maps:remove(Rank, AccMap)
        end,
    NewMaps = lists:foldl(F, BStatusMaps, RankList),
    State#arena_state{battle_status_maps = NewMaps};
%% 只有排名大于0小于3000的时候才加锁
set_battle_status(State, RankList, ?BATTLE_STATUS) ->
    NowTime = utime:unixtime(),
    MaxRank = ?ARENA_MAX_RANK_TRULY,
    #arena_state{battle_status_maps = BStatusMaps} = State,
    F = fun
            (Rank, AccMap) when Rank =< MaxRank andalso Rank > 0 ->
                maps:put(Rank, NowTime, AccMap);
            (_, AccMap) ->
                AccMap
        end,
    NewMaps = lists:foldl(F, BStatusMaps, RankList),
    State#arena_state{battle_status_maps = NewMaps}.

%% 清理冗余数据:清理3天没有变化的数据
clean_redundancy(State) ->
    CheckTime = utime:unixtime() - 86400 * 3,
    [
        case Key of
            {real_role, _} ->
                case erlang:get(Key) of
                    #real_role{rank_time = RankTime} when RankTime < CheckTime ->
                        erlang:erase(Key),
                        ok;
                    _ ->
                        ignore
                end;
            _ ->
                ignore
        end
        || Key <- erlang:get_keys()
    ],
    State.
%%%------------------------------------
%%% internal function
%%%------------------------------------
%% 获得对手个人信息
get_rival_figure(State, Rank)->
    MaxRank = ?ARENA_MAX_RANK_TRULY,
    case Rank > MaxRank of
        true  ->
            get_rival_figure_do(0, Rank);
        false ->
            RoleId = maps:get(Rank, State#arena_state.rank_maps, 0),
            get_rival_figure_do(RoleId, Rank)
    end.

get_rival_figure_do(0, Rank) ->
    lib_arena_util:make_fake_man_figure(Rank);
get_rival_figure_do(RoleId, _Rank) ->
    lib_role:get_role_figure(RoleId).

%% 获取maps里排名信息 没有的话返回0
%% @return    role_id
get_rank_role(_State = #arena_state{rank_maps = RankMaps}, Rank) ->
    MaxRank = ?ARENA_MAX_RANK_TRULY,
    case Rank > MaxRank of
        true  ->
            0;
        false ->
            get_rank_role(RankMaps, Rank)
    end;
get_rank_role(RankMaps, Rank) ->
    maps:get(Rank, RankMaps, 0).

%% 从进程字典获得真实玩家数据
get_real_role(_State, RoleId) ->
    case erlang:get({real_role, RoleId}) of
        RR when is_record(RR, real_role) ->
            RR;
        _ ->
            RR = get_db_real_role(RoleId),
            put({real_role, RoleId}, RR),
            RR
    end.

%% 保存真实玩家数据,如果是同一天战斗，排名又没发生变化，那就不用写数据库
put_real_role(State, RoleId, RealRole, Change, IsFirst) ->
    NewRealRole = RealRole#real_role{role_id = RoleId},
    case IsFirst of
        true  ->
            %% 当天第一次战斗，保存一次
            replace_db_real_role(NewRealRole);
        false ->
            %% 其余时候，有变化才保存
            Change andalso
                replace_db_real_role(NewRealRole)
    end,
    put({real_role, RoleId}, NewRealRole),
    State.

%% 保存排名数据
put_rank_role(State, Rank, RoleId) ->
    #arena_state{rank_maps = RM} = State,
    NewRM = maps:put(Rank, RoleId, RM),
    State#arena_state{rank_maps = NewRM}.

%% 清除排名数据
remove_rank_role(State, Rank) ->
    #arena_state{rank_maps = RM} = State,
    NewRM = maps:remove(Rank, RM),
    State#arena_state{rank_maps = NewRM}.

%% 如果没打过，直接用默认值
get_daily_reward_rank(#real_role{rank = 0, reward_rank = RewardRank, rank_time = 0}) ->
    RewardRank;
get_daily_reward_rank(RealRole) ->
    #real_role{rank = Rank, reward_rank = RewardRank, rank_time = RankTime} = RealRole,
    case utime:is_today(RankTime) of
        true  -> RewardRank;
        false -> Rank
    end.
%%------------check--------------
%% check 挑战资格
check_challenge(State, _ChallengeRole, []) -> {true, State};
check_challenge(State, ChallengeRole, [H | T]) ->
    case do_check_challenge(State, ChallengeRole, H) of
        {true, NewState} ->
            check_challenge(NewState, ChallengeRole, T);
        {false, Errcode, NewState} ->
            {false, Errcode, NewState}
    end.

%% 对手排名是否改变
do_check_challenge(State, ChallengeRole, rival_rank) ->
    #challenge_role{rival_id = RivalId, rival_rank = RivalRank} = ChallengeRole,
    RankRole = get_rank_role(State, RivalRank),
    case RankRole =:= RivalId of
        true ->
            {true, State};
        false ->
            if
                RankRole == 0 andalso RivalId == 0 -> {true, State};
                true -> {false, ?ERRCODE(err280_rival_rank_change), State}
            end
    end;
%% 自己排名是否改变
do_check_challenge(State, ChallengeRole, self_rank) ->
    #challenge_role{role_id = RoleId, self_rank = SelfRank} = ChallengeRole,
    RR = get_real_role(State, RoleId),
    case RR of
        #real_role{role_id = RoleId, rank = SelfRank} ->
            {true, State};
        _ ->
            if
                RR#real_role.rank == 0 andalso SelfRank == 0 -> {true, State};
                true -> {false, ?ERRCODE(err280_self_rank_change), State}
            end
    end;
%% 对手是否在战斗中
do_check_challenge(State, ChallengeRole, rival_battle_status) ->
    NowTime = utime:unixtime(),
    #arena_state{battle_status_maps = BStatusMaps} = State,
    #challenge_role{rival_rank = RivalRank} = ChallengeRole,
    Time = maps:get(RivalRank, BStatusMaps, 0),
    case NowTime - Time =< ?BATTLE_STATUS_UNLOCK of
        true  ->
            {false, ?ERRCODE(err280_on_battle_state), State};
        false ->
            {true, State}
    end;
%% 自己是否在战斗中
do_check_challenge(State, ChallengeRole, self_battle_status) ->
    NowTime = utime:unixtime(),
    #arena_state{battle_status_maps = BStatusMaps} = State,
    #challenge_role{self_rank = SelfRank} = ChallengeRole,
    Time = maps:get(SelfRank, BStatusMaps, 0),
    case SelfRank =/= 0 andalso NowTime - Time =< ?BATTLE_STATUS_UNLOCK of
        true  ->
            {false, ?ERRCODE(err280_role_on_battle_state), State};
        false ->
            {true, State}
    end;
%% 容错
do_check_challenge(State, _ChallengeRole, _Msg) ->
    {false, ?FAIL, State}.

%% GM命令：释放战斗状态
gm_release_battle_status(State, RankId) ->
    #arena_state{battle_status_maps = BStatusMaps} = State,
    NewBStatusMaps = maps:remove(RankId, BStatusMaps),
    LastState = State#arena_state{battle_status_maps = NewBStatusMaps},
    LastState.

%% --------------------db------------------------
get_db_real_role(RoleId) ->
    case db:get_row(io_lib:format(?sql_select_real_role_by_id, [RoleId])) of
        [Rank, HistoryRank, RewardRank, RankTime] ->
            #real_role{
                role_id      = RoleId,
                rank         = Rank,                %% 排名
                history_rank = HistoryRank,         %% 历史排名
                reward_rank  = RewardRank,
                rank_time    = RankTime
            };
        _ -> #real_role{role_id = RoleId}
    end.

% ---replace---
replace_db_real_role(RealRole) ->
    #real_role{
        role_id      = RoleId,
        rank         = Rank,                   %% 排名
        history_rank = HistoryRank,
        rank_time    = RankTime,
        reward_rank  = RewardRank
    } = RealRole,
    Sql = io_lib:format(?sql_replace_db_real_role, [RoleId, Rank, HistoryRank, RewardRank, RankTime]),
    db:execute(Sql).
