%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     狂战领域管理：玩法分为两轮
%%% 第一轮，所有服务器在本服进入活动场景(自动分线)混战，打BOSS/杀人都可以获得积分，个人做一个排名。BOSS为不死怪，活动结束时杀死BOSS结算
%%% 判断：如果跨服已开，则第二轮会进入跨服玩法，跨服未开，则第二轮进入本服玩法
%%% 第二轮，活动形式跟第一轮一致，只是跨服模式排名数据以服务器为单位
%%% 定时加容错
%%% @end
%%%-------------------------------------------------------------------
-module(madness_land).
-author("liushl").

-behaviour(gen_server).

-include("madness_land.hrl").
-include("common.hrl").
-include("def_fun.hrl").
-include("errcode.hrl").
-include("figure.hrl").
-include("def_act_label.hrl").
-include("def_module.hrl").
-include("activitycalen.hrl").
%% API
-export([start_link/0]).

%% gen_server callbacks
-export([init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3]).

-export([
    is_during_madness_land/0,       %% 是否狂战领域期间
    act_start/3,                    %% 活动日历通知活动开启
    ask_madness_land_info/1,        %% 查看活动信息
    ask_role_rank/3,                %% 查看单人榜单
    ask_guild_rank/3,               %% 查看公会榜单
    ask_role_score/3,               %% 查看个人积分信息
    update_role_info/3,             %% 更新玩家信息
    
    apply_info/1,
    common_cast_local/1,            %% 本服通用消息处理
    common_cast_to_center/1,        %% 通用跨服消息处理
    common_cast_center/2,
    apply_cast/1
]).

-export([
    gm_begin/0,
    gm_stage/0,
    gm_center/1,
    gm_local/1
]).
-define(SERVER, ?MODULE).

%%%===================================================================
%%% API
%%%===================================================================
%% 是否狂战领域期间
is_during_madness_land() ->
    gen_server:call(?MODULE, is_during_madness_land).

%% 活动日历通知活动开启: 活动结束由活动内控制
act_start(Module, ModuleSub, AcSub) ->
    apply_info({act_begin, Module, ModuleSub, AcSub}).

%% 查看活动信息
ask_madness_land_info(Sid) ->
    apply_info({ask_madness_land_info, Sid}).

%% 查看单人榜单
ask_role_rank(RoleId, Sid, 1) ->
    apply_info({ask_role_rank, RoleId, Sid});
ask_role_rank(RoleId, Sid, 2) ->
    ZoneId = czone_api:env_get_zone_id(),
    clusters_node:apply_cast(?MODULE, apply_info, [{ask_zone_role_rank, ZoneId, RoleId, Sid}]).

%% 查看社团榜单
ask_guild_rank(1, Guild, Sid) ->
    apply_info({ask_guild_rank, 0, Guild, Sid, 1});
ask_guild_rank(2, Guild, Sid) ->
    ZoneId = czone_api:env_get_zone_id(),
    clusters_node:apply_cast(?MODULE, apply_info, [{ask_guild_rank, ZoneId, Guild, Sid, 2}]).

%% 查看个人积分信息
ask_role_score(RoleId, Sid, Scene) ->
    case lib_scene:is_clusters_scene(Scene) of
        true ->
            ZoneId = czone_api:env_get_zone_id(),
            clusters_node:apply_cast(?MODULE, apply_info, [{ask_role_score, ZoneId, RoleId, Sid}]);
        false ->
            apply_info({ask_role_score, 0, RoleId, Sid})
    end.

%% 更新玩家信息
update_role_info(RoleId, Key, Value) ->
    ?MODULE !  {update_role_info, RoleId, Key, Value}.

apply_info(Msg) ->
    ?MODULE ! Msg.

%% GM 先通知跨服中心，由跨服中心再通知各个游戏服
gm_begin() ->
    clusters_node:apply_cast(?MODULE, gm_center, [act_begin]).

gm_stage() ->
    clusters_node:apply_cast(?MODULE, gm_center, [stage_switch]).

