%% ---------------------------------------------------------------------------
%% @doc lib_scene_object
%% @author ming_up@foxmail.com
%% @since  2017-02-06
%% @deprecated  场景对象公共接口
%% ---------------------------------------------------------------------------
-module(lib_scene_object).

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

-export([
        sync_create_a_dummy/9,
        async_create_a_dummy/9
    ]).

%% 对外接口
-export([
        sync_create_object/10           %% 同步创建场景对象
        , async_create_object/10        %% 异步创建场景对象
        , async_create_objects/5         %% 批量异步创建场景对象
        , send_object_move_msg/3        %% 发送场景对象走路协议
        , insert_object/2
        , get_scene_object_battle_attr_by_ids/4     %% 按格式返回对象的战斗属性
        , change_attr_by_ids/4          %% %% 更新场景对象属性
        , change_attr_by_mids/5
        % , apply_info/6                   %% 怪物进程info方式执行MFA
        , clear_scene_object/5           %% 清理场景所有对象
        , kill_scene_object/4            %% 杀死场景怪物
        , clear_scene_object_by_ids/4    %% 根据场景对象id清理
        , force_broad_cast_mon_hp/1
        , pack_scene_object_bin/1       %% 打包场景对象数据为二进制数据
    ]).

%% 对场景怪物模块内部接口
-export(
    [
        change_xy/1,
        remove/1,
        remove/3,
        lookup/3,
        insert/1,
        insert/3,
        update/2,
        delete/1,
        delete/3,
        put_ai/7,
        del_ai/3,
        del_all_area/3,
        broadcast_object/1,
        scene_broadcast_object/2,
        broadcast_object_attr/2,
        change_attr_broadcast/3,
        stop/2,
        die/2,
        set_args/5
    ]
).

%% @doc Args参数参考 lib_scene_object:set_args/4

%% 生成一个玩家镜像
%% retrun: DummyId
sync_create_a_dummy(SceneId, ScenePoolId, X, Y, CopyId, BroadCast, Figure, BattleAttr, Args) ->
    Args1 = [{figure, Figure}, {battle_attr, init_battle_attr(BattleAttr)}] ++ Args,
    sync_create_object(?BATTLE_SIGN_DUMMY, 0, SceneId, ScenePoolId, X, Y, 1, CopyId, BroadCast, Args1).

%% 异步生成一个玩家镜像
async_create_a_dummy(SceneId, ScenePoolId, X, Y, CopyId, BroadCast, Figure, BattleAttr, Args) ->
    Args1 = [{figure, Figure}, {battle_attr, init_battle_attr(BattleAttr)}] ++ Args,
    async_create_object(?BATTLE_SIGN_DUMMY, 0, SceneId, ScenePoolId, X, Y, 1, CopyId, BroadCast, Args1),
    ok.

%% 同步创建怪物
%% @spec sync_create_object(Type, MonId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args) -> MonAutoId
%% @param ObjectType ?BATTLE_SIGN_MON|?BATTLE_SIGN_PARTNER...
%% @param ConfigId 配置ID
%% @param Scene 场景ID
%% @param ScenePoolId 场景进程id
%% @param X 坐标
%% @param X 坐标
%% @param Type       怪物战斗类型（0被动，1主动）
%% @param CopyId     房间号ID 为0时，普通房间，非0值切换房间。值相同，在同一个房间。
%% @param BroadCast  是否出生时广播（0不广播，1广播）
%% @param Args       其余动态创建属性
%%                   = list() = [Tuple1, Tuple2...]
%%            Tuple1 = tuple(), {auto_lv, V} | {group, V}
%% @return MonAutoId 怪物自增ID，每个怪物唯一
%% @end
% sync_create_object(ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args) ->
%     case mod_scene_agent:apply_call(Scene, ScenePoolId, mod_scene_object_create, create_object,
%             [ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args]) of
%         Id when is_integer(Id) -> Id;
%         _Retrun -> 0
%     end.
%% 只要get_scene_pid以确保场景创建即可
%% （场景是基础设施，认为场景一定可正常启动），
%% 不必通过场景进程中转消息来创建怪物，可以减少场景收到的消息
sync_create_object(ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args) ->
    case mod_scene_agent:get_scene_pid(Scene, ScenePoolId) of
        undefined -> 0;
        clusters  ->
            clusters_node:apply_call(
                ?MODULE, sync_create_object, [
                    ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args
                ]
            );
        _Pid ->
            case mod_scene_object_create:create_object(
                    ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args
                ) of
                Id when is_integer(Id) -> Id;
                _ -> 0
            end
    end.

