%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%
%%% @end
%%%-------------------------------------------------------------------
-module(drop).
-author("liushl").

-include("scene.hrl").
-include("figure.hrl").
-include("drop.hrl").
-include("battle.hrl").
-include("team.hrl").
-include("def_fun.hrl").
-include("predefine.hrl").
-include("common.hrl").
-include("server.hrl").
-include("dungeon.hrl").
-include("def_goods.hrl").
-include("goods.hrl").
%% API
-export([]).
-compile(export_all).

%% 怪物死亡后触发掉落
mon_drop(MonsterInfo, Killer, KList, FirstAttacker) ->
    #scene_object{
        id = MonAutoId, scene = ObjectScene, scene_pool_id = ObjectPoolId, mod_args = ModArgs,
        copy_id = ObjectCopyId, x = X, y = Y, mon = Mon, figure = Figure, origin = Origin
    } = MonsterInfo,
    MonArgs = #mon_args{
        id = MonAutoId, mid = Mon#scene_mon.mid, kind = Mon#scene_mon.kind, lv = Figure#figure.lv,
        ctime = Mon#scene_mon.ctime, boss = Mon#scene_mon.boss, scene = ObjectScene, origin = Origin,
        scene_pool_id = ObjectPoolId, copy_id = ObjectCopyId, x = X, y = Y, name = Figure#figure.name
    },
    DropCount =
        case is_map(ModArgs) of
            true  ->
                maps:get(?DROP_MERGE_MULTI_COUNT, ModArgs, 1);
            false ->
                1
        end,
    [
        case data_drop:get_rule(MonArgs#mon_args.mid, Alloc, Figure#figure.lv) of
            #ets_drop_rule{bltype = BLType} ->
                alloc_drop_core(Alloc, BLType, MonArgs, Killer, KList, FirstAttacker, DropCount);
            _ ->
                ignore
        end
        || Alloc <- data_drop:get_rule_list(Mon#scene_mon.mid)
    ].

%% 需要先发到玩家进程去，判断一些掉落BUFF加成
%% 分配方式：个人独占
%% 个人独占的情形会有合并次数多次掉落的处理
alloc_drop_core(Alloc = ?ALLOC_ONESELF, _BLType, MonArgs, Killer, _KList, _FirstAttacker, DropCount) ->
    lib_player:apply_cast(Killer#battle_return_atter.node, Killer#battle_return_atter.id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_drop_list, [MonArgs, Alloc, [], DropCount]);

%% 分配方式：均等分配/无归属，则伤害列表每人一份奖励。此时，一般不可处理多份掉落
alloc_drop_core(Alloc = ?ALLOC_EQUAL, ?DROP_NO_ONE, MonArgs, _Killer, KList, _FirstAttacker, _DropCount) ->
    [
        lib_player:apply_cast(Atter#mon_atter.node, Atter#mon_atter.id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_drop_list, [MonArgs, Alloc, [Atter], 1])
        || Atter<- KList
    ];
%% 分配方式：均等分配/有归属，则归属者每人一份奖励。此时，一般不可处理多份掉落
alloc_drop_core(Alloc = ?ALLOC_EQUAL, BLType, MonArgs, _Killer, KList, FirstAttacker, _DropCount) ->
    {_, _, Belong} = calc_boss_bl_who(Alloc, BLType, [], KList, FirstAttacker, 0),
    [
        lib_player:apply_cast(Atter#mon_atter.node, Atter#mon_atter.id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_drop_list, [MonArgs, Alloc, [Atter], 1])
        || Atter<- Belong
    ];

%% 分配方式：先到先得/无归属，则只有一份掉落，经由击杀者判断。此时，一般不可处理多份掉落
alloc_drop_core(Alloc = ?ALLOC_HANDSPEED, ?DROP_NO_ONE, MonArgs, Killer, KList, _FirstAttacker, _DropCount) ->
    lib_player:apply_cast(Killer#battle_return_atter.node, Killer#battle_return_atter.id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_drop_list, [MonArgs, Alloc, KList, 1]);

%% 分配方式：先到先得/有归属，则只有一份掉落。此时，一般不可处理多份掉落
%% ！！！这个情形就不能限制单个玩家无掉落，因为在组队的情形下是会到队伍某个玩家进程去的
alloc_drop_core(Alloc = ?ALLOC_HANDSPEED, BLType, MonArgs, _Killer, KList, FirstAttacker, _DropCount) ->
    {_, _, Belong} = calc_boss_bl_who(Alloc, BLType, [], KList, FirstAttacker, 0),
    case Belong of
        [#mon_atter{id = RoleId, team_id = DropTeamId, node = Node}|_] ->
            if
                DropTeamId > 0 ->
                    %% 有队伍，则需要经队伍管理转发，找到队员中的掉率加成
                    %% 目前队伍只有本服才有，所以先发送到队员本服去处理
                    case Node == none of
                        true  ->
                            mod_team:cast_to_team(DropTeamId, {'alloc_drop', MonArgs, Alloc, Belong, KList});
                        false ->
                            clusters_api:rpc_cast_do_mfa(Node,
                                {mod_team, cast_to_team, [DropTeamId, {'alloc_drop', MonArgs, Alloc, Belong, KList}]})
                    end;
                true ->
                    if MonArgs#mon_args.boss == ?MON_DESERTED_BOSS ->
                            lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_deserted_drop_list, [MonArgs, Alloc, KList, 1]);
                        true ->
                            lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_drop_list, [MonArgs, Alloc, KList, 1])
                    end
            end;
        _ ->
            ignore
    end;
alloc_drop_core(Alloc, BLType, _MonArgs, _Killer, _KList, _FirstAttacker, _DropCount) ->
    ?ERR("unkown alloc:~p~n", [{Alloc, BLType}]),
    skip.

%% 分配方式：先到先得
alloc_drop_in_team(MonArgs, Alloc = ?ALLOC_HANDSPEED, TeamHurts, _KList, Ratio) ->
    [Atter|_] = TeamHurts,
    if MonArgs#mon_args.boss == ?MON_DESERTED_BOSS ->
            [lib_player:apply_cast(Node, RoleId, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE,
                deserted_boss_act_limit_drop_goods, [MonArgs, RoleLv]) || #mon_atter{node = Node, id = RoleId, att_lv = RoleLv} <- TeamHurts ];
        true -> skip
    end,
    lib_player:apply_cast(Atter#mon_atter.node, Atter#mon_atter.id, ?APPLY_CAST_STATUS, ?NOT_HAND_OFFLINE, ?MODULE, handle_drop_list, [MonArgs, Alloc, TeamHurts, Ratio, 1]);
%% 分配方式：先到先得
alloc_drop_in_team(_MonArgs, _Alloc, _TeamHurts, _KList, _Ratio) -> ignore.

%% 处理星域幻魔限时掉落(有队伍)
deserted_boss_act_limit_drop_goods(Player, MonArgs, RoleLv) ->
    #mon_args{mid = MonId} = MonArgs,
    %% 计算限时掉落: 一般是必掉物品
    case drop_logic:calc_act_limit_drop_goods(MonArgs,RoleLv) of
        [#ets_drop_goods{goods_id = GoodsId, num = Num}|_] ->
            Player1 = lib_goods_api:send_reward(Player, [{?TYPE_GOODS, GoodsId, Num}], mon_drop, MonId),
            {ok, Player1};
        _A ->
            ok
    end.

%% 处理星域幻魔特殊掉落(无队伍)
handle_deserted_drop_list(Player, MonArgs, Alloc, DropRoles, DropCount) ->
    Player1 = handle_drop_list(Player, MonArgs, Alloc, DropRoles, 0, DropCount),
    case deserted_boss_act_limit_drop_goods(Player1, MonArgs, Player1#player_status.figure#figure.lv) of
        {ok, Player2} ->
            {ok, Player2};
        _ ->
            {ok, Player1}
    end.

%% 玩家进程处理掉落, 无组队加成
handle_drop_list(Player, MonArgs, Alloc, DropRoles, DropCount) ->
    handle_drop_list(Player, MonArgs, Alloc, DropRoles, 0, DropCount).

%% 处理合并次数的多次掉落
%% 一般情况下，只有个人归属的情况下会处理合并次数
%% 比如：个人幻魔/讨伐副本每人一份奖励
handle_drop_list(Player, _MonArgs, _Alloc, _DropRoles, _TeamBuff, 0) ->
    Player;
handle_drop_list(Player, MonArgs, Alloc, DropRoles, TeamBuff, DropCount) ->
    NewPlayer = handle_drop_list_do(Player, MonArgs, Alloc, DropRoles, TeamBuff),
    handle_drop_list(NewPlayer, MonArgs, Alloc, DropRoles, TeamBuff, DropCount - 1).

%% 掉落逻辑
handle_drop_list_do(Player, MonArgs, Alloc, DropRoles, TeamBuff) ->
    #mon_args{mid = MonId} = MonArgs,
    DropRule = data_drop:get_rule(MonId, Alloc, MonArgs#mon_args.lv),
    case is_can_drop(Player, MonArgs, DropRoles, DropRule) of
        false ->
            Player;
        true  ->
            #player_status{
                figure = #figure{career = Career, lv = RoleLv, turn = Turn},
                turn_task_id = TurnTaskId,
                scene = Scene,
                id = RoleId,
                team = #status_team{team_id = TeamId}
            } = Player,
            
            NDropList =
                case (MonId == 12010011 orelse MonId == 12010012)
                    andalso lib_task:is_during_task(11060) of
                    true when MonId == 12010011 ->
                        %% 前两个赏金BOSS新手任务定制掉落
                        NewerList = [2400201,2400301,101009,101014,102602,109031],
                        [data_drop:get_goods(Id)||Id<-NewerList];
                    true when MonId == 12010012 ->
                        %% 前两个赏金BOSS新手任务定制掉落
                        NewerList = [2400401,2400501,101009,101014,102602,109031],
                        [data_drop:get_goods(Id)||Id<-NewerList];
                    false ->
                        %% 计算基础掉落
                        {StableDropGoods, RandDropGoods} = drop_logic:calc_drop_goods(Player, MonArgs, DropRule, Career, TeamBuff, DropRoles),
                        %% 计算定制活动掉落：另外一份掉落规则
                        ActDropGoods = drop_logic:calc_act_drop_goods(MonArgs, Career),
                        %% 计算限时掉落: 一般是必掉物品(星域幻魔限时掉落不走这里)
                        if
                            MonArgs#mon_args.boss == ?MON_DESERTED_BOSS ->
                                LimitDropGoods = [];
                            true ->
                                LimitDropGoods = drop_logic:calc_act_limit_drop_goods(MonArgs,RoleLv)
                        end,
                        %% 计算其他活动掉落
                        %OtherActDrops = drop_logic:calc_other_act_drops(Player, MonArgs),
                        %% 副本双倍活动：正对固定掉落直接加倍
                        NewStableDropList = drop_logic:calc_multiple_act_drops(Player, MonArgs, StableDropGoods),
                        RandDropGoods ++ NewStableDropList ++ ActDropGoods ++ LimitDropGoods
                end,
      
            %% 任务掉落
            drop_logic:handle_item_task_event(Player, MonId, []),
            %% 刷选出符合条件的掉落
            CondArgs = #cond_args{lv = RoleLv, career = Career, turn = Turn, turn_task_id = TurnTaskId},
            TotalDropList0 = filter_drop_list_with_cond(CondArgs, NDropList),
            TotalDropList  = drop_logic:handle_color_goods_limit(Player, MonArgs, DropRoles, TotalDropList0),
            %% 判断掉落次数限制
            %% 拿到限制的当前物品掉落的个人和全服限制数量
            {PersonLimits, SerLimits, DropedCoin, DefCoinLimitCount}
                = drop_logic:get_drop_goods_limit(Player, TotalDropList),
            Args = {PersonLimits, SerLimits, DropedCoin, DefCoinLimitCount},
            %% {掉落金币数量, 玩家单个物品数量列表,全服掉落数量列表,允许掉落列表，已掉落金币}
            {CoinNum, PersonL, SererL, CanDrops, DropedCoin}
                = drop_logic:do_handle_drop_goods_limit(Player, TotalDropList, Args),
            %% 先记录次数
            drop_logic:update_daily_drop_count(Player, CoinNum, PersonL, SererL, DropedCoin, PersonLimits, SerLimits),
            %% 过滤一些直接发背包的道具：一般是活动掉落
            {SendBag, OthersRewards, FinalDropList} = filter_drop_to_bag(CanDrops),
            notice_drop_goods_to_bag(Player, SendBag, MonArgs),
            %% 橙装碎片调控处理
            TotalReward = SendBag ++ OthersRewards,
            drop_logic:check_adjust_equipment_chip_control(Player, TotalReward, MonArgs, DropRoles),
            
            Player1 = lib_goods_api:send_reward(Player, SendBag, mon_drop, MonId),
            %% 副本内通知副本进程，结算时需要展示
            case lib_dungeon:is_on_dungeon(Player) of
                true  ->
                    lib_dungeon_api:collect_mon_goods(Player#player_status.copy_id, Player#player_status.id, TotalReward);
                false ->
                    ignore
            end,

            %% 经验海记录掉落
            case exp_sea_logic:is_exp_sea_scene(Scene) of
                true -> exp_sea_logic:mon_drop(RoleId, TotalReward);
                _ -> ignore
            end,

            %% 采集怪直接发送背包
            case MonArgs#mon_args.kind =:= ?MON_KIND_COLLECT orelse MonArgs#mon_args.kind == ?MON_KIND_TASK_COLLECT of
                true  ->
                    lib_goods_api:send_reward(Player1, OthersRewards, mon_drop, MonArgs#mon_args.mid);
                false ->
                    IsCluster = lib_scene:is_clusters_scene(Scene),
                    RoleIdList = [{Atter#mon_atter.id, Atter#mon_atter.hurt, Atter#mon_atter.team_id}||Atter <- DropRoles],
                    case IsCluster of
                        true  ->
                            clusters_node:apply_cast(?MODULE, handle_drop_list_core,
                                [node(), RoleId, TeamId, MonArgs, DropRule, FinalDropList, RoleIdList]);
                        false ->
                            handle_drop_list_core(node(), RoleId, TeamId, MonArgs, DropRule, FinalDropList, RoleIdList)
                    end,
                    Player1
            end
    end.

%% 处理掉落物品列表: 跨服/本服通用处理
handle_drop_list_core(Node, RoleId, TeamId, MonArgs, DropRule, DropList, RoleIdList) ->
    ExpireTime = utime:unixtime() + ?DROP_ALIVE_TIME,
    #mon_args{scene = Scene, scene_pool_id = ScenePoolId, copy_id = CopyId, x = Mx, y = My} = MonArgs,
    Xys = calc_goods_drop_xy(Scene, ScenePoolId, CopyId, Mx, My, length(DropList)),
    %% 生成掉落包数据
    DropArgs = [RoleId, TeamId, MonArgs, DropRule, ExpireTime, [], Xys, RoleIdList],
    [_, _, _, _, _, DropBin, _, _] = lists:foldl(fun handle_drop_item/2, DropArgs, DropList),
    send_drop(Node, RoleId, MonArgs, DropRule, DropBin).

%% 依次处理每个掉落: 跨服/本服通用处理
handle_drop_item(DropGoods, [RoleId, TeamId, MonArgs, DropRule, ExpireTime, DropBin, Xys, RoleIdList]) ->
    #ets_drop_goods{drop_thing_type = DTType, goods_id = GoodsTypeId, drop_icon = DropIcon, bind = Bind1,
        num = GoodsNum, get_way = GetWay, notice = Notice, drop_leff = DropEff
    } = DropGoods,
    #ets_drop_rule{alloc = Alloc, bltype = BLType, broad = Broad} = DropRule,
    #mon_args{mid = MonId, name = MonName, scene = Scene,
        scene_pool_id = ScenePoolId, copy_id = CopyId, x = Mx, y = My, origin = Origin
    } = MonArgs,
    {DX, DY, LessXys} = ?IF(Xys == [], {Mx, My, []}, begin [{Dx, Dy}|LXys] = Xys, {Dx, Dy, LXys} end),
    Bind = if Bind1 > 0 -> ?BIND; true -> ?UNBIND end,
    DropId  = mod_drop:get_drop_id(),
    GoodsDrop = #ets_drop{
        id = DropId, scene = Scene, scene_pool_id = ScenePoolId, copy_id = CopyId,
        x = DX, y = DY, bltype = BLType, drop_thing_type = DTType, alloc = Alloc,
        goods_id = GoodsTypeId, num = GoodsNum, bind = Bind, drop_icon = DropIcon,
        get_way = GetWay, notice = Notice, broad = Broad, expire_time = ExpireTime,
        mon_id = MonId, mon_name = MonName, drop_leff = DropEff, origin = Origin,hurt_id_list = RoleIdList
    },
    if
        %% 个人独占、随机分配、 均等分配，这些都是只有一个人可以拾取
        Alloc == ?ALLOC_ONESELF orelse Alloc == ?ALLOC_RAND orelse Alloc == ?ALLOC_EQUAL ->
            NewGoodsDrop = GoodsDrop#ets_drop{player_id = RoleId};

        %% 先到先得 且无归属，任何人都可以拾取
        Alloc == ?ALLOC_HANDSPEED andalso BLType == ?DROP_NO_ONE ->
            NewGoodsDrop = GoodsDrop;

        %% 先到先得 有归属，一般是队伍玩家可拾取
        Alloc == ?ALLOC_HANDSPEED andalso BLType == ?DROP_HURT_MAX ->
            if
                TeamId > 0 ->
                    NewGoodsDrop = GoodsDrop#ets_drop{team_id = TeamId};
                true ->
                    NewGoodsDrop = GoodsDrop#ets_drop{player_id = RoleId}
            end;

        %% 容错，只有击杀者可拾取
        true ->
            NewGoodsDrop = GoodsDrop#ets_drop{player_id = RoleId}
    end,
    mod_drop:add_drop(NewGoodsDrop),
    BDropEff  = pt:write_string(DropEff),
    BDropIcon = pt:write_string(DropIcon),
    Bin = <<DropId:32, DTType:8, GoodsTypeId:32, GoodsNum:32, (NewGoodsDrop#ets_drop.player_id):64, DX:16, DY:16, BDropEff/binary, BDropIcon/binary>>,
    [RoleId, TeamId, MonArgs, DropRule, ExpireTime, [Bin|DropBin], LessXys, RoleIdList].

filter_drop_to_bag(DropList) ->
    lists:foldl(
        fun(#ets_drop_goods{drop_thing_type = DTType, goods_id = GoodsTypeId, bind = Bind, num = GoodsNum} = One, {Send, Others, Drop}) ->
            FixType =
                case DTType =:= ?TYPE_GOODS andalso Bind =:= ?BIND of
                    true  -> ?TYPE_BIND_GOODS;
                    false -> DTType
                end,
            case data_drop_limit:get_goods_limit(FixType, GoodsTypeId) of
                #base_drop_limit{limit_type = ?DROP_LIMIT_GOODID} ->
                    {[{FixType, GoodsTypeId, GoodsNum}|Send], Others, Drop};
                _ ->
                    {Send, [{FixType, GoodsTypeId, GoodsNum}|Others], [One|Drop]}
            end
        end, {[], [], []}, DropList
    ).

%% 计算掉落点
calc_goods_drop_xy(Scene, _ScenePoolId, _CopyId, Mx, My, DropNum)->
    case local_boss_api:is_deserted_boss_scene(Scene) of
        true ->
            calc_goods_drop_xy(180, Scene, _ScenePoolId, _CopyId, Mx, My, DropNum);
        _ ->
            calc_goods_drop_xy(120, Scene, _ScenePoolId, _CopyId, Mx, My, DropNum)
    end.

calc_goods_drop_xy(BaseV,Scene, _ScenePoolId, _CopyId, Mx, My, DropNum)->
    DotList = data_drop:get_dot_list(),
    calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, 0, [],0).

%%分配完毕 有可能指标不够
calc_goods_drop_xy(BaseV,Scene,[],Mx,My,DropNum,CurNum,PosList,Limit)->
    case DropNum /= CurNum of
        true when Limit<3->%%指标不够 还不够则循环
            DotList = data_drop:get_dot_list(),
            calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum, PosList,Limit+1);
        _->
            PosList
    end;
%%数量满足
calc_goods_drop_xy(_BaseV,_Scene, _DotList, _Mx, _My, DropNum, DropNum, PosList,_Limit)->
    lists:reverse(PosList);
calc_goods_drop_xy(BaseV,Scene, [{Tx, Ty}|DotList], Mx, My, DropNum, CurNum, PosList,Limit)->
    Nx = util:ceil(Mx + Tx*BaseV),
    Ny = util:ceil(My + Ty*BaseV),
    case scene_landform:is_block(Scene, Nx, Ny) of
        false->
            calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum+1, [{Nx, Ny}|PosList],Limit);
        _-> %%该坐标无效 取下一个点
            calc_goods_drop_xy(BaseV,Scene, DotList, Mx, My, DropNum, CurNum, PosList,Limit)
    end.

%% 广播掉落信息
send_drop(Node, RoleId, MonArgs, DropRule, DropBin) ->
    if
        DropBin == [] -> skip;
        true ->
            #mon_args{id = MonId, scene = MScene, scene_pool_id = MSPId, origin = Origin,
                copy_id = MCopyId,  x = X, y = Y, boss = MBoss} = MonArgs,
            {ok, BinData} = pt_120:write(12017, [MonId, utime:unixtime()+?DROP_ALIVE_TIME, MScene, DropBin, X, Y, MBoss]),
            Broad = DropRule#ets_drop_rule.broad,
            if
                %% 独享BOSS，只有归属者可见
                Origin =:= ?DROP_ORIGIN_REWARD_BOSS_UNSHARED
                    orelse Origin =:= ?DROP_ORIGIN_DESERTED_BOSS_UNSHARED ->
                    lib_server_send:send_to_uid(Node, RoleId, BinData);
                Broad == ?BROAD_SCENE ->
                    lib_server_send:send_to_scene(MScene, MSPId, MCopyId, BinData);
                true ->
                    lib_server_send:send_to_uid(Node, RoleId, BinData)
            end
    end.
%%%-------------------------------------------------------------------
%%% @doc
%%%     掉落物品计算
%%% @end
%%%-------------------------------------------------------------------
%% 筛选出符合条件的掉落列表
filter_drop_list_with_cond(CondArgs, DropList) ->
    F = fun(DropGoods, AccList) ->
        GoodsId = get_drop_goods_id(CondArgs#cond_args.career, DropGoods),
        case filter_drop_list_with_cond_helper(DropGoods#ets_drop_goods.cond_list, CondArgs) of
            true when GoodsId> 0 ->
                NewDropGoods = DropGoods#ets_drop_goods{goods_id = GoodsId},
                [NewDropGoods | AccList];
            _ -> AccList
        end
        end,
    lists:foldl(F, [], DropList).

%% 掉落条件
filter_drop_list_with_cond_helper([], _CondArgs) -> true;
filter_drop_list_with_cond_helper([H|T], CondArgs) ->
    Res = case H of
              {lv, LvMin, LvMax} -> CondArgs#cond_args.lv>=LvMin andalso CondArgs#cond_args.lv=<LvMax;
              {turn, TurnList} -> lists:member(CondArgs#cond_args.turn, TurnList);
              {turn_tasks, TaskIdList} -> lists:member(CondArgs#cond_args.turn_task_id, TaskIdList);
              _ -> true
          end,
    case Res of
        true -> filter_drop_list_with_cond_helper(T, CondArgs);
        _ -> false
    end.

%% 获取#ets_drop_goods{}掉落物品id
get_drop_goods_id(Career, Drop) ->
    #ets_drop_goods{goods_id = GoodsId, replace_list = ReplaceList} = Drop,
    if
        ReplaceList =/= [] ->
            case lists:keyfind(Career, 1, ReplaceList) of
                {Career, CareerGoodsId} -> CareerGoodsId;
                _ -> 0
            end;
        true -> GoodsId
    end.
%%%-------------------------------------------------------------------
%% 统计队伍和人最大伤害
%% 将伤害按照队伍统计
%% return: [{teamId, roleId, hurts, roleList}|_]
statistics_hurt_by_team(Klist) ->
    List = statistics_hurt_by_team(Klist, []),
    F = fun({_, _, HurtA, _}, {_, _, HurtB, _}) -> HurtA > HurtB end,
    lists:sort(F, List).
statistics_hurt_by_team([H|T], List) ->
    #mon_atter{id = RoleId, team_id = TeamId, hurt = RoleHurt} = H,
    NewList =
        case TeamId > 0 of
            true  ->
                case lists:keyfind(TeamId, 1, List) of
                    {TeamId, 0, Hurt, RoleList} ->
                        lists:keyreplace(TeamId, 1, List, {TeamId, 0, Hurt+RoleHurt, [H|RoleList]});
                    _ ->
                        [{TeamId, 0, RoleHurt, [H]}|List]
                end;
            false ->
                [{0, RoleId, RoleHurt, [H]}|List]
        end,
    statistics_hurt_by_team(T, NewList);
statistics_hurt_by_team([], List) -> List.

%% boss掉落归属
get_boss_drop_bltype(Mid, MonLv) ->
    case data_drop:get_rule_list(Mid) of
        [] ->
            skip;
        [DropAlloc|_] ->
            NewBlType =
                case data_drop:get_rule(Mid, DropAlloc, MonLv) of
                    [] -> skip;
                    #ets_drop_rule{bltype = BlType} ->
                        case {DropAlloc, BlType} of
                            {?ALLOC_ONESELF, ?DROP_HURT_MAX} -> BlType;
                            {?ALLOC_ONESELF, ?DROP_FIRST_ATT} -> BlType;
                            {?ALLOC_RAND, ?DROP_HURT_MAX} -> BlType;
                            {?ALLOC_RAND, ?DROP_FIRST_ATT} -> BlType;
                            {?ALLOC_EQUAL, ?DROP_HURT_MAX} -> BlType;
                            {?ALLOC_EQUAL, ?DROP_FIRST_ATT} -> BlType;
                            {?ALLOC_HANDSPEED, ?DROP_HURT_MAX} -> BlType;
                            _ -> skip
                        end
                end,
            {DropAlloc, NewBlType}
    end.

%% 计算boss的归属返回一个列表
%% @return {Adds, Dels, NewBLWhos}
%% Adds|Dels|NewBLWhos :: [#mon_atter{}]

%%  个人独占，最高伤害归属处理：不算队员，只计算一个玩家
calc_boss_bl_who(?ALLOC_ONESELF, ?DROP_HURT_MAX, OldBLWhos, Klist, _FirstAttr, _Hp) ->
    F = fun(#mon_atter{hurt = HurtA}, #mon_atter{hurt = HurtB}) -> HurtA > HurtB end,
    NewBLWhos = case lists:sort(F, Klist) of
                    [P|_] -> [P];
                    _ -> []
                end,
    Fun = fun(E, [AL, L]) ->
        case lists:keyfind(E#mon_atter.id, #mon_atter.id, L) of
            false -> [[E|AL], L];
            _ -> [AL, L]
        end
          end,
    [Adds, _] = lists:foldl(Fun, [[], OldBLWhos], NewBLWhos),
    [Dels, _] = lists:foldl(Fun, [[], NewBLWhos], OldBLWhos),
    {Adds, Dels, NewBLWhos};
%% 其他最高伤害归属：需要判断队伍
calc_boss_bl_who(_DropAlloc, ?DROP_HURT_MAX, OldBLWhos, Klist, _FirstAttr, _Hp) ->
    NewBLWhos = case mon_state_logic:statistics_hurt_by_team(Klist) of
                    [{_TeamId, _RoleId, _Hurt, Roles}|_] -> Roles;
                    _ -> []
                end,
    Fun = fun(E, [AL, L]) ->
        case lists:keyfind(E#mon_atter.id, #mon_atter.id, L) of
            false -> [[E|AL], L];
            _ -> [AL, L]
        end
          end,
    [Adds, _] = lists:foldl(Fun, [[], OldBLWhos], NewBLWhos),
    [Dels, _] = lists:foldl(Fun, [[], NewBLWhos], OldBLWhos),
    {Adds, Dels, NewBLWhos};
%% 第一击获得：不判断队伍，有需要的改这里，之后可能需要判断队伍
calc_boss_bl_who(_DropAlloc, ?DROP_FIRST_ATT, OldBLWhos, _Klist, FirstAttr, _Hp) ->
    case FirstAttr of
        [] -> {[], [], OldBLWhos};
        _ ->
            case lists:keyfind(FirstAttr#mon_atter.id, #mon_atter.id, OldBLWhos) of
                false -> {[FirstAttr], OldBLWhos, [FirstAttr]};
                _ ->  {[], [], OldBLWhos}
            end
    end;
%% 最后一击获得:需判断队伍
calc_boss_bl_who(_DropAlloc, ?DROP_LAST_ATT, _OldBLWhos, [Killer|T], _FirstAttr, 0) ->
    TP = calc_team_member(Killer#mon_atter.team_id, T),
    {[], [], [Killer|TP]};
%% 其他，不计算归属
calc_boss_bl_who(_DropAlloc, _BlType, OldBLWhos, _Klist, _FirstAttr, _Hp) ->
    {[], [], OldBLWhos}.


%% 计算一起的队伍人数
calc_team_member(0, _PList)-> [];
calc_team_member(TeamId, PList)->
    [P || P <- PList, TeamId == P#mon_atter.team_id, P#mon_atter.hurt =/= 0].

%%%===================================================================
%%% Internal functions
%%%===================================================================
%%%===================================================================
%%% @doc 是否可以掉落
%%%==================================================================
%% 助战不给掉落奖励
is_can_drop(#player_status{dungeon = #status_dungeon{dun_id = DunId, help_type = ?HELP_TYPE_YES}},
    _MonArgs, _HurtList, _DropRule) when DunId > 0 -> false;
is_can_drop(Ps, MonArgs, DropRoles, DropRule) ->
    #mon_args{scene = Scene, mid = Mid} = MonArgs,
    #mon{lv = BossLv} = data_mon:get(Mid),
    IsNear = is_near_range(Ps, MonArgs, DropRule),
    IsOverLv = check_all_hurtlist_lv(Scene, Mid, BossLv, DropRoles),
    if
        IsNear == false orelse DropRule == [] -> false;
        %% 玩家自己击杀大于100级的boss不给掉落
        DropRoles =/= [] andalso IsOverLv == true -> false;
        true -> true
    end.

%% 是否在掉落范围
is_near_range(_Ps, _MonArgs, []) -> false;
is_near_range(PlayerStatus, MonArgs, DropRule) ->
    #player_status{scene = SceneId, scene_pool_id = PoolId, copy_id = CopyId, x = PX, y = PY} = PlayerStatus,
    #mon_args{scene = ObjectScene, scene_pool_id = ObjectPoolId, copy_id = ObjectCopyId, x = MX, y = MY} = MonArgs,
    IsSameScene = SceneId==ObjectScene andalso PoolId == ObjectPoolId andalso CopyId == ObjectCopyId,
    case {IsSameScene, DropRule#ets_drop_rule.drop_range} of
        {true, {0, 0}} -> true;
        {true, {Xpx, Ypx}} -> abs(PX - MX) =<Xpx andalso abs(PY - MY) =<Ypx;
        {false, _} -> false;
        _Unkown ->
            ?ERR("unkown drop_range:~p~n", [_Unkown]),
            false
    end.

%% 计算玩家的掉落
check_all_hurtlist_lv(_Scene, _MonId, _BossLv, [])-> false;
check_all_hurtlist_lv(Scene, MonId, BossLv, HurtList)->
    do_check_all_hurtlist_lv(Scene, MonId, BossLv, HurtList).

do_check_all_hurtlist_lv(_Scene, _MonId, _BossLv, []) -> true;
do_check_all_hurtlist_lv(Scene, MonId, BossLv, [BL|HurtList])->
    case lib_goods_check:check_boss_lv(Scene, MonId, BossLv, BL#mon_atter.att_lv) of
        false -> false;
        true -> do_check_all_hurtlist_lv(Scene, MonId, BossLv, HurtList)
    end.

%% 通知前端
notice_drop_goods_to_bag(Player, GoodsList, MonArgs) ->
    GoodsInfo = [{GoodsId, Num} || {_, GoodsId, Num} <- GoodsList],
    local_boss_api:notice_goods_drop(Player, MonArgs#mon_args.scene, GoodsInfo).