%% -------------------------------------
%% module   :lib_dungeon_god.erl
%% desc     :唤神副本
%% author   :hh
%% time     :21/06/20
%% -------------------------------------

-module(lib_dungeon_god).

-include("dungeon.hrl").
-include("god_dun.hrl").
-include("common.hrl").
-include("scene.hrl").
-include("czone.hrl").
-include("figure.hrl").
-include("predefine.hrl").
-include("def_goods.hrl").
-include("server.hrl").
-include("def_fun.hrl").
-include("def_module.hrl").
-include("battle.hrl").
-include("attr.hrl").
-include("skill.hrl").

-export([
    dispatch_dun_event/2
    ,handle_wave_state/2
    ,role_be_hurted/4

    ,calc_custom_made_mon_attr/3
    ,handle_enter_dungeon/2
    ,handle_kill_mon_do/2
    ,handle_dungeon_result/1
    ,pack_account_kv_data/2
    ,check_quit_state/2
    ,get_send_reward/2
    ,push_settlement/2
    ]).

-export([
    role_update_rank_score/3
    ,calc_wave_range_time/1
    ,god_dun_mon_info_ready/2
    ,handle_kill_dummy/5
    ,handle_kill_dummy_do/2
    ]).

dispatch_dun_event({'init_dun_wave', Wave}, State) ->
    #dungeon_state{dun_id = DunId} = State,
    DunWaveCfg = data_dungeon_wave:get_dun_wave(DunId, Wave),
    if is_record(DunWaveCfg, base_dun_wave_cfg) ->
            NewState  = init_god_dun_wave(DunWaveCfg, State),
            NewState1 = create_god_dun_wave_mon(DunWaveCfg, NewState),
            NewState1;
        true ->
            State
    end;

dispatch_dun_event({'create_mon', _SceneId, _MonList}, State) ->
    #dungeon_state{dun_id = DunId, wave_num = WaveNum, wave_info = [WaveInfo|_], role_list = RoleList} = State,
    #dun_wave_info{key = {Wave, WaveIndex}, typical_data = WaveMap} = WaveInfo,
    RandMonList = maps:get(mon_list, WaveMap, []),
    #dungeon_state{typical_data = DunMap} = NewState = calc_god_dun_start_time(State),
    MonNumL = [{MonIdX, 0} || {MonIdX, _, _} <- RandMonList],
    NewDunMap = maps:put(?DUN_STATE_SPECIAL_KEY_MON_KILL_CALC, MonNumL, DunMap),
    if
        RandMonList == [] ->
            NewState#dungeon_state{typical_data = NewDunMap};
        true ->
            NewState1 = NewState#dungeon_state{typical_data = NewDunMap},
            dungeon_logic:notice_wave_info(NewState1),
            dungeon_logic:notice_wave_mon_info(DunId, Wave, WaveIndex, [WaveInfo], RoleList),
            god_dun_create_mon(RandMonList, WaveNum, NewState1)
    end;

dispatch_dun_event(Msg, State) ->
    dungeon_default:dispatch_dun_event(Msg, State).

init_god_dun_wave(DunWaveCfg, State) ->
    #dungeon_state{
        index_of_wave = WaveIndex, typical_data = DunMap
    } = State,
    #base_dun_wave_cfg{wave = Wave, next_wave = NextWave, mon_list = MonList} = DunWaveCfg,
    WaveKey = {Wave, WaveIndex},
    {MonNum, RandMonList} = calc_rand_wave_mon(MonList),
    god_dun_rank_local:check_god_mon_info_update(self(), RandMonList),
    {_, WaveStartTime, WaveEndTime} = calc_wave_range_time(DunWaveCfg),
    Map = #{start_time_ms => WaveStartTime, end_time_ms => WaveEndTime, mon_list => RandMonList},
    WaveInfo     = dungeon_default:make_record(dun_wave_info, [WaveKey, 0, MonNum, ?DUN_WAVE_UNFIN, Map]),
    NewWaveInfos = [WaveInfo],
    if
        Wave =/= NextWave -> NewWaveIndex = WaveIndex;
        true -> NewWaveIndex = WaveIndex+1
    end,
    MonNum = length(RandMonList),
    NewDunMap =
    if
        MonNum == 2 ->
            DoubleWaves = maps:get(?DUN_ROLE_GOD_DOUBLE_REWARD_WAVE, DunMap, []),
            case lists:member(Wave, DoubleWaves) of
                true -> DunMap;
                _    -> maps:put(?DUN_ROLE_GOD_DOUBLE_REWARD_WAVE, [Wave|DoubleWaves], DunMap)
            end;
        true ->
            DunMap
    end,
    % ?ERR("~p", [NewDunMap]),
    NewState = State#dungeon_state{wave_num = Wave, index_of_wave = NewWaveIndex, wave_info = NewWaveInfos, typical_data = NewDunMap},
    %% 通知前端波数刷新
    dungeon_logic:notice_wave_info(NewState),
    NewState.

