%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% 假人逻辑模块
%%%
%%% 本模块主要为“怪物逻辑管理进程”的状态函数的内部接口
%%%
%%% 是私有模块，
%%% 通常仅由怪物逻辑管理进程内部调用，其他地方勿用
%%%
%%% -------------------------------------------------------
%%% 其他说明：
%%% 这里的接口主要由原来 mod_dummy_active 模块中移植并调整。
%%% 此模块与怪物逻辑管理模块(mon_state_logic)都挂载在mon_mgr
%%% 实例进程中，其他详细说明可以参考怪物相关模块的说明
%%% @end
%%% -------------------------------------------------------
-module(dummy_state_logic).
%% mon_mgr回调接口
-export([
        init/1
        ,change_scene/2
        ,handle_info/3
        ,terminate/3
    ]).
%% 假人状态函数
-export([
        sleep/2
        ,trace/2
        ,find_target/2
        ,dead/2
        ,thorough_sleep/2
        ,back/2
        ,walk/2
        ,revive/2
    ]).

-include("server.hrl").
-include("scene.hrl").
-include("dungeon.hrl").
-include("skill.hrl").
-include("attr.hrl").
-include("common.hrl").
-include("figure.hrl").
-include("battle.hrl").
-include("def_fun.hrl").

%% 怪物属性和初始状态初始化
init([Id, _ConfigId, Scene, ScenePoolId, Xpx, Ypx, Type, CopyId, BroadCast, Arg]) ->
    Dummy  = #scene_object{
        sign=?BATTLE_SIGN_DUMMY, id=Id, scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=Xpx, y=Ypx, aid=self(),
        type=Type, warning_range = 1200, create_time = utime:unixtime(), striking_distance = 500, tracing_distance = 1200,
        dummy = #scene_dummy{}
    },
    Default = #ob_act{object = Dummy},
    {State, StateName, _} = lib_scene_object:set_args(Arg, Default, sleep, 0, []),

    HandlerState =
    case State#ob_act.born_handler of
        {BornM, BornF, BornA} ->
            case BornM:BornF(init, State, BornA) of
                StateThen when is_record(StateThen, ob_act) ->
                    StateThen;
                _ ->
                    State
            end;
        _ ->
            State
    end,
    
    lib_scene_object:insert(HandlerState#ob_act.object),

    case BroadCast =:= 1 of
        true  -> lib_scene_object:broadcast_object(HandlerState#ob_act.object);
        false -> ignore
    end,
    {ok, StateName, HandlerState}.

%% 切换场景
change_scene(State, Args) ->
    {State1, StateName, _} = lib_scene_object:set_args([{aid, self()}|Args], State, sleep, 0, []),
    State2 =
    case State1#ob_act.change_scene_handler of
        {BornM, BornF, BornA} ->
            case BornM:BornF(State1, BornA) of
                StateThen when is_record(StateThen, ob_act) ->
                    StateThen;
                _ ->
                    State1
            end;
        _ ->
            State1
    end,
    lib_scene_object:insert(State2#ob_act.object),
    lib_scene_object:broadcast_object(State2#ob_act.object),
    {ok, StateName, State2}.

%% ------------------------------------------------
%% 一些状态下的特殊消息过滤
%% ------------------------------------------------
handle_info(_, thorough_sleep, State) ->
    {next_state, thorough_sleep, State};
%% ------------------------------------------------

%% 清理假人
handle_info({'stop', Broadcast}, _StateName, State) ->
    lib_scene_object:stop(State#ob_act.object, Broadcast),
    {stop, normal, State};

%% 随机走路
handle_info('auto_move', _StateName, State) ->
    #ob_act{object=Object} = State,
    #scene_object{x=X, y=Y} = Object,
    Angle = urand:rand(-1000, 1000)*math:pi()/1000,
    TmpX = max(0, round(X+134*math:sin(Angle))),
    TmpY = max(0, round(Y+134*math:cos(Angle))),
    {NewObject, _Time} = lib_scene_object_ai:move_dest_path(Object, X, Y, TmpX, TmpY),
    {next_state, thorough_sleep, State#ob_act{object=NewObject}};

handle_info({'battle_info', BattleReturn}, StateName, State) ->
    #battle_return{
        hp = Hp,
        hurt = FullHurt,
        move_x = MoveX,
        move_y = MoveY,
        attr_buff_list = AttrBuffList,
        other_buff_list = OtherBuffList,
        atter = Atter,
        sign  = AtterSign  %% 1：怪物， 2：人
    } = BattleReturn,
    #battle_return_atter{hide=AtterHide, real_id=RealId, x=Xatt, y=Yatt, id = AttackId, sign = AttackSign} = Atter,
    #ob_act{att=OldAtt, object = Object, die_handler = DieHandler, klist = KList} = State,
    Hurt = min(FullHurt, Object#scene_object.battle_attr#battle_attr.hp),
    %% 目前只记录玩家id，以后有需求再做拓展(给攻击加上时间戳)
    NewKList =
    case AttackSign == ?BATTLE_SIGN_PLAYER andalso Hurt > 0  of
        true ->
            case lists:keyfind(AttackId, #mon_atter.id, KList) of
                #mon_atter{} = MonAtter ->
                    lists:keystore(AttackId, #mon_atter.id, KList, MonAtter#mon_atter{time = utime:unixtime()});
                _ ->
                    [#mon_atter{id = AttackId, time = utime:unixtime()}|KList]
            end;
        _ ->
            KList
    end,
    Object1 = Object#scene_object{
        battle_attr = Object#scene_object.battle_attr#battle_attr{hp=max(0,Hp), attr_buff_list=AttrBuffList, other_buff_list=OtherBuffList},
        x = case MoveX == 0 of
            true -> Object#scene_object.x;
            false -> MoveX
        end,
        y = case MoveY == 0 of
            true -> Object#scene_object.y;
            false -> MoveY
        end
    },
    State1 = State#ob_act{object = Object1, klist = NewKList},
    if
        Hp =< 0 ->
            StateDriven = mon_state_util:conv_delay_driven({3000, repeat}),
            lib_scene_object_event:be_killed(Object1, [], Atter, AtterSign),
            DieState =
            case DieHandler of
                {Mod, Fun, Args} ->
                    case catch Mod:Fun(State1, NewKList, Atter, AtterSign, Args) of
                        {'EXIT', Err} ->
                            ?ERR("apply ~p error ~p~n", [DieHandler, Err]),
                            State1;
                        #ob_act{} = StateThen ->
                            StateThen;
                        _ ->
                            State1
                    end;
                _ ->
                    State1
            end,
            {next_state, dead, DieState#ob_act{att=undefined, state_driven = StateDriven, klist = []} };
        true ->
            NewAttTarget =
                if
                    AtterHide == 1 -> OldAtt;
                    OldAtt == undefined -> #{id=>RealId, x=>Xatt, y=>Yatt, sign=>AtterSign};
                    true -> #{id=>RealId, x=>Xatt, y=>Yatt, sign=>AtterSign}
                end,
            if
                StateName == sleep orelse StateName == find_target ->
                    StateDriven = mon_state_util:conv_delay_driven({500, repeat}),
                    {next_state, trace, State1#ob_act{att=NewAttTarget, state_driven = StateDriven}};
                true ->
                    {next_state, StateName, State1#ob_act{att=NewAttTarget}}
            end
    end;

%% 副技能
handle_info({'combo_battle_back', Res}, StateName, State) ->
    case Res of
        #skill_return{used_skill = SkillId, aer_info = BackData} ->
            case maps:find(SkillId, State#ob_act.selected_skill) of
                {ok, SelectedSkillInfo} when is_record(SelectedSkillInfo, selected_skill) ->
                    NewState = lib_scene_object_ai:battle_combo_res(SelectedSkillInfo, State, Res),
                    {next_state, StateName, NewState};
                _ ->
                    #ob_act{object = Object} = State,
                    BackObj = lib_battle_api:update_by_slim_back_data(Object, BackData),
                    {next_state, StateName, State#ob_act{object = BackObj}}
            end;
        _ ->
            {next_state, StateName, State}
    end;

handle_info({'combo_assist_back', Res}, StateName, State) ->
    case Res of
        #skill_return{used_skill = SkillId, aer_info = BackData} ->
            case maps:find(SkillId, State#ob_act.selected_skill) of
                {ok, SelectedSkillInfo} when is_record(SelectedSkillInfo, selected_skill) ->
                    NewState = lib_scene_object_ai:assist_combo_res(SelectedSkillInfo, State, Res),
                    {next_state, StateName, NewState};
                _ ->
                    #ob_act{object = Object} = State,
                    BackObj = lib_battle_api:update_by_slim_back_data(Object, BackData),
                    {next_state, StateName, State#ob_act{object = BackObj}}
            end;
        _ ->
            {next_state, StateName, State}
    end;

%% 释放辅助技能
handle_info({'object_assist_back', Res}, StateName, State) ->
    #ob_act{selected_skill = SelectSkillMap, general_driven = GeneralDriven, object = SceneObject} = State,
    case Res of
        #skill_return{used_skill = SkillId} ->
            case maps:find(SkillId, SelectSkillMap) of
                {ok, SelectedSkillInfo} when is_record(SelectedSkillInfo, selected_skill) ->
                    {Next, Args} = lib_scene_object_ai:handle_assist_res(SelectedSkillInfo, SceneObject, GeneralDriven, Res),
                    AfBattleState = lib_scene_object_ai:set_ac_state(Args, State),
                    NextStateName = case Next of
                        trace -> trace;
                        _     -> back
                    end,
                    {next_state, NextStateName, AfBattleState};
                _ ->
                    NewState = mon_state_util:update_state_driven(State, {1000, repeat}),
                    {next_state, StateName, NewState}
            end;
        _ ->
            NewState = mon_state_util:update_state_driven(State, {1000, repeat}),
            {next_state, StateName, NewState}
    end;

%% 释放主动技能
handle_info({'object_battle_back', Res}, StateName, State) ->
    #ob_act{selected_skill = SelectSkillMap, general_driven = GeneralDriven, object = SceneObject} = State,
    case Res of
        #skill_return{used_skill = SkillId} ->
            case maps:find(SkillId, SelectSkillMap) of
                {ok, SelectedSkillInfo} when is_record(SelectedSkillInfo, selected_skill) ->
                    {Next, Args} = lib_scene_object_ai:handle_battle_res(SelectedSkillInfo, SceneObject, GeneralDriven, Res),
                    AfBattleState = lib_scene_object_ai:set_ac_state(Args, State),
                    NextStateName = case Next of
                        trace -> trace;
                        _     -> back
                    end,
                    {next_state, NextStateName, AfBattleState};
                _ ->
                    NewState = mon_state_util:update_state_driven(State, {1000, repeat}),
                    {next_state, StateName, NewState}
            end;
        _ ->
            NewState = mon_state_util:update_state_driven(State, {1000, repeat}),
            {next_state, StateName, NewState}
    end;


%% 设置战斗状态
handle_info({'battle_attr', BA}, StateName, State) ->
    #ob_act{object=Object} = State,
    {next_state, StateName, State#ob_act{object=Object#scene_object{battle_attr=BA}}};

%% 设置buff
handle_info({'buff', AttrBuffL, OtherBuffL}, StateName, State) ->
    #ob_act{object=#scene_object{battle_attr=BA}=Object} = State,
    {next_state, StateName, State#ob_act{object=Object#scene_object{battle_attr=BA#battle_attr{attr_buff_list=AttrBuffL, other_buff_list=OtherBuffL}}}};

handle_info({'change_attr', KeyValues}, StateName, State) ->
    {NewState, NewStateName, UpList} = lib_scene_object:set_args(KeyValues, State, StateName, 1, []),
    lib_scene_object:update(NewState#ob_act.object, UpList),
    lib_scene_object:broadcast_object(NewState#ob_act.object),
    NewState2 = case NewStateName /= StateName of
        true  ->
            mon_state_util:update_state_driven(NewState, {0, repeat});
        false -> NewState
    end,
    {next_state, NewStateName, NewState2};

%% 持续施放副技能
handle_info({'combo', Args}, StateName, State) ->
    State1 = lib_scene_object_ai:combo(Args, State),
    {next_state, StateName, State1};

%% 寻找新目标
handle_info('find_target', _StateName, State) ->
    NewState = mon_state_util:update_state_driven(State, {0, repeat}),
    {next_state, find_target, NewState};

%% 死亡复活
handle_info('revive', _StateName, State) ->
    NewState = mon_state_util:update_state_driven(State, {50, repeat}),
    {next_state, revive, NewState};

%% 找目标追踪(死亡状态/睡眠状态不处理)
handle_info({'get_for_trace', _Res}, sleep, State) ->
    {next_state, sleep, State};
handle_info({'get_for_trace', Res}, StateName, State) ->
    #ob_act{att=Att, state_driven = OldStateDriven, object = Object, path = MonPath} = State,
    #scene_object{battle_attr = BattleAttr, scene = SceneId, x = X, y = Y} = Object,
    IsWastelandSafe = lists:member(SceneId, [7600,7601]) andalso scene_landform:is_safe_pos(SceneId, X, Y),
    case Res of
        {TgSign, TgId, TgPid, TgX, TgY} when BattleAttr#battle_attr.hp > 0 ->
            case Att of
                undefined ->
                    case OldStateDriven of
                        {TimeMS, _} when TimeMS > 0 ->
                            NowTimeMS = utime:unixtime(ms),
                            RemainTime = TimeMS - NowTimeMS,
                            case RemainTime > 100 of
                                true  ->
                                    StateDriven = mon_state_util:conv_delay_driven({RemainTime, go}, NowTimeMS),
                                    NewState = State#ob_act{
                                        att=#{id=>TgId, sign=>TgSign, pid=>TgPid, x=>TgX, y=>TgY},
                                        state_driven = StateDriven
                                    },
                                    {next_state, trace, NewState};
                                _ ->
                                    NewState = State#ob_act{att=#{id=>TgId, sign=>TgSign, pid=>TgPid, x=>TgX, y=>TgY}},
                                    Msg = if
                                              StateName =:= trace -> repeat;
                                              true -> go
                                          end,
                                    % handle_info({'trace_info_back', [TgId, TgX, TgY, Msg]}, StateName, NewState)
                                    %% 废土战场如果假人在安全区，继续往非安全区移动(冲刺)，不记录攻击目标
                                    case IsWastelandSafe of
                                        true when MonPath =/= [] ->
                                            DelayGeneralDriven = [{200, rush_and_find_target}],
                                            NewState1 = mon_state_util:update_general_driven(State, DelayGeneralDriven),
                                            {next_state, StateName, NewState1};
                                        true -> %% 触发本分支概率比较低,因为假人复活不会清空path字段。计算数组消耗理论上说比较低
                                            {TargetX, TargetY} = offline_hosting_wasteland_war:get_target_point(SceneId),
                                            NewPath = lib_scene_object_ai:dest_path(X, Y, TargetX, TargetY, BattleAttr#battle_attr.speed),
                                            DelayGeneralDriven = [{200, rush_and_find_target}],
                                            NewState1 = mon_state_util:update_general_driven(State, DelayGeneralDriven),
                                            {next_state, StateName, NewState1#ob_act{path = NewPath}};
                                        _ ->
                                            handle_info({'trace_info_back', [TgId, TgX, TgY, Msg]}, StateName, NewState)
                                    end
                            end;
                        _ ->
                            NewState = State#ob_act{att=#{id=>TgId, sign=>TgSign, pid=>TgPid, x=>TgX, y=>TgY}},
                            Msg = if
                                      StateName =:= trace -> repeat;
                                      true -> go
                                  end,
                            % handle_info({'trace_info_back', [TgId, TgX, TgY, Msg]}, StateName, NewState)
                            case IsWastelandSafe of
                                true when MonPath =/= [] ->
                                    DelayGeneralDriven = [{200, rush_and_find_target}],
                                    NewState1 = mon_state_util:update_general_driven(State, DelayGeneralDriven),
                                    {next_state, StateName, NewState1};
                                true ->
                                    {TargetX, TargetY} = offline_hosting_wasteland_war:get_target_point(SceneId),
                                    NewPath = lib_scene_object_ai:dest_path(X, Y, TargetX, TargetY, BattleAttr#battle_attr.speed),
                                    DelayGeneralDriven = [{200, rush_and_find_target}],
                                    NewState1 = mon_state_util:update_general_driven(State, DelayGeneralDriven),
                                    {next_state, StateName, NewState1#ob_act{path = NewPath}};
                                _ ->
                                    handle_info({'trace_info_back', [TgId, TgX, TgY, Msg]}, StateName, NewState)
                            end
                    end;
                _ ->
                    {next_state, StateName, State}
            end;
        _ ->
            StateDriven = mon_state_util:conv_delay_driven({2000, repeat}),
            {next_state, back, State#ob_act{state_driven = StateDriven}}
    end;

%% 追踪我的攻击目标后的返回(死亡状态状态不处理)
handle_info({'trace_info_back', [Id, X, Y|_]}, StateName, State) ->
    #ob_act{
        att=Att, object = Minfo, skill_link_info = SkillLinkInfo,
        next_att_time = NextAttTime, next_move_time = NextMoveTime,
        check_block = CheckBlock
    } = State,
    #scene_object{
        scene = SceneId, copy_id = CopyId, x = MyX, y = MyY, 
        striking_distance = AttArea, tracing_distance=TracingDistance,
        battle_attr = BattleAttr} = Minfo,
    #battle_attr{speed = Speed} = BattleAttr,
    case Att of
        #{id := Id, sign := Sign} when BattleAttr#battle_attr.hp > 0 ->
            case lib_scene_path:is_continue_trace(MyX, MyY, X, Y, TracingDistance) of
                false ->
                    case data_scene:get(SceneId) of
                        #ets_scene{type = ?SCENE_TYPE_DUNGEON} ->
                            case lib_scene_object_ai:get_next_step(MyX, MyY, AttArea, SceneId, CopyId, X, Y, true) of
                                {New_x, New_y} ->
                                    case lib_scene_object_ai:move(New_x, New_y, Minfo, Speed, false) of
                                        block ->
                                            StateDriven = mon_state_util:conv_delay_driven({100, repeat}),
                                            {next_state, back, State#ob_act{att = undefined, state_driven = StateDriven}};
                                        {true, NewMinfo, Time} ->
                                            StateDriven = mon_state_util:conv_delay_driven({Time, repeat}),
                                            NewState = State#ob_act{object = NewMinfo, state_driven = StateDriven},
                                            {next_state, trace, NewState}
                                    end;
                                attack ->
                                    NowTime = utime:longunixtime(),
                                    {Next, Args} = lib_scene_object_ai:trace_to_att(Minfo, X, Y, 
                                        {target, Sign, Id}, NextAttTime, NextMoveTime, NowTime, SkillLinkInfo, CheckBlock),
                                    %% 这里有可能会丢失目标！！ 既是：att = undefined
                                    AfBattleState = lib_scene_object_ai:set_ac_state(Args, State),
                                    NextStateName = case Next of
                                        trace -> trace;
                                        back  -> back;
                                        _     -> back
                                    end,
                                    {next_state, NextStateName, AfBattleState};
                                _A ->
                                    StateDriven = mon_state_util:conv_delay_driven({100, repeat}),
                                    {next_state, back, State#ob_act{att = undefined, state_driven = StateDriven}}
                            end;
                        _ ->
                            StateDriven = mon_state_util:conv_delay_driven({100, repeat}),
                            {next_state, back, State#ob_act{att=undefined, state_driven = StateDriven}}
                    end;
                _R ->
                    NowTime = utime:longunixtime(),
                    {Next, Args}  = lib_scene_object_ai:trace_to_att(
                        Minfo, X, Y,
                        {target, Sign, Id},
                        NextAttTime, NextMoveTime, NowTime, SkillLinkInfo, CheckBlock
                    ),
                    %% 这里有可能会丢失目标！！ 既是：att = undefined
                    AfBattleState = lib_scene_object_ai:set_ac_state(Args, State),
                    NextStateName = case Next of
                                        trace -> trace;
                                        back  -> back;
                                        _     -> back
                                    end,
                    {next_state, NextStateName, AfBattleState}
            end;
        _ ->
            {next_state, StateName, State}
    end;
%% 追踪目标返回 找不到目标，则开始寻找新目标
handle_info({'trace_info_back', _Res}, _StateName, State) ->
    NewState = mon_state_util:update_state_driven(State, {500, repeat}),
    {next_state, find_target, NewState#ob_act{att = undefined}};

%% 冲刺并寻找新目标
handle_info(rush_and_find_target, _StateName, State) ->
    #ob_act{object = Minfo, path = MonPath} = State,
    #scene_object{battle_attr= BA, x = X, y = Y} = Minfo,
    case MonPath of
        [] ->
            NewState = mon_state_util:update_state_driven(State, {0, repeat}),
            {next_state, find_target, NewState};
        [{NextX, NextY}|RemainPath] ->
            #battle_attr{speed = Speed} = BA,
            case lib_scene_object_ai:move(NextX, NextY, Minfo, Speed, false) of
                block ->
                    StateDriven = mon_state_util:conv_delay_driven({500, repeat}),
                    {next_state, find_target, State#ob_act{state_driven = StateDriven, path=RemainPath}};
                {true, NewMinfo, Time} ->
                    lib_mon_event:walk(NewMinfo),
                    NewTime = max(300, Time),
                    StateDriven = mon_state_util:conv_delay_driven({NewTime, repeat}),
                    {next_state, find_target, State#ob_act{
                        object=NewMinfo, state_driven = StateDriven, path=RemainPath, o_point = {X, Y}, w_point = {NextX, NextY}
                    }
                    }
            end;
        _ ->
            NewState = mon_state_util:update_state_driven(State, {0, repeat}),
            {next_state, find_target, NewState}

    end;

%% 移动
handle_info({move, X, Y}, StateName, State) ->
    #ob_act{object = Object} = State,
    #scene_object{battle_attr = #battle_attr{speed=Speed}} = Object,
    case lib_scene_object_ai:move(X, Y, Object, Speed, false) of
        {true, NewObject, _LastTime} ->
            {next_state, StateName, State#ob_act{object = NewObject}};
        _ ->
            {next_state, StateName, State}
    end;

handle_info('sleep', _StateName, State) ->
    {next_state, sleep, State};

handle_info('thorough_sleep', _StateName, State) ->
    {next_state, thorough_sleep, State};

%% 托管玩家触发行为
handle_info({offline_hosting_behavior, Behavior, Arg}, StateName, Status) ->
    case apply(offline_hosting_dummy, host_behavior, [Behavior, Status, Arg]) of
        ok ->
            {next_state, StateName, Status};
        {ok, NewStatus} when is_record(NewStatus, ob_act) ->
            {next_state, StateName, NewStatus};
        {stop, Reason, NewStatus} when is_record(NewStatus, ob_act) ->
            {stop, Reason, NewStatus};
        _ ->
            {next_state, StateName, Status}
    end;

%% 假人切场景
handle_info({change_scene, SceneId, PoolId, CopyId, X, Y, Arg}, _StateName, State) ->
    #ob_act{
        object = Object
    } = State,
    NewObject = Object#scene_object{
        scene = SceneId,
        scene_pool_id = PoolId,
        copy_id = CopyId,
        x = X,
        y = Y
    },
    NewState = State#ob_act{object = NewObject, att = undefined, klist = []},
    case clusters_api:is_center() of
        true  ->
            case lib_scene:is_clusters_scene(SceneId) of
                true  ->
                    %% 确保场景进程开启
                    mod_scene_agent:get_scene_pid(SceneId, PoolId),
                    mon_mgr:insert_mon(NewState, Arg);
                false ->
                    %% 到对应节点获取新的对象id
                    ServerId = clusters_center:get_node_by_role_id(Object#scene_object.figure#figure.id),
                    clusters_center:apply_cast(ServerId, lib_scene_object, insert_object, [NewState, Arg])
            end;
        false ->
            case lib_scene:is_clusters_scene(SceneId) of
                true  ->
                    %% 到对应节点获取新的对象id
                    clusters_node:apply_cast(lib_scene_object, insert_object, [NewState, Arg]);
                false ->
                    %% 确保场景进程开启
                    mod_scene_agent:get_scene_pid(SceneId, PoolId),
                    mon_mgr:insert_mon(NewState, Arg)
            end
    end,
    %% 广播删除旧的,更新新的
    lib_scene_object:stop(Object, 1),
    {stop, normal, State};

handle_info(_Info, StateName, State) ->
    {next_state, StateName, State}.

terminate(Reason, _StateName, _Status = #ob_act{object = SceneObject}) ->
    #scene_object{id = ObjId,
        scene = SceneId, scene_pool_id = PoolId, copy_id = CopyId,
        config_id = ConfigId
    } = SceneObject,
    terminate_gc_proc_dict(ObjId),
    case Reason of
        normal -> ignore;
        _ ->
            ?ERR("scene[~w,~w,~w] obj[~w] terminate state[~w], error:~n~p",
                [SceneId, PoolId, CopyId, ConfigId, _StateName, Reason]
            )
    end,
    ok;
terminate(_Reason, _StateName, _StateData) ->
    ?ERR("scene obj data error:~w", [_StateData]),
    ok.

%% =========处理怪物所有状态=========

%%静止状态并回血
sleep(_R, State) ->
    {next_state, sleep, State}.

%% 彻底休眠状态，只接受死亡信息
thorough_sleep(_R, State) ->
    {next_state, thorough_sleep, State}.

%% 战斗死亡
%% 死亡
dead(_R, State) ->
    #ob_act{object=Object, revive_time = ReTime, stay_dead = Stay} = State,
    if
        ReTime =< 0 ->
            case Stay > 0 of
                true  ->
                    {next_state, sleep, State};
                false ->
                    lib_scene_object:stop(Object, 1),
                    {stop, normal, State}
            end;
        true ->
            NewState = mon_state_util:update_general_driven(State, [{ReTime, 'revive'}]),
            {next_state, dead, NewState}
    end.

%% 复活
revive(_R, State) ->
    #ob_act{born_handler = BornHandler} = State,
    ReviveState =
        case BornHandler of
            {BornM, BornF, BornA} ->
                case catch BornM:BornF(revive, State, BornA) of
                    {'EXIT', Err} ->
                        ?ERR("apply ~p error ~p~n", [BornHandler, Err]),
                        State;
                    StateThen when is_record(StateThen, ob_act) ->
                        StateThen;
                    _ ->
                        State
                end;
            _ ->
                State
        end,
    #scene_object{battle_attr=BA, x = X, y = Y} =
        Minfo = ReviveState#ob_act.object,
    #battle_attr{hp_lim=HpLim} = BA,
    NewMinfo = Minfo#scene_object{battle_attr=BA#battle_attr{hp = HpLim}},
    lib_scene_object:update(NewMinfo, [{rivive, HpLim, X, Y, 1},
        {pk_protect_time, BA#battle_attr.pk#pk.pk_protect_time}]),
    StateDriven = mon_state_util:conv_delay_driven({1000, repeat}),
    NewState = ReviveState#ob_act{
        object = NewMinfo,
        state_driven = StateDriven,
        att = undefined,
        klist = [],
        clist = [],
        first_att = []
    },
    {next_state, back, NewState}.

%% 追踪
trace(Msg, State) ->
    #ob_act{att=Att, object = Minfo, next_move_time=NextMoveTime} = State,
    #scene_object{
        scene = SceneId, scene_pool_id = ScenePoolId,
        aid = Aid, id = ObjectId
    } = Minfo,
    case Att of
        #{id:=Id, sign:=Sign} -> skip;
        _ -> Id = 0, Sign = 0
    end,
    case Id=/=0 of %% 有目标
        true ->
            NowTimeMS = utime:unixtime(ms),
            if
                NextMoveTime > NowTimeMS ->
                    DelayTime = NextMoveTime - NowTimeMS,
                    NewState = mon_state_util:update_state_driven(State, {DelayTime, Msg}, NowTimeMS),
                    {next_state, trace, NewState};
                true ->
                    mod_scene_agent:apply_cast(SceneId, ScenePoolId,
                        lib_scene_agent, get_trace_info_cast,
                        [Aid, ObjectId, Sign, Id, Msg]
                    ),
                    NewState = mon_state_util:update_state_driven(State, {5000, repeat}, NowTimeMS),
                    {next_state, back, NewState}
            end;
        _ -> %% 目标丢失，尝试等待
            NewState = mon_state_util:update_state_driven(State, {3000, repeat}),
            {next_state, back, NewState}
    end.

%% 查找target
find_target(_, State) ->
    #ob_act{object=Object, find_type = FindType} = State,
    #scene_object{id=ObjectId, aid = Aid, sign=ObjectSign, x=ObjectX, y=ObjectY, scene=SceneId, scene_pool_id=ScenePoolId, copy_id=CopyId, warning_range = WarningRange,
        battle_attr=BA, skill_owner=SkillOwner, pos=_Pos} = Object,
    {OwnerSign, OwnerId} = lib_scene_object_ai:get_skill_owner_args(SkillOwner),
    Args = {BA#battle_attr.group, ObjectSign, ObjectId, OwnerSign, OwnerId},
    mod_scene_agent:apply_cast(
        SceneId, ScenePoolId, lib_scene_calc, get_any_for_trace_cast_mon_first,
        [Aid, ObjectId, CopyId, ObjectX, ObjectY, WarningRange, Args, undefined, FindType]
    ),
    {next_state, back, State}.

back(_, State) ->
    #ob_act{object = Minfo, path = Path} = State,
    #scene_object{battle_attr=BA} = Minfo,
    case BA#battle_attr.hp =< 0 of
        true ->
            % old: Ref1 = lib_scene_object:send_event_after(Ref, 100, repeat),
            StateDriven = mon_state_util:conv_delay_driven({100, repeat}),
            {next_state, dead, State#ob_act{att = undefined, state_driven = StateDriven, back_dest_path=null}};
        false ->
            case Path of
                [_|_] ->
                    % old: Ref1 = lib_scene_object:send_event_after(Ref, 0, repeat),
                    StateDriven = mon_state_util:conv_delay_driven({0, repeat}),
                    {next_state, walk, State#ob_act{state_driven = StateDriven, att = undefined}};
                _ ->
                    % old: Ref1 = lib_scene_object:send_event_after(Ref, 2000, repeat),
                    StateDriven = mon_state_util:conv_delay_driven({2000, repeat}),
                    {next_state, find_target, State#ob_act{state_driven = StateDriven, att = undefined}}
            end
    end.

walk(_R, State) ->
    #ob_act{object=Minfo, path=MonPath} = State,
    #scene_object{battle_attr= BA, x = X, y = Y} = Minfo,
    case MonPath of
        [] ->
            StateDriven = mon_state_util:conv_delay_driven({2000, repeat}),
            {next_state, find_target, State#ob_act{state_driven = StateDriven, path = undefined}};
        [{NextX, NextY}|RemainPath] ->
            #battle_attr{speed=Speed} = BA,
            NowTime = utime:longunixtime(),
            case lib_skill_buff:is_can_move(BA#battle_attr.other_buff_list, Speed, NowTime) of
                {false, MoveWaitMs} ->
                    NewState = mon_state_util:update_state_driven(State, {MoveWaitMs, repeat}),
                    {next_state, find_target, NewState};
                false ->
                    {next_state, sleep, State#ob_act{att=undefined}};
                true ->
                    case lib_scene_object_ai:move(NextX, NextY, Minfo, Speed, false) of
                        block ->
                            StateDriven = mon_state_util:conv_delay_driven({500, repeat}),
                            {next_state, sleep, State#ob_act{state_driven = StateDriven, path=[]}};
                        {true, NewMinfo, Time} ->
                            lib_mon_event:walk(NewMinfo),
                            StateDriven = mon_state_util:conv_delay_driven({Time, repeat}),
                            {next_state, find_target, State#ob_act{object=NewMinfo, state_driven = StateDriven, path=RemainPath, o_point = {X, Y}, w_point = {NextX, NextY}}}
                    end
            end;
        _ ->
            NewState = mon_state_util:update_state_driven(State, {500, repeat}),
            {next_state, sleep, NewState}
    end.

%% 回收单个假人对应的进程字典数据
terminate_gc_proc_dict(_DummyId) ->
    ok.