gm_center(Msg) ->
    case Msg =:= act_begin of
        true  ->
            apply_info({act_begin, ?MOD_MADNESS_LAND, 0, 2});
        false ->
            apply_info(Msg)
    end,
    clusters_center:apply_to_all_node(?MODULE, gm_local, [Msg]).
gm_local(Msg) ->
    case Msg =:= act_begin of
        true  ->
            apply_info({act_begin, ?MOD_MADNESS_LAND, 0, 2}),
            lib_activitycalen_api:success_start_activity(?MOD_MADNESS_LAND, 0, 2);
        false ->
            apply_info(Msg)
    end.
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @end
%%--------------------------------------------------------------------
-spec(start_link() ->
    {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%%===================================================================
%%% common callbacks
%%%===================================================================
%% 本服通用消息处理
common_cast_local(Msg) ->
    apply_cast({local_msg, Msg}).

%% 通用跨服消息处理
common_cast_to_center(Msg) ->
    ZoneId = czone_api:env_get_zone_id(),
    clusters_node:apply_cast(?MODULE, apply_cast, [{center_msg, ZoneId, Msg}]).

common_cast_center(ZoneId, Msg) ->
    apply_cast({center_msg, ZoneId, Msg}).

apply_cast(Msg) ->
    gen_server:cast(?MODULE, Msg).

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%%                     {ok, State, Timeout} |
%%                     ignore |
%%                     {stop, Reason}
%% @end
%%--------------------------------------------------------------------
-spec(init(Args :: term()) ->
    {ok, State :: #madness_land{}} | {ok, State :: #madness_land{}, timeout() | hibernate} |
    {stop, Reason :: term()} | ignore).
init([]) ->
    IsCenter = clusters_api:is_center(),
    State =
        case IsCenter of
            true  ->
                #madness_land{
                    cls_type = ?NODE_CENTER,
                    guild_rank = load_zone_guild_rank(),
                    role_rank = load_zone_role_rank()
                };
            false ->
                #madness_land{
                    cls_type = ?NODE_GAME,
                    role_rank = load_local_role_rank(),
                    guild_rank = load_local_guild_rank()
                }
        end,
    {ok, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
    State :: #madness_land{}) ->
    {reply, Reply :: term(), NewState :: #madness_land{}} |
    {reply, Reply :: term(), NewState :: #madness_land{}, timeout() | hibernate} |
    {noreply, NewState :: #madness_land{}} |
    {noreply, NewState :: #madness_land{}, timeout() | hibernate} |
    {stop, Reason :: term(), Reply :: term(), NewState :: #madness_land{}} |
    {stop, Reason :: term(), NewState :: #madness_land{}}).
handle_call(Msg, From, State) ->
    try
        do_handle_call(Msg, From, State)
    catch _:_Error ->
        io:format("do_handle_call Msg:~p, Error:~p, ~p~n", [Msg, _Error, erlang:get_stacktrace()]),
        {reply, error, State}
    end.
do_handle_call(is_during_madness_land, _From, State) ->
    Res = State#madness_land.stage > 0,
    {reply, Res, State};
do_handle_call(_Request, _From, State) ->
    io:format("time:[~p], module:~p: do_handle_call unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Request]),
    {reply, ok, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_cast(Request :: term(), State :: #madness_land{}) ->
    {noreply, NewState :: #madness_land{}} |
    {noreply, NewState :: #madness_land{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #madness_land{}}).
handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch _:_Error ->
        io:format("handle_cast Msg:~p, Error:~p, ~p~n", [Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.
%% 本服数据通用处理
do_handle_cast({local_msg, Msg}, State) when State#madness_land.stage > 0 ->
    #madness_land{
        local_data = LocalData
    } = State,
    {State1, NewLocalData}
                = madness_land_act:handle(Msg, State, LocalData),
    NewState    = State1#madness_land{local_data = NewLocalData},
    {noreply, NewState};
%% 跨服数据通用处理
do_handle_cast({center_msg, ZoneId, Msg}, State) when State#madness_land.stage > 0  ->
    #madness_land{
        zone_data = ZoneData
    } = State,
    ZoneInfo    = maps:get(ZoneId, ZoneData, #madness_land_act{zone_id = ZoneId}),
    {State1, NewZoneInfo}
                = madness_land_act:handle(Msg, State, ZoneInfo),
    NewState    = State1#madness_land{zone_data = maps:put(ZoneId, NewZoneInfo, ZoneData)},
    {noreply, NewState};
do_handle_cast(_Request, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
-spec(handle_info(Info :: timeout() | term(), State :: #madness_land{}) ->
    {noreply, NewState :: #madness_land{}} |
    {noreply, NewState :: #madness_land{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #madness_land{}}).
handle_info(Msg, State) ->
    try
        do_handle_info(Msg, State)
    catch _:_Error ->
        io:format("[~p]~nhandle_info Msg:~p~n Error:~p~n ~p~n", [erlang:localtime(), Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

%% 活动流程-活动开启
do_handle_info({act_begin, _, _, _}, #madness_land{stage = Stage} = State)
    when Stage > 0 ->
    %% 已经开启了，就忽略
    {noreply, State};
do_handle_info({act_begin, Module, ModuleSub, AcSub}, State) ->
    case data_activitycalen:get_ac(Module, ModuleSub, AcSub) of
        #base_ac{node_type = 0} ->
            Round2Type = ?NODE_GAME;
        #base_ac{node_type = 1} ->
            Round2Type = ?NODE_CENTER;
        #base_ac{node_type = 2} ->
            Round2Type = ?NODE_CENTER;
        _ ->
            Round2Type = ?NODE_GAME
    end,
    NewState = madness_land_stage:stage_begin(State),
    {noreply, NewState#madness_land{round_2_type = Round2Type}};

%% 阶段切换
do_handle_info(stage_switch, State) ->
    NewState = madness_land_stage:stage_switch(State),
    {noreply, NewState};

%% 定时刷新排行榜：本服
do_handle_info(refresh_rank, #madness_land{cls_type = ?NODE_GAME} = State) ->
    {State1, _, _}
        = madness_land_act:refresh_rank(State, State#madness_land.local_data),
    NewState
        = State1#madness_land{
        ref_refresh_rank = madness_land_stage:set_timer_refresh_rank()
    },
    {noreply, NewState};

%% 定时刷新排行榜: 跨服
do_handle_info(refresh_rank, #madness_land{cls_type = ?NODE_CENTER} = State) ->
    State1 = maps:fold(
        fun(_Key, Value, Temp) ->
            {State1, _, _} = madness_land_act:refresh_rank(Temp, Value),
            State1
        end, State, State#madness_land.zone_data
    ),
    NewState    = State1#madness_land{
        ref_refresh_rank = madness_land_stage:set_timer_refresh_rank()},
    {noreply, NewState};

%% 循环加分
do_handle_info({cycle_add_score, AddStage}, State) ->
    #madness_land{
        cls_type = ClsType,
        round = Round,
        stage = Stage
    } = State,
    case Round > 0 andalso AddStage =:= Stage of
        true  ->
            madness_land_act:cycle_add_score(Round, ClsType),
            NewState = State#madness_land{
                ref_cycle_add_score = madness_land_stage:set_timer_cycle_add_score(Stage)
            },
            {noreply, NewState};
        false ->
            {noreply, State}
    end;

%% 小怪出生
do_handle_info(mon_born, State) when State#madness_land.round > 0->
    State1 = madness_land_act:born_mon(State),
    NewState = State1#madness_land{ref_mon_born = undefined},
    {noreply, NewState};

%% 活动开始后，每30秒检查一遍，如果没人攻击BOSS，则主动触发

%% 关闭活动
do_handle_info(close_act, State) ->
    case State#madness_land.cls_type of
        ?NODE_GAME ->
            %% 关闭第一个活动场景
            [
                begin
                    mod_scene_agent:close_scene(?MADNESS_LAND_SCENE_ROUND_1, PoolIdRound1)
                end
                || PoolIdRound1 <- scene_mgr:get_scene_pool_ids(?MADNESS_LAND_SCENE_ROUND_1)
            ],
            %% 结束托管
            offline_hosting_madness_land:end_hosting(),
            SceneId = ?MADNESS_LAND_SCENE_ROUND_2_NODE;
        ?NODE_CENTER ->
            SceneId = ?MADNESS_LAND_SCENE_ROUND_2_CENTER
    end,
    %% 关闭第二个活动场景
    [
        mod_scene_agent:close_scene(SceneId, PoolId)
        || PoolId <- scene_mgr:get_scene_pool_ids(SceneId)
    ],
    {noreply, State};

%% 清理成绩 clean_data
do_handle_info(clean_data, #madness_land{round = 0} = State) ->
    NewState = #madness_land{
        role_rank           = State#madness_land.role_rank,
        guild_rank          = State#madness_land.guild_rank
    },
    {noreply, NewState};
%% 请求进入
do_handle_info({ask_enter, RoleId, Force}, State) ->
    #madness_land{
        stage = Stage,
        round_2_type = SecondType,
        round = Round
    } = State,
    if
        Stage == 0 ->
            {ok, Bin} = pt_415:write(41501, [?ERRCODE(err415_not_open)]),
            lib_server_send:send_to_uid(RoleId, Bin);
        true ->
            SceneId = ?MADNESS_LAND_SCENE(Round, SecondType),
            madness_land_api:is_ok_enter(RoleId, SceneId, [{action_lock, ?ERRCODE(err415_in_madness_land)}], Force)
    end,
    {noreply, State};

%% 请求本服个人排行榜
do_handle_info({ask_role_rank, RoleId, Sid}, State) ->
    #madness_land{
        local_data = ActData,
        role_rank = RoleRank
    } = State,
    RankInfo = maps:get(0, RoleRank, []),
    SendRanks =
        [
            begin
                Picture =  lib_player:get_role_picture(Id),
                {0, Score, Rank, Picture}
            end
            ||#madness_land_role{role_id = Id, score = Score, rank = Rank} <- RankInfo
        ],
    MyScore = get_role_score(RankInfo, ActData, RoleId),
    Info = [SendRanks, MyScore, 1],
    {ok, Bin} = pt_415:write(41506, Info),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% 请求分区个人排行榜：只有跨服才有服务器排行榜
do_handle_info({ask_zone_role_rank, ZoneId, RoleId, Sid}, State) ->
    #madness_land{
        zone_data = ZoneData,
        role_rank = RoleRank
    } = State,
    RankInfo = maps:get(ZoneId, RoleRank, []),
    ActData  = maps:get(ZoneId, ZoneData, #madness_land_act{zone_id = ZoneId}),
    SendRanks =
        [
            {ServerNum, Score, Rank, Picture}
            || #madness_land_role{picture = Picture, score = Score, server_num = ServerNum, rank = Rank} <- RankInfo
        ],
    MyScore = get_role_score(RankInfo, ActData, RoleId),
    {ok, Bin} = pt_415:write(41506, [SendRanks, MyScore, 2]),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};
%% 请求公会排行榜
do_handle_info({ask_guild_rank, ZoneId, GuildId, Sid, Type}, State) ->
    #madness_land{
        cls_type = ClsType,
        guild_rank = RankLog,
        zone_data = ZoneData,
        local_data = LocalData
    } = State,
    GuildInfo = maps:get(ZoneId, RankLog, []),
    SendRanks =
        [
            {ServerNum, GuildName, Score, Rank, GuildFlag}
            || #madness_land_guild{
                    server_num       = ServerNum
                    , guild_name     = GuildName
                    , score          = Score
                    , rank           = Rank
                    , guild_flag     = GuildFlag
                } <- GuildInfo
        ],
    %% 同样社团积分也先从榜单里拿，无数据再从总成绩里找
    MyGuidScore =
    case lists:keyfind(GuildId, #madness_land_guild.guild_id, GuildInfo) of
        #madness_land_guild{score = MyScore} ->
            MyScore;
        _ ->
            FindMyScore =
                case ClsType =:= ?NODE_GAME of
                    true  ->
                        case LocalData of
                            #madness_land_act{guild_grade = GuildGrade} ->
                                GuildGrade;
                            _ ->
                                []
                        end;
                    false ->
                        ActData = maps:get(ZoneId, ZoneData, #madness_land_act{zone_id = ZoneId}),
                        ActData#madness_land_act.guild_grade
                end,
            case lists:keyfind(GuildId, #madness_land_guild.guild_id, FindMyScore) of
                #madness_land_guild{score = MyScore} ->
                    MyScore;
                _ ->
                    0
            end
    end,
    {ok, Bin} = pt_415:write(41507, [SendRanks, MyGuidScore, Type]),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% 前端请求玩家榜单积分
do_handle_info({ask_role_score, ZoneId, RoleId, Sid}, State) ->
    #madness_land{
        cls_type = ClsType,
        local_data = LocalData,
        zone_data = ZoneData,
        role_rank = RoleRank
    } = State,
    RankInfo = maps:get(ZoneId, RoleRank, []),
    ActData  = case ClsType =:= ?NODE_GAME of
        true  ->
            LocalData;
        false ->
            maps:get(ZoneId, ZoneData, #madness_land_act{zone_id = ZoneId})
    end,
    MyScore = get_role_score(RankInfo, ActData, RoleId),
    {ok, Bin} = pt_415:write(41512, [MyScore]),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% 查看活动数据
do_handle_info({ask_madness_land_info, Sid}, State) ->
    #madness_land{
        stage               = Stage
        , end_time          = EndTime
    } = State,
    {ok, Bin} = pt_415:write(41500, [Stage, EndTime]),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% 第二轮结算的时候读取第一轮的成绩
do_handle_info({settlement_round2_in_server, Info}, State) ->
    madness_land_act:settlement_round2_in_server(State, Info),
    {noreply, State};

%% 更新玩家数据
do_handle_info({update_role_info, RoleId, Key, Value}, State) ->
    case State#madness_land.local_data of
        #madness_land_act{} = ActData ->
            case Key of
                guild ->
                    NewActData = update_act_role_info(ActData, RoleId, Key, Value),
                    {noreply, State#madness_land{local_data = NewActData}};
                _ ->
                    {noreply, State}
            end;
        _ ->
            case State#madness_land.round =:= 2 of
                true  ->
                    ZoneId = czone_api:env_get_zone_id(),
                    clusters_node:apply_cast(?MODULE, apply_info, [{update_zone_role_info, ZoneId, RoleId, Key, Value}]);
                false ->
                    ok
            end,
            {noreply, State}
    end;

%% 跨服更新玩家数据
do_handle_info({update_zone_role_info, ZoneId, RoleId, Key, Value}, State) ->
    #madness_land{zone_data = ZoneData} = State,
    case maps:find(ZoneId, ZoneData) of
        {ok, ActData} ->
            NewActData  = update_act_role_info(ActData, RoleId, Key, Value),
            NewZoneData = maps:put(ZoneId, NewActData, ZoneData),
            {noreply, State#madness_land{zone_data = NewZoneData}};
        _ ->
            {noreply, State}
    end;

do_handle_info(_Info, State) ->
    io:format("time:[~p], module:~p: handle_info unexpect message:~p~n", [erlang:localtime(), ?MODULE, _Info]),
    {noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
    State :: #madness_land{}) ->
    term()).
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
-spec(code_change(OldVsn :: term() | {down, term()}, State :: #madness_land{},
    Extra :: term()) ->
    {ok, NewState :: #madness_land{}} | {error, Reason :: term()}).
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%%===================================================================
%%% Internal functions
%%%===================================================================
load_zone_role_rank() ->
    SQL = <<"SELECT zone_id,rank,role_id,name,sex,vip,sup_vip,server_num,score,photo,photo_dress,career,turn FROM madness_land_zone_role_rank">>,
    All = db:get_all(SQL),
    lists:foldl(
        fun([ZoneId, Rank, RoleId, Name, Sex, Vip, SupVip, ServerNum, Score, Photo, PhotoDress, Career, Turn], Temp) ->
            ZoneData = maps:get(ZoneId, Temp, []),
            NewZoneData =
                [
                    #madness_land_role{
                        role_id         = RoleId
                        , server_num    = ServerNum
                        , score         = Score
                        , picture       = #rec_picture{name = Name, sex = Sex, vip = Vip, career = Career, turn = Turn,
                            sup_vip = SupVip, profile_photo_id = Photo, picture_frame = PhotoDress}
                        , rank          = Rank
                    }|ZoneData
                ],
            maps:put(ZoneId, NewZoneData, Temp)
        end, #{}, All
    ).
load_zone_guild_rank() ->
    SQL = <<"SELECT zone_id,rank,server_num,guild_name,score,guild_flag FROM madness_land_zone_guild_rank">>,
    All = db:get_all(SQL),
    lists:foldl(
        fun([ZoneId, Rank, ServerNum, GuildName, Score, GuildFlag], Temp) ->
            ZoneData = maps:get(ZoneId, Temp, []),
            NewZoneData =
                [
                    #madness_land_guild{
                        server_num       = ServerNum
                        , guild_name     = GuildName
                        , score          = Score
                        , rank           = Rank
                        , guild_flag     = GuildFlag
                    }|ZoneData
                ],
            maps:put(ZoneId, NewZoneData, Temp)
        end, #{}, All
    ).
load_local_role_rank() ->
    SQL = <<"SELECT rank,role_id,score FROM madness_land_role_rank">>,
    All = db:get_all(SQL),
    Data =
    [
        #madness_land_role{
            role_id = RoleId,
            rank = Rank,
            score = Score
        } || [Rank, RoleId, Score] <- All
    ],
    #{0 => Data}.
load_local_guild_rank() ->
    SQL = <<"SELECT rank,guild_name,guild_flag,score FROM madness_land_guild_rank r">>,
    All = db:get_all(SQL),
    Data =
    [
        #madness_land_guild{
            guild_name = GuildName,
            guild_flag = GuildFlag,
            rank = Rank,
            score = Score
        } || [Rank, GuildName, GuildFlag, Score] <- All
    ],
    #{0 => Data}.

%% 拿到个人积分数据，优先从榜单里拿，保证玩家数据和榜单数据一致
%% 如果榜单里没数据，那就从总的成绩单里拿，都没上榜，就不存在一致性问题
get_role_score(RankInfo, ActData, RoleId) ->
    case lists:keyfind(RoleId, #madness_land_role.role_id, RankInfo) of
        #madness_land_role{score = MyScore} ->
            MyScore;
        _ ->
            case ActData of
                #madness_land_act{role_grade = RoleGrade}  ->
                    case dict:find(RoleId, RoleGrade) of
                        {ok, #madness_land_role{score = MyScore}} -> MyScore;
                        _ -> 0
                    end;
                _ ->
                    0
            end
    end.

update_act_role_info(ActData, RoleId, Key, Value) ->
    case dict:find(RoleId, ActData#madness_land_act.role_grade) of
        {ok, #madness_land_role{picture = Picture} = Role} ->
            NewOne =
                case Key of
                    name ->
                        Role#madness_land_role{picture = Picture#rec_picture{name = Value}};
                    vip  ->
                        Role#madness_land_role{picture = Picture#rec_picture{vip = Value}};
                    sup_vip  ->
                        Role#madness_land_role{picture = Picture#rec_picture{sup_vip = Value}};
                    photo ->
                        Role#madness_land_role{picture = Picture#rec_picture{profile_photo_id = Value}};
                    photo_dress ->
                        Role#madness_land_role{picture = Picture#rec_picture{picture_frame = Value}};
                    guild ->
                        {GuildId, GuildName} = Value,
                        Role#madness_land_role{guild_id = GuildId, guild_name = GuildName}
                end,
            NewRoleGrade = dict:store(RoleId, NewOne, ActData#madness_land_act.role_grade),
            ActData#madness_land_act{role_grade = NewRoleGrade};
        _ ->
            ActData
    end.