calc_wave_range_time(DunWaveCfg) ->
    #base_dun_wave_cfg{create_time = CreateTime, limit_time = LimitTime} = DunWaveCfg,
    Now = utime:longunixtime(),
    WaveStartTime = Now + CreateTime*1000,
    WaveEndTime   = WaveStartTime + LimitTime*1000,
    {Now, WaveStartTime, WaveEndTime}.

%% 生成初始波怪时记录开始时间
calc_god_dun_start_time(State) ->
    #dungeon_state{wave_num = WaveNum, typical_data = Map} = State,
    if
        WaveNum == 1 ->
            StartTime = utime:longunixtime(),
            NewMap = maps:put(?DUN_ROLE_GOD_START_TIME, StartTime, Map),
            State#dungeon_state{typical_data = NewMap};
        true ->
            State
    end.

%% 每波随机怪物
calc_rand_wave_mon(MonList) ->
    RandMons = urand:rand_with_weight([{Weight, Mons} || {Mons, Weight} <- MonList]),
    MonNum = length(RandMons),
    {MonNum, RandMons}.

%% 创怪操作
create_god_dun_wave_mon(DunWaveCfg, State) ->
    #dungeon_state{
        wave_num = Wave, index_of_wave = WaveIndex,
        init_wave_sign = InitWaveSign, wave_ref = WaveRef,
        wave_info = WaveInfos, dun_id = DunId
    } = State,
    #base_dun_wave_cfg{create_time = CreateTime, limit_time = LimitTime} = DunWaveCfg,
    [OldWaveStartRef, OldWaveEndRef|_] = WaveRef,
    [WaveInfo = #dun_wave_info{typical_data = WaveMap}|_] = WaveInfos,
    MonList = maps:get(mon_list, WaveMap, []),
    MonNumL = [{MonIdX, 0} || {MonIdX, _, _} <- MonList],
    % ?ERR("~p ~p", [Wave, MonNumL]),
    NewWaveMap = maps:put(?DUN_STATE_SPECIAL_KEY_MON_KILL_CALC, MonNumL, WaveMap),
    State0 = State#dungeon_state{wave_info = [WaveInfo#dun_wave_info{typical_data = NewWaveMap}]},
    if
        InitWaveSign =/= ?INIT_WAVE_LOAD_SIGN -> %% 默认初始波数需前端加载驱动
            WaveStartRef = util:send_after(OldWaveStartRef, ?INIT_WAVE_CREATE_TIME, self(), {'create_init_dun_wave_mon', ?INIT_WAVE_LOAD_SIGN, Wave, MonList}),
            NewState = State0;
        true -> %% 后续波数正常
            if
                CreateTime =< 0 ->
                    WaveStartRef = undefined,
                    NewState = dungeon_default:create_dun_wave_mon(MonList, Wave, State0);
                true ->
                    WaveStartRef = util:send_after(OldWaveStartRef, CreateTime*1000, self(), {'create_dun_wave_mon', Wave, MonList}),
                    NewState = State0
            end
    end,
    if  LimitTime == 0 ->
            util:cancel_timer(OldWaveEndRef),
            WaveEndRef = undefined;
        true ->
            WaveEndRef = util:send_after(OldWaveEndRef, (LimitTime+CreateTime)*1000, self(), {'wave_timeout', DunId, Wave, WaveIndex})
    end,
    NewState1 = NewState#dungeon_state{wave_ref = [WaveStartRef, WaveEndRef]},
    NewState1.


get_create_mon_args(From, MonId, FigureType) ->
    [{from_pid, From}, {born_handler, {?MODULE, calc_custom_made_mon_attr, [From, MonId, FigureType]}}].

handle_wave_state(State, [StateSign|_] = Args) ->
    if
        StateSign == ?WAVE_NEXT orelse
         StateSign == ?DUN_PASS ->
            #dungeon_state{dun_id = DunId, dun_type = DunType, role_list = [Role|_], wave_info = [WaveInfo|_]} = State,
            #dungeon_role{id = RoleId, server_id = ServerId, server_num = ServerNum, figure = Figure, typical_data = Map, hp = Hp, hp_lim = HpLim} = Role,
            #dun_wave_info{key = {Wave, _WaveIndex}, typical_data = WaveMap, status = _Status} = WaveInfo,
            case maps:get(end_time_ms, WaveMap, 0) of
                EndTime when EndTime =/= 0 ->
                    Now = utime:longunixtime(),
                    % ?ERR("~p ~p ~p ~p", [StartTime, CreateTime, LimitTime, Now]),
                    RestTime = EndTime - Now,
                    Score = calc_god_dun_wave_score(RestTime, Hp, HpLim, Wave),
                    % update_exchange_score(RoleId, Wave),
                    ScoreList = maps:get(?DUN_ROLE_GOD_SCORE, Map, []),
                    NewScoreList = lists:keystore(Wave, 1, ScoreList, {Wave, Score}),
                    TotalScore = lists:sum([ScoreX || {_, ScoreX} <- NewScoreList]),
                    update_role_score(wave_score, ServerId, ServerNum, DunId, RoleId, Wave, TotalScore, Figure),
                    update_role_score({total_score, StateSign}, ServerId, ServerNum, DunId, RoleId, Wave, Score, Figure),
                    update_role_score_in_local(RoleId, DunType, Score),
                    NewMap = maps:put(?DUN_ROLE_GOD_SCORE, NewScoreList, Map),
                    NewRoleList = [Role#dungeon_role{typical_data = NewMap}],
                    NewState = State#dungeon_state{role_list = NewRoleList};
                _ -> %% 开始时间记录有问题
                    NewState = State
            end,
            dungeon_default:handle_wave_state_normal(NewState, Args);
        true ->
            dungeon_default:handle_wave_state_normal(State, Args)
    end.

calc_god_dun_wave_score(RestTime, Hp, HpLim, Wave) ->
    %% 0.1
    BloodIntergral = data_god_dun:get_kv(blood_integral),
    %% 0.05
    TimeIntergral  = data_god_dun:get_kv(time_integral),
    case data_god_dun:get_wave_reward(Wave) of
        #base_god_dun_wave_reward{rank_score = RankScore} -> ok;
        _  -> RankScore = 0
    end,
    TimeScore = round(RestTime * TimeIntergral),
    %% 剩余血量百分比
    RestBlood = util:float_sub(Hp/HpLim, 4),
    BloodTimes = util:float_sub(RestBlood/0.0001, 4),
    BloodScore = round(BloodTimes * BloodIntergral),
    TotalScore = TimeScore + BloodScore + RankScore,
    % ?ERR("~p ~p ~p", [TimeScore, BloodScore, RankScore]),
    TotalScore.


role_be_hurted(State, RoleId, Hp, HpLim) ->
    #dungeon_state{role_list = RoleList} = State,
    case lists:keyfind(RoleId, #dungeon_role.id, RoleList) of
        Role = #dungeon_role{} ->
            NewRoleList = lists:keystore(RoleId, #dungeon_role.id, RoleList, Role#dungeon_role{hp = Hp, hp_lim = HpLim}),
            State#dungeon_state{role_list = NewRoleList};
        _ ->
            State
    end.

%% 怪物回调处理
calc_custom_made_mon_attr(init, Minfo = #scene_object{}, [InitPid, _, FigureType|_]) ->
    #scene_object{id = Mid, config_id = MonId, scene = SceneId, scene_pool_id = ScenePool, copy_id = CopyId, x = X, y = Y} = Minfo,
    From = self(),
    calc_custom_made_mon_attr_do(MonId, Mid, From, InitPid, FigureType, {SceneId, ScenePool, CopyId, X, Y}),
    Minfo;

calc_custom_made_mon_attr(init, Minfo = #ob_act{}, [InitPid, MonId, FigureType|_]) ->
    #ob_act{object = Object} = Minfo,
    #scene_object{id = Mid, scene = SceneId, scene_pool_id = ScenePool, copy_id = CopyId, x = X, y = Y} = Object,
    From = self(),
    calc_custom_made_mon_attr_do(MonId, Mid, From, InitPid, FigureType, {SceneId, ScenePool, CopyId, X, Y}),
    Minfo.

calc_custom_made_mon_attr_do(MonId, Mid, From, InitPid, FigureType, {SceneId, ScenePool, CopyId, X, Y}) ->
    case data_god_dun:get_mon(MonId) of
        GodMonCfg = #base_god_dun_mon_cfg{type = 2} ->
            god_dun_rank_local:get_role_attrs_by_other_rank(GodMonCfg, From, Mid);
        GodMonCfg = #base_god_dun_mon_cfg{type = 1} ->
            gen_server:cast(InitPid, {get_role_attrs_by_self_rank, GodMonCfg, From, FigureType, [Mid, SceneId, ScenePool, CopyId, X, Y]});
        _ ->
            ok
    end.

handle_enter_dungeon(Player, _DunCfg) ->
    #player_status{id = RoleId} = Player,
    Now = utime:unixtime(),
    ServerId = config:get_server_id(),
    ZoneId = czone_api:env_get_zone_id(),
    ZoneId =/= undefined andalso clusters_node:apply_cast(god_dun_rank_mgr, update_god_live_role, [RoleId, ZoneId, ServerId, Now]),
    Player.

update_role_score(ScoreType, ServerId, ServerNum, DunId, RoleId, Wave, Score, Figure) ->
    case czone_api:env_get_zone() of
        #czone_svr_local{zone_id = ZoneId} ->
            Role = change_data_format(ScoreType, ServerId, ServerNum, DunId, RoleId, Wave, Score, Figure),
            % ?ERR("~p ~p", [ZoneId, ScoreType]),
            if
                ScoreType == wave_score ->
                    clusters_node:apply_cast(god_dun_rank_mgr, upload_role_wave_score, [ZoneId, Wave, Role]);
                true ->
                    clusters_node:apply_cast(god_dun_rank_mgr, upload_role_total_score, [ZoneId, Wave, Role])
            end;
        _ ->
            skip
    end.

update_role_score_in_local(RoleId, DunType, Score) ->
    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_update_rank_score, [DunType, Score]).

role_update_rank_score(Player, DunType, Score) ->
    #player_status{id = RoleId} = Player,
    lib_week:plus_count(RoleId, ?MOD_DUNGEON, ?MOD_GOD_DUN_SCORE, DunType, Score),
    ok.

change_data_format(wave_score, ServerId, ServerNum, DunId, RoleId, Wave, Score, Figure) ->
    #figure{
        profile_photo_id = PhotoId, name = RoleName} = Figure,
    #god_dun_wave_score_role{
        dun_id = DunId,
        wave = Wave,
        role_id = RoleId,
        server_id = ServerId,
        server_num = ServerNum,
        score = Score,
        show = #wave_key_figure{name = RoleName, profile_photo_id = PhotoId}
    };
change_data_format({total_score, Status}, ServerId, ServerNum, _DunId, RoleId, _Wave, Score, Figure) ->
    #figure{
        name = RoleName, sex = Sex, career = Career, turn = Turn, vip_type = VipType,
        vip = Vip, sup_vip = SupVip, lv = Lv, power = Power, picture = Pic, picture_ver = PicVer,
        profile_photo_id = PhotoId, dress_list = DressList
    } = Figure,
    #god_dun_score_role{
        role_id = RoleId,
        server_id = ServerId,
        server_num = ServerNum,
        score = Score,
        pass = ?IF(Status == ?DUN_PASS, 1, 0),
        show = #role_key_figure{
            id = RoleId, name = RoleName, sex = Sex, career = Career,
            turn = Turn, vip_type = VipType, vip = Vip, sup_vip = SupVip,
            lv = Lv, power = Power, picture = Pic, picture_ver = PicVer,
            profile_photo_id = PhotoId, dress_list = DressList
        }
    }.