%% 异步场景对象
%% @spec async_create_object(Type, MonId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args) -> ok.
%% @end
% async_create_object(ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args) ->
%     mod_scene_agent:apply_cast(Scene, ScenePoolId, mod_scene_object_create, create_object_cast, [ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args]).
%% 只要get_scene_pid以确保场景创建即可
%% （场景是基础设施，认为场景一定可正常启动），
%% 不必通过场景进程中转消息来创建怪物，可以减少场景收到的消息
async_create_object(ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args) ->
    case mod_scene_agent:get_scene_pid(Scene, ScenePoolId) of
        undefined -> error;
        clusters  ->
            clusters_node:apply_cast(
                ?MODULE, async_create_object, [
                    ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args
                ]
            );
        _Pid ->
            mod_scene_object_create:create_object_cast(
                ObjectType, ConfigId, Scene, ScenePoolId, X, Y, Type, CopyId, BroadCast, Args
            )
    end.

%% 插入一只怪
insert_object(State, Args) ->
    #ob_act{object = #scene_object{scene = Scene, scene_pool_id = ScenePoolId}} = State,
    case mod_scene_agent:get_scene_pid(Scene, ScenePoolId) of
        undefined -> error;
        clusters  ->
            clusters_node:apply_cast(
                ?MODULE, insert_object, [
                    State, Args
                ]
            );
        _Pid ->
            mod_scene_object_create:insert_object(
                State, Args
            )
    end.

%% 批量异步创建对象
% async_create_objects(Scene, ScenePoolId, CopyId, Broadcast, List) ->
%     mod_scene_agent:apply_cast(Scene, ScenePoolId, mod_scene_object_create, create_more_cast, [Scene, ScenePoolId, CopyId, Broadcast, List]).
async_create_objects(Scene, ScenePoolId, CopyId, Broadcast, List) ->
    case mod_scene_agent:get_scene_pid(Scene, ScenePoolId) of
        undefined -> error;
        clusters  ->
            clusters_node:apply_cast(
                ?MODULE, async_create_objects, [
                    Scene, ScenePoolId, CopyId, Broadcast, List
                ]
            );
        _Pid ->
            mod_scene_object_create:create_more_cast(
                Scene, ScenePoolId, CopyId, Broadcast, List
            )
    end.

%% 按格式返回对象的战斗属性
%% SceneId    = int()           场景id
%% Ids        = list()          怪物唯一Id列表
%% ResultForm = list()          [#battle_attr.xx1, #battle_attr.xx2...] | all | #battle_attr.xx1 属性组装列表或者单项属性, 复合属性暂不支持
get_scene_object_battle_attr_by_ids(SceneId, ScenePoolId, Ids, ResultForm) ->
    mod_scene_agent:apply_call(SceneId, ScenePoolId, lib_scene_object_agent, get_scene_object_battle_attr_by_ids, [Ids, ResultForm]).

%% 更新场景对象属性
change_attr_by_ids(Scene, ScenePoolId, Ids, KeyValues) ->
    mod_scene_agent:apply_cast(Scene, ScenePoolId, lib_scene_object_agent, change_attr_by_ids, [Ids, KeyValues]).

%% 更新场景对象属性
change_attr_by_mids(Scene, ScenePoolId, CopyId, Ids, KeyValues) ->
    mod_scene_agent:apply_cast(Scene, ScenePoolId, lib_scene_object_agent, change_attr_by_mids, [CopyId, Ids, KeyValues]).

% 不应该通过场景中转消息，多余
% %% 怪物进程info方式执行MFA
% %% SceneId     = int()                场景id
% %% ScenePoolId = int()                场景进程id
% %% MonPid      = integer() | pid()    怪物唯一Id或者怪物进程pid
% %% Moudle      = atom()               模块名
% %% Method      = atom()               方法名
% %% Args        = term()               方法实参
% apply_info(SceneId, ScenePoolId, MonPid, Moudle, Method, Args) ->
%     case misc:is_process_alive(MonPid) of
%         true  ->
%             mod_scene_agent:apply_cast(SceneId, ScenePoolId, erlang, send, [MonPid, {'mod', Moudle, Method, Args}]);
%         false when is_integer(MonPid) ->
%             mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, apply_info, [MonPid, Moudle, Method, Args]);
%         _ -> skip
%     end,
%     ok.

