%% ---------------------------------------------------------------------------
%% @doc mod_dungeon_cast.erl

%% @author  hjh
%% @email  hejiahua@163.com
%% @since  2017-02-14
%% @deprecated 副本进程
%% ---------------------------------------------------------------------------
-module(mod_dungeon_cast).
-export([handle_cast/2]).

-include("dungeon.hrl").
-include("common.hrl").
-include("predefine.hrl").
-include("scene.hrl").
-include("drop.hrl").
-include("figure.hrl").
-include("errcode.hrl").
-include("def_module.hrl").
-include("team.hrl").
-include("def_fun.hrl").
-include("battle.hrl").
-include("dun_guard.hrl").
-include("god_dun.hrl").
-include("attr.hrl").

-spec handle_cast(Msg, State) -> 
    {noreply, State}
    | {stop, Reason, State} when
    Msg      :: term(),
    Reason   :: term(),
    State    :: #dungeon_state{}.
handle_cast(Msg, State) ->
    case catch do_handle_cast(Msg, State) of
        NewState = #dungeon_state{} ->
            {noreply, NewState};
        {noreply, NewState} ->
            {noreply, NewState};
        Result when Result == ok orelse Result == skip ->
            {noreply, State};
        {stop, _Reason, NewState} ->
            _Reason =/= normal andalso ?ERR("dun stop reason ~n ~p", [_Reason]),
            {stop, _Reason, NewState};
        Reason ->
            ?ERR("dun handle cast msg ~n ~p ~n error reason ~n ~p", [Msg, Reason]),
            {noreply, State}
    end.