handle_kill_mon_do(State, [Mid, _AtterId, _MonXys|_]) ->
    #dungeon_state{typical_data = TypicalData, role_list = RoleList} = State,
    KillMonList = maps:get(?DUN_STATE_SPECIAL_KEY_MON_KILL_CALC, TypicalData, []),
    AllMonKill = maps:get(?DUN_STATE_SPECIAL_KEY_GOD_KILL, TypicalData, 0),
    NewKillMonList = case lists:keyfind(Mid, 1, KillMonList) of
        {_, OldNum} ->
            lists:keystore(Mid, 1, KillMonList, {Mid, OldNum+1});
        _ ->
            KillMonList
    end,
    NewTypicalData = maps:put(?DUN_STATE_SPECIAL_KEY_MON_KILL_CALC, NewKillMonList, TypicalData),
    NewTypicalData1 = maps:put(?DUN_STATE_SPECIAL_KEY_GOD_KILL, AllMonKill+1, NewTypicalData),
    {ok, BinData} = pt_611:write(61110, [AllMonKill+1]),
    dungeon_logic:notice_dun_role_info(RoleList, BinData),
    case RoleList of
        [#dungeon_role{id = RoleId}|_] ->
            lib_achievement_api:async_event(RoleId, lib_achievement_api, dungeon_god_event, 1);
        _ ->
            ignore
    end,
    State#dungeon_state{typical_data = NewTypicalData1}.

handle_kill_dummy(State, _KList, Atter, _AtterSign, [MonId, MonKey|_]) ->
    #ob_act{object = SceneObj} = State,
    #scene_object{id = AutoId, copy_id = CopyId} = SceneObj,
    #battle_return_atter{id = AtterId} = Atter,
    ReturnArgs = [AutoId, MonId, ?BATTLE_SIGN_DUMMY, MonKey, 0, [{killer, AtterId}]],
    mod_dungeon:apply(CopyId, ?MODULE, handle_kill_dummy_do, ReturnArgs),
    ok.

handle_kill_dummy_do(DunState, ReturnArgs) ->
    DunState1 = dungeon_logic:handle_kill_mon(ReturnArgs, DunState),
    {noreply, DunState1}.

handle_dungeon_result(State) ->
    #dungeon_state{scene_id = SceneId, scene_pool_id = ScenePool} = State,
    lib_mon:kill_scene_mon(SceneId, ScenePool, self()),
    State.

pack_account_kv_data(State, _RoleId) ->
    #dungeon_state{role_list = [Role|_], wave_info = WaveInfos, typical_data = TypicalData} = State,
    #dungeon_role{typical_data = Map} = Role,
    ScoreList = maps:get(?DUN_ROLE_GOD_SCORE, Map, []),
    DoubleWaves = maps:get(?DUN_ROLE_GOD_DOUBLE_REWARD_WAVE, TypicalData, []),
    TotalScore = lists:sum([ScoreX || {_, ScoreX} <- ScoreList]),
    [#dun_wave_info{key = {Wave, _WaveIndex}, status = Status}|_] = WaveInfos,
    PassWave = ?IF(Status == ?DUN_WAVE_FIN, Wave, max(0, Wave-1)),
    ExchangeScore = calc_role_exchange_score(PassWave, DoubleWaves, 0),
    [{1, TotalScore}, {2, ExchangeScore}].

calc_role_exchange_score(0, _, ExchangeScore) -> ExchangeScore;
calc_role_exchange_score(Wave, DoubleWaves, ExchangeScore) ->
    case data_god_dun:get_wave_reward(Wave) of
        #base_god_dun_wave_reward{score = Score} ->
            case lists:member(Wave, DoubleWaves) of
                true ->
                    calc_role_exchange_score(Wave-1, DoubleWaves, ExchangeScore+round(Score*2));
                _ ->
                    calc_role_exchange_score(Wave-1, DoubleWaves, ExchangeScore+Score)
            end;
        _ ->
            calc_role_exchange_score(Wave-1, DoubleWaves, ExchangeScore)
    end.

check_quit_state(State, _RoleId) ->
    #dungeon_state{
        role_list = [Role|_]
    } = State,
    #dungeon_role{typical_data = Map} = Role,
    case maps:get(?DUN_ROLE_GOD_SCORE, Map, []) of
        [] ->
            {?DUN_RESULT_TYPE_FAIL, ?DUN_RESULT_SUBTYPE_ACTIVE_QUIT};
        _ ->
            {?DUN_RESULT_TYPE_SUCCESS, ?DUN_RESULT_SUBTYPE_ACTIVE_QUIT}
    end.

get_send_reward(State, DungeonRole) ->
    #dungeon_state{wave_info = [WaveInfo|_], typical_data = Map, role_list = [DungeonRole|_]} = State,
    #dun_wave_info{key = {Wave, _}, status = Status} = WaveInfo,
    #dungeon_role{figure = Figure} = DungeonRole,
    DoubleWaves = maps:get(?DUN_ROLE_GOD_DOUBLE_REWARD_WAVE, Map, []),
    ResultWave =
    if
        Status == ?DUN_WAVE_UNFIN ->
            max(0, Wave-1);
        true ->
            Wave
    end,
    Rewards = calc_god_dun_reward(DoubleWaves, ResultWave, []),
    % ?ERR("~p ~p ~p", [DoubleWaves, ResultWave, Rewards]),
    case lib_dungeon_api:get_custom_act_reward_times(?DUNGEON_TYPE_GOD, 0, Figure#figure.lv) of
        Times when Times > 1 ->
            CustomReward = [{TGoodsType1, TGoodsId1, TGoodsNum1*max(1, Times-1)}||{TGoodsType1, TGoodsId1, TGoodsNum1}<-Rewards],
            DungeonRole#dungeon_role{calc_reward_list = Rewards, custom_reward_list = CustomReward};
        _ ->
            DungeonRole#dungeon_role{calc_reward_list = Rewards}
    end.

calc_god_dun_reward(_, Wave, Acc) when Wave =< 0 ->
    Acc;
calc_god_dun_reward(DoubleWaves, Wave, Acc) ->
    case data_god_dun:get_wave_reward(Wave) of
        #base_god_dun_wave_reward{rewards = WaveReward} ->
            case lists:member(Wave, DoubleWaves) of
                false ->
                    calc_god_dun_reward(DoubleWaves, Wave-1, lists:append(WaveReward, Acc));
                _ ->
                    DoubleRewards = [{GoodsType, GoodsTypeId, round(Num*2)} || {GoodsType, GoodsTypeId, Num} <- WaveReward],
                    calc_god_dun_reward(DoubleWaves, Wave-1, lists:append(DoubleRewards, Acc))
            end;
        _ ->
            calc_god_dun_reward(DoubleWaves, Wave-1, Acc)
    end.

push_settlement(State, DungeonRole) ->
    #dungeon_state{
        result_type = ResultType,
        dun_id = DunId,
        scene_id = SceneId,
        wave_num  = WaveNum,
        wave_info = WaveInfos,
        result_subtype = ResultSubtype
    } = State,
    #dungeon_role{
        node = Node, id = RoleId, custom_reward_list = CustomRewards
    } = DungeonRole,
    %%奖励
    RewardList = lib_dungeon:calc_base_reward_list(DungeonRole),

    KvData = pack_account_kv_data(State, RoleId),

    [#dun_wave_info{status = Status}|_] = WaveInfos,
    NewWaveNum =
    if Status == ?DUN_WAVE_UNFIN -> max(0, WaveNum-1);
        true -> WaveNum
    end,
    {ok, BinData} = pt_610:write(61003, [ResultType, ResultSubtype, DunId, SceneId, NewWaveNum, RewardList, CustomRewards, KvData]),
    dungeon_logic:send_to_uid(Node, RoleId, BinData).

god_dun_mon_info_ready(State, [MonArgs]) ->
    #dungeon_state{typical_data = TypicalData} = State,
    NewTypicalData = maps:put(mon_figure, MonArgs, TypicalData),
    State#dungeon_state{typical_data = NewTypicalData}.

god_dun_create_mon(MonList, WaveNum, State) ->
    #dungeon_state{
        mon_auto_id = MonAutoId, scene_id = NowSceneId, scene_pool_id = ScenePoolId,
        index_of_wave = WaveIndex, typical_data = TypicalData
    } = State,
    MonArgs     = maps:get(mon_figure, TypicalData, []),
    CopyId      = self(),

    MonFun = fun
        ({MonId, X, Y}, {Num, MonAutoIdX}) ->
            case lists:keyfind(MonId, 1, MonArgs) of
                {_, InfoRoleId, IsLocalSvr, FigureType} -> ok;
                _ -> IsLocalSvr = true, FigureType = 0, InfoRoleId = 0
            end,
            case data_mon:get(MonId) of
                MonCfg = #mon{type = MonType} -> ok;
                _ -> MonCfg = #mon{}, MonType = 0
            end,
            MonKey     = {?DUN_WAVE_MON_KEY, MonAutoIdX, WaveNum, WaveIndex},
            MonAttrs   = [{create_key, MonKey}, {type, MonType}],
            ExtraAttrs  = get_create_mon_args(CopyId, MonId, FigureType),
            SpecialAttrs = special_attrs(MonCfg, InfoRoleId, IsLocalSvr, FigureType, MonKey),
            FinalAttrs = lists:append([MonAttrs, ExtraAttrs, SpecialAttrs]),
            if FigureType == 1 -> ObjType = ?BATTLE_SIGN_DUMMY;
                true -> ObjType = ?BATTLE_SIGN_MON
            end,
            lib_scene_object:async_create_object(ObjType, MonId, NowSceneId, ScenePoolId, X, Y, MonType, CopyId, 1, FinalAttrs),
            % lib_mon:async_create_mon(MonId, NowSceneId, ScenePoolId, X, Y, MonType, CopyId, 1, FinalAttrs),
            {Num+1, MonAutoIdX+1};
        (_, {Num, MonAutoIdX}) ->
            {Num, MonAutoIdX}
    end,
    {_, MonAutoId1} = lists:foldl(MonFun, {0, MonAutoId}, MonList),
    State#dungeon_state{mon_auto_id = MonAutoId1}.