%% 清除全场景的怪物
%% Sign       = 0|?BATTLE_SIGN_MON | ?BATTLE_SIGN_PARTNER...
%% SceneId    = int()                 场景ID
%% CopyId     = int() | pid()         房间id,不分房间清理时置为 []
%% BroadCast  = 0 | 1                 是否需要在清除的时候广播(0不广播，1广播)
clear_scene_object(Sign, SceneId, ScenePoolId, CopyId, BroadCast) ->
    mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, clear_scene_object, [Sign, CopyId, BroadCast]),
    ok.

%% 杀死场景怪物
kill_scene_object(Sign, SceneId, ScenePoolId, CopyId) ->
    mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, kill_scene_object, [Sign, CopyId]),
    ok.

%% 清除id怪物
%% SceneId    = int()                 场景ID
%% BroadCast  = 0 | 1                 是否需要在清除的时候广播(0不广播，1广播)
%% Ids        = list()                怪物唯一Id列表 #scene_object.id
clear_scene_object_by_ids(SceneId, ScenePoolId, BroadCast, Ids) ->
    mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, clear_scene_object_by_ids, [BroadCast, Ids]),
    ok.

%% 场景对象移动
change_xy(#scene_object{id=ObjectId, scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=X, y=Y}) ->
    mod_scene_agent:cast_to_scene(Scene, ScenePoolId, {'scene_object_move', CopyId, X, Y, ObjectId}).

%% 清除场景对象
remove(#scene_object{id=ObjectId, aid=ObjectPid, scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=X, y=Y} = Object) ->
    case is_pid(ObjectPid) of
        true  -> mod_scene_agent:apply_cast(Scene, ScenePoolId, erlang, send, [ObjectPid, 'stop']);
        false -> delete(Object)
    end,
    {ok, BinData} = pt_120:write(12006, ObjectId),
    broad_cast(Scene, ScenePoolId, CopyId, X, Y, BinData),
    ok.
remove(Scene, ScenePoolId, MonId) ->
    case lookup(Scene, ScenePoolId, MonId) of
        [] -> ok;
        Object -> remove(Object)
    end.

%% 查找指定对象信息
lookup(Scene, ScenePoolId, IdList) when is_list(IdList) ->
    mod_scene_agent:apply_call(Scene, ScenePoolId, lib_scene_object_agent, get_object, [IdList]);
lookup(Scene, ScenePoolId, Id) ->
    mod_scene_agent:apply_call(Scene, ScenePoolId, lib_scene_object_agent, get_object, [Id]).

%% 修改或者插入数据
insert(Object) ->
    mod_scene_agent:apply_cast(Object#scene_object.scene, Object#scene_object.scene_pool_id, lib_scene_object_agent, put_object, [Object]).

insert(Scene, ScenePoolId, Object) ->
    mod_scene_agent:apply_cast(Scene, ScenePoolId, lib_scene_object_agent, put_object, [Object]).

update(Object, KeyValues) ->
    mod_scene_agent:apply_cast(Object#scene_object.scene, Object#scene_object.scene_pool_id, lib_scene_object_agent, update, [Object#scene_object.id, KeyValues]).

delete(Object) ->
    mod_scene_agent:apply_cast(Object#scene_object.scene, Object#scene_object.scene_pool_id, lib_scene_object_agent, del_object, [Object#scene_object.id]).
delete(Scene, ScenePoolId, Id) ->
    mod_scene_agent:apply_cast(Scene, ScenePoolId, lib_scene_object_agent, del_object, [Id]).

%% 写入警戒区
put_ai(MonId, SceneId, ScenePoolId, CopyId, X, Y, WaringRange) ->
    mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, do_for_trace, [MonId, CopyId, WaringRange, X, Y, 1]).

%% 删除警戒区
del_ai(SceneId, ScenePoolId, CopyId) ->
    mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, del_trace, [CopyId]).

%% 删除9宫格数据
del_all_area(SceneId, ScenePoolId, CopyId) ->
    mod_scene_agent:apply_cast(SceneId, ScenePoolId, lib_scene_object_agent, del_all_area, [CopyId]).

%% 广播对象移动协议
send_object_move_msg(Oldx, Oldy, Object)->
    #scene_object{id = Id, scene = SceneId, scene_pool_id=ScenePoolId, copy_id = CopyId, x = X, y = Y} = Object,
    %% 告诉玩家有怪物移动
    {ok, BinData}  = pt_120:write(12008, [X, Y, Id]),
    % 告诉玩家有怪物被移除
    {ok, BinData1} = pt_120:write(12006, Id),
    %% 告诉玩家有怪物移动进入
    BinData2 = pack_scene_object_bin(Object),
    case lib_scene:is_broadcast_scene(SceneId) of
        true ->
            lib_server_send:send_to_scene(SceneId, ScenePoolId, CopyId, BinData);
        false ->
            mod_scene_agent:apply_cast(SceneId, ScenePoolId,
                lib_scene_calc, move_broadcast,
                [SceneId, CopyId, X, Y, Oldx, Oldy, BinData, BinData1, BinData2, []]
            )
    end.

% old:
% %% 取消定时器和发送新的定时器消息
% send_event_after(Ref, Time, Msg) ->
%     util:cancel_timer(Ref),
%     R = gen_fsm:send_event_after(Time, Msg),
%     R.

%% 广播场景对象出现
broadcast_object(#scene_object{scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=Xpx, y=Ypx}=Object) ->
    BinData = pack_scene_object_bin(Object),
    broad_cast(Scene, ScenePoolId, CopyId, Xpx, Ypx, BinData).

scene_broadcast_object(#scene_object{scene=Scene, copy_id=CopyId, x=Xpx, y=Ypx}=Object, BroadCast) ->
    BinData = pack_scene_object_bin(Object),
    scene_broad_cast(Scene, CopyId, Xpx, Ypx, BinData, BroadCast).

%% 广播场景对象属性更新
broadcast_object_attr(#scene_object{id=Id, scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=Xpx, y=Ypx}, AttrKeyValues) ->
    if
        length(AttrKeyValues) > 0 ->
            {ok, BinData} = pt_120:write(12080, [Id, AttrKeyValues]),
            broad_cast(Scene, ScenePoolId, CopyId, Xpx, Ypx, BinData);
        true ->
            ok
    end.

change_attr_broadcast([], SceneObject, UpList) ->
    broadcast_object_attr(SceneObject, UpList);
change_attr_broadcast([{restore_hp}|L], SceneObject, UpList) ->
    #scene_object{battle_attr = BattleAttr} = SceneObject,
    change_attr_broadcast(L, SceneObject, [{5, BattleAttr#battle_attr.hp}|UpList]);
change_attr_broadcast([{hp, _Hp}|L], SceneObject, UpList) ->
    #scene_object{battle_attr = BattleAttr} = SceneObject,
    change_attr_broadcast(L, SceneObject, [{5, BattleAttr#battle_attr.hp}|UpList]);
change_attr_broadcast([{pk_protect_time, Time}|L], SceneObject, UpList) ->
    change_attr_broadcast(L, SceneObject, [{6, Time}|UpList]);
change_attr_broadcast([{is_be_atted, Val}|L], SceneObject, UpList) ->
    change_attr_broadcast(L, SceneObject, [{3, Val}|UpList]);
change_attr_broadcast([{change_speed, Value}|L], SceneObject, UpList) ->
    #scene_object{id=Id, scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=Xpx, y=Ypx, sign = Sign} = SceneObject,
    {ok, BinData} = pt_120:write(12082, [Sign, Id, Value]),
    broad_cast(Scene, ScenePoolId, CopyId, Xpx, Ypx, BinData),
    change_attr_broadcast(L, SceneObject, UpList);
change_attr_broadcast([{mon_name, Value}|L], SceneObject, UpList) ->
    #scene_object{id=Id, scene=Scene, scene_pool_id=ScenePoolId, copy_id=CopyId, x=Xpx, y=Ypx} = SceneObject,
    {ok, BinData} = pt_120:write(12090, [Id, [{1, 0, Value}]]),
    broad_cast(Scene, ScenePoolId, CopyId, Xpx, Ypx, BinData),
    change_attr_broadcast(L, SceneObject, UpList);
change_attr_broadcast([{lv, Value}|L], SceneObject, UpList) ->
    change_attr_broadcast(L, SceneObject, [{7, Value}|UpList]);

change_attr_broadcast([_T|L], SceneObject, UpList) ->
    change_attr_broadcast(L, SceneObject, UpList).

%% 打包场景对象
pack_scene_object_bin(#scene_object{sign=Sign} = Object) ->
    case Sign of
        ?BATTLE_SIGN_MON ->
            {ok, BinData} = pt_120:write(12007, Object),
            BinData;
        ?BATTLE_SIGN_DUMMY ->
            {ok, BinData} = pt_120:write(12015, Object),
            BinData;
        _ ->
            {ok, BinData} = pt_120:write(12014, Object),
            BinData
    end.

%% 移除场景对象(Broadcast:0不广播|1广播)
stop(Object, Broadcast) ->
    #scene_object{scene = SceneId, scene_pool_id = ScenePoolId} = Object,
    case mod_scene_agent:get_alive_pid(SceneId, ScenePoolId) of
        Pid when is_pid(Pid) ->
            delete(Object),
            case Broadcast of
                1 ->
                    {ok, BinData} = pt_120:write(12006, Object#scene_object.id),
                    broad_cast(SceneId, ScenePoolId, Object#scene_object.copy_id, Object#scene_object.x, Object#scene_object.y, BinData);
                _ -> skip
            end;
        _ -> skip
    end.

%% 杀死怪物
die(Object, Broadcast) ->
    #scene_object{scene = SceneId, scene_pool_id = ScenePoolId} = Object,
    delete(Object),
    case Broadcast of
        1 ->
            {ok, BinData} = pt_120:write(12027, Object#scene_object.id),
            broad_cast(SceneId, ScenePoolId, Object#scene_object.copy_id, Object#scene_object.x, Object#scene_object.y, BinData);
        _ -> skip
    end.

%% 设置场景对象参数
set_args([H|T], State, StateName, Broadcast, UpList) ->
    #ob_act{object = SceneObject} = State,
    [NewObj, UpList1] =
        case H of
            {aid, Aid} ->
                [ SceneObject#scene_object{aid = Aid}, [H|UpList] ];
            {skill_owner, SkillOwner} ->
                [ SceneObject#scene_object{skill_owner = SkillOwner}, [H|UpList] ];
            {skill_owner_team_id, TeamId} ->
                SkillOwner = SceneObject#scene_object.skill_owner,
                case Broadcast of
                    1 ->
                        {ok, BinData} = pt_120:write(12080, [SceneObject#scene_object.id, [{2, TeamId}] ]),
                        lib_server_send:send_to_area_scene(
                            SceneObject#scene_object.scene,
                            SceneObject#scene_object.scene_pool_id,
                            SceneObject#scene_object.copy_id,
                            SceneObject#scene_object.x,
                            SceneObject#scene_object.y,
                            BinData
                        );
                    _ -> skip
                end,
                NewSkillOwner = SkillOwner#skill_owner{team_id=TeamId},
                [ SceneObject#scene_object{skill_owner = NewSkillOwner}, [{skill_owner, NewSkillOwner}|UpList] ];
            {figure, Value} ->
                [ SceneObject#scene_object{figure=Value}, [H|UpList] ];
            {lv, Value} ->
                Figure=SceneObject#scene_object.figure#figure{lv=Value},
                [ SceneObject#scene_object{figure=Figure}, [{figure, Figure}|UpList] ];
            {battle_attr, Value} ->
                [ SceneObject#scene_object{battle_attr=Value}, [H|UpList] ];
            {speed, Value} ->
                BA = SceneObject#scene_object.battle_attr,
                NewBA = BA#battle_attr{speed=Value},
                [ SceneObject#scene_object{battle_attr=NewBA}, [{battle_attr, NewBA}|UpList] ];
            {group, Value} ->
                BA = SceneObject#scene_object.battle_attr,
                NewBA = BA#battle_attr{group=Value},
                [ SceneObject#scene_object{battle_attr=NewBA}, [{battle_attr, NewBA}|UpList] ];
            {skill, Value} ->
                F = fun({SkillId, Lv}) ->
                        case data_skill:get(SkillId, Lv) of
                            #skill{type=Type} when Type == ?SKILL_TYPE_ACTIVE orelse Type == ?SKILL_TYPE_ASSIST -> true;
                            _ -> false
                        end
                end,
                Skill = lists:filter(F, Value),
                [ SceneObject#scene_object{skill = Skill}, [{filter_skill, Skill}|UpList] ];
            {skill_passive, Value} ->
                F = fun({SkillId, Lv}) ->
                        case data_skill:get(SkillId, Lv) of
                            #skill{type=Type} when Type == ?SKILL_TYPE_PASSIVE -> true;
                            _ -> false
                        end
                end,
                SkillPassive = lists:filter(F, Value),
                [ SceneObject#scene_object{skill_passive = SkillPassive}, [{skill_passive, SkillPassive}|UpList] ];
            {mod_args, Value} ->
                [ SceneObject#scene_object{mod_args = Value}, [H|UpList] ];
            {find_target, Value} ->
                mon_mgr:send_after(Value, SceneObject#scene_object.aid, SceneObject#scene_object.id, 'find_target'),
                [SceneObject, UpList];
            {pos, Pos} ->
                %% 带阵法属性
                [ SceneObject#scene_object{pos = Pos}, [H|UpList] ];
            {dummy, Dummy} ->
                [ SceneObject#scene_object{dummy = Dummy}, [{dummy, Dummy}|UpList] ];
            {hp, Value} ->
                BA = SceneObject#scene_object.battle_attr,
                NewBA = BA#battle_attr{hp=Value},
                [ SceneObject#scene_object{battle_attr=NewBA}, [{battle_attr, NewBA}|UpList] ];
            {type, Value} ->
                [SceneObject#scene_object{type = Value}, UpList];
            {warning_range, Value} ->
                [SceneObject#scene_object{warning_range = Value}, UpList];
            {tracing_distance, Value} ->
                [SceneObject#scene_object{tracing_distance = Value}, UpList];
            {ghost, Value} ->
                BA = SceneObject#scene_object.battle_attr,
                NewBA = BA#battle_attr{ghost = Value},
                [SceneObject#scene_object{battle_attr = NewBA}, [{battle_attr, NewBA}|UpList]];
            {combat_power, Value} ->
                [SceneObject#scene_object{combat_power = Value}, UpList];
            {attr_r, Value} ->
                BattleAttr = SceneObject#scene_object.battle_attr,
                Attr = BattleAttr#battle_attr.attr,
                AttrList = attr_conv:to_attr_tuple_list(Attr),
                BaseAttrList = lib_player_attr:get_list_base_attr_kv(AttrList),
                NewBaseAttrList = lib_player_attr:set_attr_by_ratio(lists:keydelete(?HP, 1, BaseAttrList), Value),
                NewBattleAttr = lib_player_attr:set_battle_attr(BattleAttr, NewBaseAttrList),
                #battle_attr{hp = Hp, hp_lim = HpLim} = BattleAttr,
                NewHp = round(Hp * Value / ?RATIO_MAX),
                NewHpLim = round(HpLim * Value / ?RATIO_MAX),
                LastBattleAttr = NewBattleAttr#battle_attr{hp = NewHp, hp_lim = NewHpLim},
                [SceneObject#scene_object{battle_attr = LastBattleAttr}, [{battle_attr, LastBattleAttr}|UpList]];
            {attr_list, Value} ->
                BattleAttr = SceneObject#scene_object.battle_attr,
                NewBattleAttr = lib_player_attr:set_battle_attr(BattleAttr, Value),
                [ SceneObject#scene_object{battle_attr = NewBattleAttr}, [{attr_list, Value}|UpList] ];
            {cannot_beatt_list, Value} ->
                [ SceneObject#scene_object{cannot_beatt_list=Value}, [{cannot_beatt_list, Value}|UpList] ];
            _Other ->
                [SceneObject, UpList]
        end,
        NewSN =
            case H of
            {state, TmpSN} -> TmpSN;
            _ -> StateName
        end,
        NewState =
            case H of
                {die_handler, ObValue} ->
                    State#ob_act{die_handler = ObValue};
                {born_handler, ObValue} ->
                    State#ob_act{born_handler = ObValue};
                {change_scene_handler, ObValue} ->
                    State#ob_act{change_scene_handler = ObValue};
                {offline_hosting, ObValue} ->
                    State#ob_act{offline_hosting = ObValue};
                {check_block, ObValue} ->
                    State#ob_act{check_block = ObValue};
                {path, ObValue} ->
                    State#ob_act{path = ObValue};
                {revive_time, ObValue} ->
                    State#ob_act{revive_time = ObValue};
                {find_type, ObValue} ->
                    State#ob_act{find_type = ObValue};
                {stay_dead, ObValue} ->
                    State#ob_act{stay_dead = ObValue};
                {delay_cost_value, ObValue} ->
                    offline_hosting_dummy:delay_cost_value(State, ObValue);
                _ ->
                    State
            end,
        LastState = NewState#ob_act{object=NewObj},
    set_args(T, LastState, NewSN, Broadcast, UpList1);
set_args(_, State, StateName, _, UpList) -> {State, StateName, UpList}.

%% 初始化场景对象battle_attr的一些中间状态
init_battle_attr(BattleAttr) ->
    Attr = BattleAttr#battle_attr.attr,
    BattleAttr#battle_attr{
        hp              = BattleAttr#battle_attr.hp_lim,
        skill_effect    = #skill_effect{},
        attr            = Attr#attr{speed = ?SPEED_VALUE},
        speed           = ?SPEED_VALUE,
        attr_buff_list  = [],
        other_buff_list = [],
        ghost           = 0,
        hide            = 0
    }.

%% 广播怪物血量
force_broad_cast_mon_hp(Mon) ->
    #scene_object{id = Id, battle_attr = #battle_attr{hp = Hp, hp_lim = HpLim},
        scene = Scene, scene_pool_id = ScenePoolId, copy_id = CopyId} = Mon,
    {ok, BinData} = pt_120:write(12009, [Id, Hp, HpLim]),
    case lib_scene:is_force_broadcast_scene(Scene) of
        true  ->
            mod_scene_agent:send_to_scene(Scene, ScenePoolId, CopyId, BinData);
        false ->
            ok
    end.

broad_cast(Scene, ScenePoolId, CopyId, Xpx, Ypx, BinData) ->
    case lib_scene:is_broadcast_scene(Scene) of
        true ->
            mod_scene_agent:send_to_scene(Scene, ScenePoolId, CopyId, BinData);
        false ->
            case lib_scene:is_force_broadcast_scene(Scene) of
                true  ->
                    mod_scene_agent:send_to_scene(Scene, ScenePoolId, CopyId, BinData);
                false ->
                    mod_scene_agent:send_to_area_scene(Scene, ScenePoolId, CopyId, Xpx, Ypx, BinData)
            end
    end.

scene_broad_cast(Scene, CopyId, X, Y, BinData, BroadCast) ->
    case lib_scene:is_broadcast_scene(Scene) of
        true ->
            lib_scene_agent:send_to_local_scene(CopyId, BinData);
        false ->
            %% 只对某些消息进行强制广播,上层调用接口自行修改参数。默认为0
            case BroadCast of
                1 ->
                    lib_scene_agent:send_to_local_scene(CopyId, BinData);
                _ ->
                    lib_scene_agent:send_to_local_area_scene(CopyId, X, Y, BinData)
            end
    end.