%% 副本信息
do_handle_cast({'send_dungeon_info', RoleId, Node}, State) ->
    #dungeon_state{
        dun_id = DunId, dun_type = DunType, start_time = StartTime, end_time = EndTime, 
        scene_id = SceneId, wave_num = WaveNum, index_of_wave = WaveIndex, 
        wave_info = WaveInfos} = State,
    case data_dungeon_wave:get_dun_wave(DunId, WaveNum) of
        #base_dun_wave_cfg{limit_time = LimitTime} -> ok;
        _ -> LimitTime = 0
    end,
    WaveStartTime = 
    case lists:keyfind({WaveNum, WaveIndex}, #dun_wave_info.key, WaveInfos) of
        #dun_wave_info{typical_data = Data} ->
            if 
                DunType == ?DUNGEON_TYPE_GOD ->
                    StartTime0 = maps:get(start_time_ms, Data, 0),
                    StartTime0 div 1000;
                true ->
                    maps:get(start_time, Data, 0)
            end;
        _ ->
            0
    end,
    WaveEndTime = round(WaveStartTime + LimitTime),
    {ok, BinData} = pt_610:write(61004, [SceneId, DunId, StartTime, EndTime, WaveNum, WaveStartTime, WaveEndTime]),
    lib_server_send:send_to_uid(Node, RoleId, BinData),
    {noreply, State};

%% 副本评分信息
do_handle_cast({'get_dun_score_info', RoleId, Node}, State) ->
    #dungeon_state{dun_id = DunId, role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        Role = #dungeon_role{} ->
            dungeon_default:notice_score_event_update(DunId, Role);
        _ ->
            dungeon_logic:send_to_uid(Node, RoleId, pt_610, 61065, [DunId, []])
    end,
    {noreply, State};

%% 更新怪物伤害输出
do_handle_cast({'mon_be_hurt', AtterId, AttSign, _AtterName, Hurt}, State) ->
    #dungeon_state{is_end = IsEnd, dun_type = Type, role_list = RoleList, typical_data = TypicalData} = State,
    case IsEnd =/= ?DUN_IS_END_YES andalso lists:member(Type, ?DUNGEON_MON_HURT_TYPE) of
        true ->
            if AttSign == ?BATTLE_SIGN_PLAYER ->
                    case lists:keyfind(AtterId, #dungeon_role.id, RoleList) of
                        DungeonRole = #dungeon_role{typical_data = TypicalData1} ->
                            RoleMonHurt = maps:get(?DUN_ROLE_CRUSADE_DUN_MON_HURT, TypicalData1, 0),
                            NewTypicalData1 = maps:put(?DUN_ROLE_CRUSADE_DUN_MON_HURT, round(RoleMonHurt+Hurt), TypicalData1),
                            NewRoleList = lists:keystore(AtterId, #dungeon_role.id, RoleList, DungeonRole#dungeon_role{typical_data = NewTypicalData1}),
                            NewState = State#dungeon_state{role_list = NewRoleList},
                            dungeon_logic:notice_mon_hurt_rank(NewState),
                            NewState;
                        _ ->
                            NewState = State
                    end;
                AttSign == ?BATTLE_SIGN_DUMMY ->
                    DunDummys = maps:get(?DUN_STATE_SPECIAL_KEY_DUMMY, TypicalData, []),
                    case lists:keyfind(AtterId, #dungeon_dummy.id, DunDummys) of
                        DunDummy = #dungeon_dummy{hurt_calc = OldHurt} ->
                            NewDunDummys1 = lists:keydelete(AtterId, #dungeon_dummy.id, DunDummys),
                            NewDunDummys2 = lists:keystore(AtterId, #dungeon_dummy.id, NewDunDummys1, DunDummy#dungeon_dummy{hurt_calc = round(OldHurt+Hurt)}),
                            NewTypicalData = maps:put(?DUN_STATE_SPECIAL_KEY_DUMMY, NewDunDummys2, TypicalData),
                            NewState = State#dungeon_state{typical_data = NewTypicalData},
                            dungeon_logic:notice_mon_hurt_rank(NewState),
                            NewState;
                        _ ->
                            NewState = State
                    end;
                true ->
                    NewState = State
            end;
        _ ->
            NewState = State
    end,
    {noreply, NewState};

do_handle_cast({'role_be_hurted', RoleId, Hp, HpLim, _DunType}, State) ->
    NewState = lib_dungeon_distribute:role_be_hurted(State, RoleId, Hp, HpLim),
    NewState1  = dungeon_logic:role_hp_change_trigger(NewState, RoleId, Hp, HpLim),
    {noreply, NewState1};

%% 击杀怪物
do_handle_cast({'kill_mon', Args}, State) ->
    [_, _, _, CreateKey|_] = Args,
    if State#dungeon_state.is_end =/= ?DUN_IS_END_YES ->
            case CreateKey of
                {?DUN_WAVE_MON_KEY, ?DUN_GUARD_TOWER, _MonAutoId} ->
                    NewState = lib_dungeon_guard:handle_tower_killed(Args, State);
                {?DUN_WAVE_MON_KEY, _, _Wave, _WaveIndex} ->
                    NewState = dungeon_logic:handle_kill_mon(Args, State);
                _ ->
                    NewState = State
            end;
        true ->
            NewState = State
    end,
    %% 评级掉落检查
    #dungeon_state{result_type = ResultType} = NewState,
    if ResultType == ?DUN_RESULT_TYPE_SUCCESS ->
            NewState1 = dungeon_logic:calc_rating_drop(NewState);
        true ->
            NewState1 = NewState
    end,
    {noreply, NewState1};

do_handle_cast({'stop_mon', AutoId, Mid, DieSign, CreateKey, OwnId, _Hp, _HpLim}, State) ->
    if State#dungeon_state.is_end =/= ?DUN_IS_END_YES ->
            NewState = dungeon_logic:handle_kill_mon([AutoId, Mid, DieSign, CreateKey, OwnId, [{killer, 0}]], State);
        true ->
            NewState = State
    end,
    {noreply, NewState};

%% 对象(假人)死亡
do_handle_cast({'object_die', _AutoId, _OwnId, _ObjId}, State) ->
    #dungeon_state{dun_id = DunId, dun_type = DunType, typical_data = TypicalData} = State,
    DummyKilled = maps:get(?DUN_STATE_SPECIAL_KEY_DUMMY_KILLED, TypicalData, 0),
    NewTypicalData = maps:put(?DUN_STATE_SPECIAL_KEY_DUMMY_KILLED, DummyKilled+1, TypicalData),
    NewState  = State#dungeon_state{typical_data = NewTypicalData},
    NewState1 = dungeon_logic:check_role_die_trigger(DunId, DunType, ?BATTLE_SIGN_DUMMY, 0, 0, NewState),
    {noreply, NewState1};

%% 采集怪处理
do_handle_cast({'collect_mon_goods', RoleId, GoodsList}, State) ->
    #dungeon_state{role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        DungeonRole = #dungeon_role{drop_reward_list = DropRewardList} ->
            NewDropRewardList = lists:append(GoodsList, DropRewardList),
            NewDungeonRole = DungeonRole#dungeon_role{drop_reward_list = NewDropRewardList},
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, NewDungeonRole),
            NewState = State#dungeon_state{role_list = NewRoleList};
        _ ->
            NewState = State
    end,
    {noreply, NewState};

%% 主动退出
do_handle_cast({'active_quit', RoleId}, State) ->
    dungeon_logic:handle_active_quit(RoleId, State);

%% 重连
do_handle_cast({'reconnect', RoleId, Args, Xy}, State) ->
    dungeon_logic:reconnect_do(RoleId, Args, Xy, State);


%% 推送结算
do_handle_cast({'push_settlement', _RoleId}, State) ->
    %     DungeonRole -> lib_dungeon_mod:push_settlement(State, DungeonRole)
    {noreply, State};


%% 玩家死亡
do_handle_cast({'player_die', RoleId, HpLim, _DeadCount, AttrList}, State) ->
    {ok, NewState} = dungeon_logic:update_dungeon_role(State, RoleId, AttrList),
    #dungeon_state{dun_id = DunId, dun_type = DunType, role_list = RoleList} = NewState,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        DungeonRole = #dungeon_role{revive_ref = Ref, revive_count = ReviveCount, dead_count = OldDeadCount} ->
            case lists:member(DunType, ?DUN_AUTO_REVIVE) of
                true ->
                    if DunType == ?DUNGEON_TYPE_GUARD ->
                        NextTime = data_dun_guard:get_revive_cd(ReviveCount+1);
                        true ->
                            #dun_cfg{revive_time = ReviveTime} = data_dungeon:get_dun(DunId),
                            NextTime = ReviveTime
                    end,
                    NewRef = util:send_after(Ref, NextTime*1000, self(), {'revive_ref', RoleId});
                _ ->
                    util:cancel_timer(Ref), NewRef = undefined
            end,
            NewDeadCount = OldDeadCount + 1,
            NewDungeonRole = DungeonRole#dungeon_role{hp = 0, hp_lim = HpLim, revive_ref = NewRef, dead_count = NewDeadCount},
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, NewDungeonRole),
            NewState1 = NewState#dungeon_state{role_list = NewRoleList},
            NewState2 = dungeon_logic:check_role_die_trigger(DunId, DunType, ?BATTLE_SIGN_PLAYER, RoleId, NewDeadCount, NewState1),
            NewState3 = dungeon_logic:role_hp_change_trigger(NewState2, RoleId, 0, HpLim);
        _ ->
            NewState3 = NewState
    end,
    {noreply, NewState3};

%% 玩家复活
do_handle_cast({'player_revive', RoleId, _ReviveType, Args}, State) ->
    #dungeon_state{dun_type = DunType, role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        false -> NewState = State;
        #dungeon_role{revive_ref = OldRef} = DungeonRole ->
            util:cancel_timer(OldRef),
            NewDungeonRole0 = DungeonRole#dungeon_role{revive_ref = undefined},
            NewDungeonRole = dungeon_logic:do_update_dungeon_role(Args, NewDungeonRole0),
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, NewDungeonRole),
            DunType  == ?DUNGEON_TYPE_HELP andalso lib_dungeon_help:recovery_mon_hp(State),
            NewState = State#dungeon_state{role_list = NewRoleList}
    end,
    {noreply, NewState};

%% 登录
do_handle_cast({'login', _RoleId, _AttrList}, State) ->
    {noreply, State};

%% 副本中登出/闪退/掉线
do_handle_cast({'logout', RoleId, Hp, HpLim}, State) ->
    dungeon_logic:disconnect(RoleId, Hp, HpLim, State);

%% 
do_handle_cast({enter_next_dun, List}, State) ->
    dungeon_logic:enter_next_dun(List, State);

%% 直接副本结束(不结算)
do_handle_cast({'close_dungeon'}, State) ->
    {stop, normal, State};

%% 掉落拾取副本处理
do_handle_cast({'drop_choose', RoleId, #{goods := ObjectList, id := DropId} = Data}, State) ->
    % ?PRINT("drop_choose ~p~n", [[RoleId, Data]]),
    #dungeon_state{role_list = RoleList, dun_id = DunId} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        false -> {noreply, State};
        #dungeon_role{drop_reward_list = RewardList, drop_list = DropList,
            id = RoleId, figure = #figure{name = RoleName}, node = Node
        } = DungeonRole ->
            NewRewardList = lib_goods_api:make_reward_unique(ObjectList ++ RewardList),
            case maps:find(notice, Data) of
                {ok, [_|_] = Notice} ->
                    Rating = maps:get(rating, Data, 0),
                    ExtraAttr = maps:get(extra_attr, Data, []),
                    GoodsId = maps:get(goods_id, Data, 0),
                    %MonId = maps:get(mon_id, Data, 0),
                    if
                        %DunType =:= ?DUNGEON_TYPE_PER_BOSS ->
                        %    lib_player:apply_cast(RoleId, ?APPLY_CAST_SAVE, lib_achievement_api, boss_achv_finish, [?BOSS_TYPE_PERSONAL]),
                        %    mod_boss:boss_add_drop_log(RoleId, RoleName, SceneId, MonId, Notice, 0, [GoodsId, Rating, ExtraAttr]);
                        true ->
                            DunName = lib_dungeon_api:get_dungeon_name(DunId),
                            [unode:apply(Node, lib_chat, send_TV, [{all}, ModId, Id, [RoleName, RoleId, DunName, GoodsId, Rating, util:term_to_string(ExtraAttr)]]) || {ModId, Id} <- Notice, ?MOD_DUNGEON =:= ModId]
                    end;
                _ ->
                    skip
            end,
            NewDropList = lists:keydelete(DropId, #ets_drop.id, DropList),
            NewDungeonRole = DungeonRole#dungeon_role{drop_reward_list = NewRewardList, drop_list = NewDropList},
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, NewDungeonRole),
            NewState = State#dungeon_state{role_list = NewRoleList},
            {noreply, NewState}
    end;

%% 新增掉落
do_handle_cast({'goods_drop', RoleId, DropInfo}, State) ->
    #dungeon_state{role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        false -> {noreply, State};
        #dungeon_role{drop_list = DropList} = DungeonRole ->
            NewDropList = [DropInfo|DropList],
            NewDungeonRole = DungeonRole#dungeon_role{drop_list = NewDropList},
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, NewDungeonRole),
            NewState = State#dungeon_state{role_list = NewRoleList},
            {noreply, NewState}
    end;

do_handle_cast({update_role_lv, RoleId, Lv}, State) ->
    #dungeon_state{role_list = RoleList, dun_type = DunType} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        #dungeon_role{figure = Figure} = DungeonRole ->
            NewFigure = Figure#figure{lv = Lv},
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, DungeonRole#dungeon_role{figure = NewFigure}),
            EnterLv = lib_dungeon:calc_enter_lv(NewRoleList, DunType),
            {noreply, State#dungeon_state{role_list = NewRoleList, enter_lv = EnterLv}};
        _ ->
            {noreply, State}
    end;

do_handle_cast({'update_dungeon_role', RoleId, AttrList}, State) ->
    #dungeon_state{role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        #dungeon_role{} ->
            {_, NewState} = dungeon_logic:update_dungeon_role(State, RoleId, AttrList),
            {noreply, NewState};
        _ ->
            {noreply, State}
    end;

do_handle_cast({'get_mon_kill_info', RoleId, Node}, State) ->
    #dungeon_state{dun_id = DunId, typical_data = TypicalData} = State,
    MonInfoList = maps:get(?DUN_STATE_SPECIAL_KEY_MON_KILL_CALC, TypicalData, []),
    % ?ERR("~p", [MonInfoList]),
    {ok, BinData} = pt_610:write(61069, [DunId, MonInfoList]),
    lib_server_send:send_to_uid(Node, RoleId, BinData),
    {noreply, State};

do_handle_cast({'get_mon_hurt_info', Sid, Node}, State) ->
    #dungeon_state{is_end = IsEnd, dun_type = Type} = State,
    case IsEnd =/= ?DUN_IS_END_YES andalso lists:member(Type, ?DUNGEON_MON_HURT_TYPE) of
        true ->
            NewPackData = dungeon_logic:get_mon_hurt_info(State),
            {ok, BinData} = pt_610:write(61029, [NewPackData]),
            lib_server_send:send_to_sid(Node, Sid, BinData);
        _ ->
            skip
    end,
    {noreply, State};

do_handle_cast({'get_dun_rating_info', RoleId, Node}, State) ->
    #dungeon_state{dun_id = DunId, start_time = StartTime, role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        #dungeon_role{grade_rating = RatingList} ->
            Now = utime:unixtime(),
            LastTime = Now - StartTime,
            case lists:foldl(fun({Rating, _, ConfigLast, _Status}, Acc) -> 
                if LastTime < ConfigLast -> [Rating|Acc];
                    true -> Acc
                end
            end, [], RatingList) of
                NewRatingList = [_|_] ->
                    NewEndTime = dungeon_default:calc_next_time(Now, StartTime, lists:keysort(3, RatingList)),
                    MaxRating = lists:max(NewRatingList);
                _ ->
                    case RatingList of
                        [_|_] ->
                            case data_dungeon_grade:get_dun_grades(DunId) of
                                Ratings = [_|_] ->
                                    MaxRating = lists:min(Ratings),
                                    case data_dungeon:get_dun(DunId) of
                                        #dun_cfg{time = DunTime} ->
                                            NewEndTime = StartTime + DunTime;
                                        _ ->
                                            NewEndTime = 0
                                    end;
                                _ ->
                                    MaxRating = 0, NewEndTime = 0
                            end;
                        _ ->
                            MaxRating = 0, NewEndTime = 0
                    end
            end,
            dungeon_logic:send_to_uid(Node, RoleId, pt_610, 61070, [DunId, MaxRating, NewEndTime]);
        _ ->
            skip
    end,
    {noreply, State};

do_handle_cast({handle_enter_fail, RoleId, _Why}, State) ->
    #dungeon_state{role_list = RoleList} = State,
    NewRoleList = lists:keydelete(RoleId, #dungeon_role.id, RoleList),
    NewState = State#dungeon_state{role_list = NewRoleList},
    case dungeon_logic:nobody_in_dungeon(NewState) of
        true ->
            {stop, normal, NewState};
        _ ->
            {noreply, NewState}
    end;

do_handle_cast({alloc_drop, MonArgs, Alloc, _AtterId, Klist}, State) ->
    #dungeon_state{role_list = RoleList, dun_type = DunType} = State,
    #mon_args{mid = Mid, lv = MonLv} = MonArgs,
    DropRule = data_drop:get_rule(Mid, Alloc, MonLv),
    NeedDropHandle = lists:member(DunType, ?HANDLE_DROP_DUN_TYPE),
    if Alloc =/= ?ALLOC_EQUAL orelse DropRule == [] orelse (not NeedDropHandle) -> 
            skip;
        true ->
            [lib_player:apply_cast(Node, Id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, dungeon_logic, handle_dun_drop, [MonArgs, Alloc, 0, Klist])
             || #dungeon_role{node = Node, id = Id, online = Online} <- RoleList, Online =:= ?DUN_ONLINE_YES]
    end,
    {noreply, State};

do_handle_cast({get_role_attrs_by_self_rank, GodMonCfg, From, FigureType, [Mid, _SceneId, _ScenePool, _CopyId, _X, _Y]}, State) ->
    #dungeon_state{role_list = [#dungeon_role{id = RoleId, base_attr = BaseAttrs}|_]} = State,
    #base_god_dun_mon_cfg{attrs = AttrsCfg, info_from_rank = InfoRank} = GodMonCfg,
    ChangeAttrs = lists:foldl(fun({AttrId, ChangVal}, Acc) -> 
        case lists:keyfind(AttrId, 1, BaseAttrs) of
            {_, BaseVal} ->
                [{AttrId, round(BaseVal*ChangVal/100)}|Acc];
            _ ->
                Acc
        end
    end, [], AttrsCfg),
    gen_server:cast(god_dun_rank_local, {get_role_info_by_rank, [From, Mid, InfoRank]}),
    HpAttrs = 
    case lists:keyfind(?HP, 1, ChangeAttrs) of
        {_, Hp} when FigureType == 1 ->
            {ok, BinData} = pt_120:write(12009, [Mid, Hp, Hp]),
            lib_server_send:send_to_uid(RoleId, BinData),
            [];
        {_, Hp} ->
            {ok, BinData} = pt_120:write(12009, [Mid, Hp, Hp]),
            lib_server_send:send_to_uid(RoleId, BinData),
            [{hp_lim, Hp},{hp, Hp}];
        _ ->
            []
    end,
    % ?ERR("~p ~p", [ChangeAttrs, HpAttrs]),    
    mon_mgr:send(From, Mid, {'change_attr', HpAttrs ++ [{attr_list, ChangeAttrs}]}),
    {noreply, State};

do_handle_cast({get_god_dun_role_wave_score, Sid, _Wave}, State) ->
    #dungeon_state{role_list = [#dungeon_role{typical_data = Map}|_]} = State,
    ScoreL = maps:get(?DUN_ROLE_GOD_SCORE, Map, []),
    Val = lists:sum([ScoreX || {_, ScoreX} <- ScoreL]),
    lib_server_send:send_to_sid(Sid, pt_610, 61092, [Val]),
    {noreply, State};

do_handle_cast({fin_change_scene, RoleId}, State) ->
    #dungeon_state{
        init_wave_sign = InitWaveSign, is_end = IsEnd,
        wave_ref = [OldWaveStartRef, _OldWaveEndRef]
    } = State,
    %% 加载完场景
    StateEnter = lib_dungeon_distribute:fin_enter_dun(State, RoleId),
    if 
        InitWaveSign == ?INIT_WAVE_LOAD_SIGN ->
            {noreply, StateEnter};
        IsEnd == ?DUN_IS_END_YES ->
            {noreply, StateEnter};
        true ->
            %% 取消加载场景定时,开始特效倒计时,特效超时副本才真正开始
            util:cancel_timer(OldWaveStartRef),
            Ref = erlang:send_after(?ANIMATION_TIMEOUT, self(), {animation_timeout}),
            State1 = StateEnter#dungeon_state{animation_ref = Ref, wave_ref = [undefined, _OldWaveEndRef]},
            {noreply, State1}
    end;

do_handle_cast({animation_notice, Sid}, State) ->
    #dungeon_state{scene_id = SceneId, dun_id = DunId, wave_num = WaveNum, init_wave_sign = InitWaveSign} = State,
    if
        InitWaveSign == ?INIT_WAVE_LOAD_SIGN ->
            {DunStart, DunEnd, WaveStart, WaveEnd} = dungeon_logic:get_dun_time_info(State),
            lib_server_send:send_to_sid(Sid, pt_611, 61124, [SceneId, DunId, DunStart, DunEnd, WaveNum, WaveStart, WaveEnd, ?SUCCESS]),
            {noreply, State};
        true ->
            StateRefresh = dungeon_logic:refresh_init_wave_info(State),
            % 设置评分事件
            StateAfScore = lib_dungeon_distribute:make_grade_event(StateRefresh),
            % 副本通用评级
            StateAfRating = lib_dungeon_distribute:make_grade_rating(StateAfScore),
            % 推一次波数信息
            dungeon_logic:notice_wave_info(StateAfRating),
            {DunStart, DunEnd, WaveStart, WaveEnd} = dungeon_logic:get_dun_time_info(StateAfRating),
            %% 特效通知返回
            lib_server_send:send_to_sid(Sid, pt_611, 61124, [SceneId, DunId, DunStart, DunEnd, WaveNum, WaveStart, WaveEnd, ?SUCCESS]),
            % ?ERR("animation_notice ~p", [InitWaveSign]),
            {noreply, StateAfRating#dungeon_state{init_wave_sign = ?INIT_WAVE_LOAD_SIGN}}
    end;

do_handle_cast({get_god_dun_score, RoleId, Name, PhotoId, ZoneId, ServerId, SerNum, Wave}, State) ->
    #dungeon_state{role_list = [Role|_]} = State,
    #dungeon_role{typical_data = Map} = Role,
    ScoreL = maps:get(?DUN_ROLE_GOD_SCORE, Map, []),
    SumScore = lists:sum([ScoreX || {_, ScoreX} <- ScoreL]),
    clusters_node:apply_cast(gen_server, cast, [god_dun_rank_mgr, {get_role_god_dun_score, RoleId, ServerId, SerNum, Name, PhotoId, ZoneId, Wave, SumScore}]),
    {noreply, State};

do_handle_cast({apply, Mod, Fun, Args}, State) ->
    case catch Mod:Fun(State, Args) of
        NewState when is_record(NewState, dungeon_state) ->
            {noreply, NewState};
        {noreply, NewState} when is_record(NewState, dungeon_state) ->
            {noreply, NewState};
        {'EXIT', Error} ->
            ?ERR("mod_dungeon_cast: apply error: ~p~n", [[Mod, Fun, Args, Error]]),
            {noreply, State};
        _ ->
            {noreply, State}
    end;

do_handle_cast({dispatch_dun_event, Msg}, State) ->
    case catch lib_dungeon_distribute:dispatch_dun_event(Msg, State) of
        NewState when is_record(NewState, dungeon_state) ->
            {noreply, NewState};
        {noreply, NewState} when is_record(NewState, dungeon_state) ->
            {noreply, NewState};
        {'EXIT', Error} ->
            ?ERR("mod_dungeon_cast dispatch_dun_event ~p ~n error: ~p ~n", [Msg, Error]),
            {noreply, State};
        _ ->
            {noreply, State}
    end;

do_handle_cast({get_dummy_id, Id, OldDummyId}, State) ->
    #dungeon_state{typical_data = TypicalData} = State,
    DunDummys = maps:get(?DUN_STATE_SPECIAL_KEY_DUMMY, TypicalData, []),
    case lists:keyfind(OldDummyId, #dungeon_dummy.id, DunDummys) of
        OldDummy = #dungeon_dummy{figure = Figure} ->
            NewFigure = Figure#figure{id = Id},
            NewDunmmy = OldDummy#dungeon_dummy{id = Id, figure = NewFigure},
            NewDunDummys1 = lists:keydelete(OldDummyId, #dungeon_dummy.id, DunDummys),
            NewDunDummys = lists:keystore(Id, #dungeon_dummy.id, NewDunDummys1, NewDunmmy),
            NewTypicalData  = maps:put(?DUN_STATE_SPECIAL_KEY_DUMMY, NewDunDummys, TypicalData),
            NewState = State#dungeon_state{typical_data = NewTypicalData},
            {noreply, NewState};
        _ ->
            {noreply, State}
    end;

% keytake(Key, N, TupleList1) -> {value, Tuple, TupleList2}
do_handle_cast({dummy_die, FromAid, DieDummyId, ObjId, Args}, State) ->
    #dungeon_state{dun_type = DunType, typical_data = TypicalData} = State,
    if DunType == ?DUNGEON_TYPE_GUARD ->
            DunDummys = maps:get(?DUN_STATE_SPECIAL_KEY_DUMMY, TypicalData, []),
            case lists:keyfind(ObjId, #dungeon_dummy.id, DunDummys) of
                DieDummy = #dungeon_dummy{typical_data = DummyTypicalData} ->
                    ReviveRef = maps:get(?DUN_DUMMY_GUARD_REVIVE_REF, DummyTypicalData, undefined),
                    ReviveCount = maps:get(?DUN_DUMMY_GUARD_REVIVE_TIME, DummyTypicalData, 0),
                    NewReviveCount = ReviveCount + 1,
                    util:cancel_timer(ReviveRef),
                    MaxCount = lists:max(data_dun_guard:get_all_counts()),
                    CfgReviveCount = 
                    if NewReviveCount >= MaxCount -> MaxCount;
                        true -> NewReviveCount
                    end,
                    case data_dun_guard:get_revive(CfgReviveCount) of
                        #base_dun_guard_revive{cd = Cd} -> Cd;
                        _   -> Cd = 0
                    end,
                    if Cd == 0 -> NewReviveRef = undefined;
                        true   -> NewReviveRef = util:send_after(undefined, Cd*1000, self(), {dummy_revive, FromAid, DieDummyId, ObjId, Args})
                    end,
                    NewDummyTypicalData = maps:put(?DUN_DUMMY_GUARD_REVIVE_REF, NewReviveRef, DummyTypicalData),
                    NewDummyTypicalData1 = maps:put(?DUN_DUMMY_GUARD_REVIVE_TIME, NewReviveCount, NewDummyTypicalData),
                    NewDieDummy = DieDummy#dungeon_dummy{typical_data = NewDummyTypicalData1},
                    NewDunDummys = lists:keystore(ObjId, #dungeon_dummy.id, DunDummys, NewDieDummy),
                    NewTypicalData = maps:put(?DUN_STATE_SPECIAL_KEY_DUMMY, NewDunDummys, TypicalData),
                    NewState = State#dungeon_state{typical_data = NewTypicalData},
                    {noreply, NewState};
                _A ->
                    {noreply, State}
            end;
        true ->
            {noreply, State}
    end;


%% 默认匹配
do_handle_cast(Event, State) ->
    catch ?ERR("mod_dungeon_cast:handle_cast not match: ~p", [Event]),
    {noreply, State}.