%% 本地玩家
special_attrs(MonCfg, RoleId, true, 1, MonKey) when RoleId =/= 0 ->
    #figure{career = Career, sex = Sex} = Figure = lib_role:get_role_figure(RoleId),
    {BattleAttr, Skills} = dummy_battle_attr(MonCfg, Career, Sex),
    ServerNum = config:get_server_num(),
    [{figure, Figure}, {battle_attr, BattleAttr}, {skill, Skills}, {dummy, #scene_dummy{server_num = ServerNum}}, {die_handler, {?MODULE, handle_kill_dummy, [MonCfg#mon.id, MonKey]}}];
%% 其他节点玩家
special_attrs(MonCfg, RoleId, false, 1, MonKey) when RoleId =/= 0 ->
    {Figure, ServerNum} = god_dun_rank_local:get_other_node_role(RoleId),
    #figure{career = Career, sex = Sex} = Figure,
    {BattleAttr, Skills} = dummy_battle_attr(MonCfg, Career, Sex),
    [{figure, Figure}, {battle_attr, BattleAttr}, {skill, Skills}, {dummy, #scene_dummy{server_num = ServerNum}}, {die_handler, {?MODULE, handle_kill_dummy, [MonCfg#mon.id, MonKey]}}];
special_attrs(_, _, _, _, _) ->
    [].

dummy_battle_attr(MonCfg, Career, Sex) ->
    #mon{
        att = Att, hit = Hit, dodge = Dodge, crit = Crit,  hp_lim = Hp, def = Def, ten = Ten
    } = MonCfg,
    %% 初始化怪物技能cd
    TempSkills = lib_skill_api:get_career_active_skill_ids(Career, Sex),
    SkillList  = dungeon_default:filter_anger_skill(TempSkills, []),
    %% 初始化内存数据
    Attr = #attr{att = Att, hp = Hp, hit = Hit, dodge = Dodge, crit = Crit, def = Def, ten = Ten, speed = ?SPEED_VALUE},
    AttrList = attr_conv:to_attr_tuple_list(Attr),
    % NewAttrList = ulists:kv_list_plus_extra(AttrList),
    NewAttr = attr_conv:to_attr_record(AttrList),
    BattleAttr = #battle_attr{
        hp=Hp, hp_lim=Hp, hp_lim_origin = Hp, attr=NewAttr,
        pk = #pk{}, speed = ?SPEED_VALUE, group = 1
    },
    {BattleAttr, SkillList}.