%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     赏金BOSS管理进程
%%% @end
%%%-------------------------------------------------------------------
-module(reward_boss_mgr).
-author("liushl").

-behaviour(gen_server).

-include("local_boss.hrl").
-include("scene.hrl").
-include("battle.hrl").
-include("attr.hrl").
-include("server.hrl").
-include("common.hrl").
-include("predefine.hrl").
-include("def_module.hrl").
-include("figure.hrl").
-include("goods.hrl").
-include("def_goods.hrl").
-include("skill.hrl").
-include("errcode.hrl").
-include("def_event.hrl").
-include("def_act_label.hrl").
-include("def_fun.hrl").
-include("drop.hrl").
%% API
-export([start_link/0]).

%% gen_server callbacks
-export([init/1,
    handle_call/3,
    handle_cast/2,
    handle_info/2,
    terminate/2,
    code_change/3]).

-export([
    ask_enter_reward_boss_scene/3,  %% 赏金BOSS-请求进入
    leave_scene/2,                  %% 赏金BOSS-离开场景
    team_change/4,                  %% 赏金BOSS-队伍信息变更
    enter_scene/2,                  %% 赏金BOSS-正式进入
    get_reward_boss_info/3,         %% 赏金BOSS-列表信息
    get_reward_boss_drop_log/1,     %% 赏金BOSS-击杀日志
    add_reward_boss_drop_log/1,     %% 赏金BOSS-增加一条日志
    encourage_attr/5,               %% 赏金BOSS-鼓舞
    cost_encourage_money/4,         %% 玩家进程处理鼓舞扣钱
    get_encourage_info/2,           %% 赏金BOSS-鼓舞信息
    revive/2,                       %% 赏金BOSS-安全区复活
    role_go_supporting/2,           %% 玩家同意协助
    role_cancel_support/2,          %% 玩家取消协助

    reborn_all_boss/0,              %% 复活所有BOSS
    boss_revive/1,                  %% 复活单个Boss
    get_boss_reborn_time/1,         %% 获取单个boss复活时间
    role_add_inspire_count/2,
    %% GM
    gm_reborn_boss/1,
    gm_get_boss_info/1
]).

%% 怪物逻辑
-export([
    when_boss_born/3,                       %% 出生监听器
    when_boss_be_hurt/3,                    %% 血量监听器
    when_boss_die/5,                        %% 死亡监听器了
    enter_boss_scene/2,                     %% 进入BOSS场景
    go_supporting/2,                        %% 玩家同意协助
    cancel_support/2,                       %% 玩家取消协助
    re_statistics_hurt_list_by_team/2,      %% 重新统计仇恨
    settlement_do_in_player/4,              %% 到玩家进程结算
    calc_extra_reward/1,
    after_mon_die_scene_user_do/1
]).
-define(SERVER, ?MODULE).

%%%===================================================================
%%% API
%%%===================================================================
%% 赏金BOSS-请求进入
ask_enter_reward_boss_scene(RoleId, BossId, Force) ->
    gen_server:cast(?MODULE, {ask_enter_reward_boss_scene, RoleId, BossId, Force}).

%% 赏金BOSS-正式进入
enter_scene(RoleId, BossId) ->
    gen_server:cast(?MODULE, {enter_scene, RoleId, BossId}).

%% 赏金BOSS-离开场景
leave_scene(RoleId, BossId) ->
    gen_server:cast(?MODULE, {leave_scene, RoleId, BossId}).

%% 赏金BOSS-队伍信息变更
team_change(BossId, RoleId, TeamId, LeaderName) ->
    Msg = {'team_flag', RoleId, TeamId, LeaderName},
    gen_server:cast(?MODULE, {send_message_to_boss, BossId, Msg}).

%% 赏金BOSS-安全区复活
revive(RoleId, BossId) ->
    Msg = {'role_revive', RoleId},
    gen_server:cast(?MODULE, {send_message_to_boss, BossId, Msg}).

%% 赏金BOSS-列表信息
get_reward_boss_info(RoleSid, FocusList, CounterInfo) ->
    gen_server:cast(?MODULE, {get_reward_boss_info, RoleSid, FocusList, CounterInfo}).

%% 赏金BOSS-击杀日志
get_reward_boss_drop_log(RoleSid) ->
    gen_server:cast(?MODULE, {get_reward_boss_drop_log, RoleSid}).

%% 赏金BOSS-增加一条日志
%% type: 100礼包/小于100，BOSS类型
add_reward_boss_drop_log(Log) ->
    gen_server:cast(?MODULE, {add_reward_boss_drop_log, Log}).

%% 赏金BOSS-鼓舞
encourage_attr(RoleId, RolePid, BossId, Type,IsUnite) ->
    gen_server:cast(?MODULE, {encourage_attr, RoleId, RolePid, BossId, Type,IsUnite}).

%% 赏金BOSS-鼓舞信息
get_encourage_info(RoleId, BossId) ->
    gen_server:cast(?MODULE, {get_encourage_info, RoleId, BossId}).

%% 玩家同意协助
role_go_supporting(RoleId, BossId) ->
    Msg = {mod, ?MODULE, go_supporting, [RoleId]},
    gen_server:cast(?MODULE, {send_message_to_boss, BossId, Msg}).

%% 玩家取消协助
role_cancel_support(RoleId, BossId) ->
    Msg = {mod, ?MODULE, cancel_support, [RoleId]},
    gen_server:cast(?MODULE, {send_message_to_boss, BossId, Msg}).

%% 复活所有BOSS
reborn_all_boss() ->
    gen_server:cast(?MODULE, reborn_all_boss).

%% 复活单个Boss
boss_revive(BossId) ->
    gen_server:cast(?MODULE, {boss_revive, BossId}).

%% 获取单个boss复活时间
get_boss_reborn_time(BossId) ->
    gen_server:call(?MODULE, {get_boss_reborn_time, BossId}).

%% GM
gm_reborn_boss(BossId) ->
    ?MODULE ! {reborn_reward_boss, BossId}.
%%
gm_get_boss_info(BossId) ->
    gen_server:call(?MODULE, {gm_get_boss_info, BossId}).
%%%===================================================================
%% @doc 怪物逻辑
%% 出生监听器:管理进程记录BOSS进程PID
%% {?MODULE, when_boss_born, []}
when_boss_born(init, #scene_object{id = MonId, config_id = BossId, figure = #figure{name = BossName}}, _Args) ->
    local_boss_api:send_tv(reward_boss_reborn, [BossName, BossId]),
    gen_server:cast(?MODULE, {when_boss_born, BossId, self(), MonId}),
    ok.

%% 血量监听器:广播攻击者的伤害
%% {?MODULE, when_boss_be_hurt, 0} : MonAtter 可能是协助者的数据，所以，只用他的伤害值
when_boss_be_hurt(#ob_act{object = Boss, klist = [TrueAtter|_], support_klist = SupportKlist} = State, MonAtter, _) ->
    #scene_object{config_id = BossId, scene = SceneId, scene_pool_id = PoolId} = Boss,
    #mon_atter{support_id = SupportId} = MonAtter,
    HurtList = get_hurt_list(Boss),
    {SendInfo, NewHurtList, PersonalHurt} = mon_state_logic:update_hurt_list(TrueAtter#mon_atter{hurt = MonAtter#mon_atter.hurt}, HurtList),
    Boss1 = put_hurt_list(Boss, NewHurtList),
    %% 广播该次统计的伤害
    Data = get_one_info(SendInfo),
    {ok, Bin} = pt_460:write(46008, [BossId|tuple_to_list(Data)]),
    lib_server_send:send_to_scene(SceneId, PoolId, Bin),
    %% 组队的时候给自己推个人伤害
    case is_integer(PersonalHurt) of
        true ->
            lib_server_send:send_to_uid(TrueAtter#mon_atter.id, pt_460, 46025, [BossId, PersonalHurt]);
        _ ->
            ok
    end,
    %% 如果是协助者，则单播给被协助者和自己
    case SupportId > 0 of
        true  ->
            case SupportKlist of
                [#mon_atter{id = Id, name = Name, hurt = Hurt}|_] ->
                    {ok, Bin1} = pt_460:write(46021, [BossId, Id, Name, Hurt]),
                    lib_server_send:send_to_uid(SupportId, Bin1),
                    lib_server_send:send_to_uid(MonAtter#mon_atter.id, pt_460, 46025, [BossId, Hurt]);
                _ ->
                    ok
            end;
        false ->
            ok
    end,
    %% 刷新头名标识
    OldTop = get_top_roles(Boss),
    NewTop = check_new_top(SceneId, PoolId, SendInfo, OldTop),
    Boss2  = put_hurt_list(Boss1, NewHurtList),
    Boss3  = put_top_roles(Boss2, NewTop),
    State#ob_act{object = Boss3};
when_boss_be_hurt(_MonState, _MonAtter, _) ->
    ok.

%% 死亡监听器了:结算
%% {?MODULE, when_boss_die, []}
when_boss_die(
    #ob_act{object = #scene_object{config_id = BossId, scene = Scene, scene_pool_id = Pool, copy_id = CopyId}, 
        support_klist = SupportKlist},
    [#mon_atter{name = Name}|_] = Klist, _Killer, _, BornTime
) ->
    %% 发送击杀奖励/其他功能触发，在玩家进程 local_boss_api:handle_event
    boss_die_settlement(BossId, Klist, SupportKlist),
    gen_server:cast(?MODULE, {when_boss_die, BossId, BornTime, Name}),
    %% 场景通知一下，为了给协助者飘个字
    mod_scene_agent:apply_cast_scene_user(Scene, Pool, CopyId, ?MODULE, after_mon_die_scene_user_do, []),
    ok;
when_boss_die(_, _, _, _, _) -> ok.

%%%===================================================================

%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @end
%%--------------------------------------------------------------------
-spec(start_link() ->
    {ok, Pid :: pid()} | ignore | {error, Reason :: term()}).
start_link() ->
    gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%%                     {ok, State, Timeout} |
%%                     ignore |
%%                     {stop, Reason}
%% @end
%%--------------------------------------------------------------------
-spec(init(Args :: term()) ->
    {ok, State :: #local_reward_boss{}} | {ok, State :: #local_reward_boss{}, timeout() | hibernate} |
    {stop, Reason :: term()} | ignore).
init([]) ->
    erlang:send_after(?LOCAL_BOSS_DELAY_TIME, self(), init),
    {ok, #local_reward_boss{}}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%%                                   {noreply, State, Timeout} |
%%                                   {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
-spec(handle_info(Info :: timeout() | term(), State :: #local_reward_boss{}) ->
    {noreply, NewState :: #local_reward_boss{}} |
    {noreply, NewState :: #local_reward_boss{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #local_reward_boss{}}).
handle_info(Msg, State) ->
    try
        do_handle_info(Msg, State)
    catch _:_Error ->
        io:format("do handle_info Msg:~w, Error:~w, ~p", [Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

%% 初始化
do_handle_info(init, _State) ->
    BossStatus = [
        list_to_tuple(One)
        || One <- db:get_all(?SQL_GET_REWARD_BOSS_STATUS, [?MON_REWARD_BOSS])
    ],
    Now = utime:unixtime(),
    BossInfo = [
        begin
            create_boss(BossId, Now),
            LastKiller =
                case lists:keyfind(BossId, 1, BossStatus) of
                    {BossId, Killer} ->
                        Killer;
                    _ ->
                        <<>>
                end,
            #reward_boss_info{
                boss_id = BossId
                ,last_killer = LastKiller
            }
        end
        || BossId <- data_local_boss:get_all_reward_boss()
    ],
    {noreply, #local_reward_boss{boss_info = BossInfo}};

%% BOSS重生
do_handle_info({reborn_reward_boss, BossId}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{} ->
            Now = utime:unixtime(),
            create_boss(BossId, Now);
        _ ->
            ok
    end,
    {noreply, State};

%% 场景清空人
do_handle_info({clear_scene, BossId}, State) ->
    case data_local_boss:get_reward_boss_info(BossId) of
        #base_reward_boss_info{boss_scene = SceneId} ->
            lib_scene:kick_players_out_scene(SceneId, BossId, []);
        _ ->
            ok
    end,
    {noreply, State};

do_handle_info(_Info, State) ->
    io:format("module:~p: handle_info unexpect message:~p", [?MODULE, _Info]),
    {noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_call(Request :: term(), From :: {pid(), Tag :: term()},
    State :: #local_reward_boss{}) ->
    {reply, Reply :: term(), NewState :: #local_reward_boss{}} |
    {reply, Reply :: term(), NewState :: #local_reward_boss{}, timeout() | hibernate} |
    {noreply, NewState :: #local_reward_boss{}} |
    {noreply, NewState :: #local_reward_boss{}, timeout() | hibernate} |
    {stop, Reason :: term(), Reply :: term(), NewState :: #local_reward_boss{}} |
    {stop, Reason :: term(), NewState :: #local_reward_boss{}}).
handle_call(Msg, From, State) ->
    try
        do_handle_call(Msg, From, State)
    catch _:_Error ->
        io:format("do_handle_call Msg:~w, Error:~w, ~p", [Msg, _Error, erlang:get_stacktrace()]),
        {reply, error, State}
    end.
do_handle_call({gm_get_boss_info, BossId}, _From, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    Res =
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{boss_pid = Pid} ->
            case misc:is_process_alive(Pid) of
                true  ->
                    {_, MonState} = sys:get_state(Pid),
                    SelfHurt =
                    case erlang:process_info(Pid, dictionary) of
                        {dictionary, List} ->
                            case lists:keyfind(hurt_list_by_team, 1, List) of
                                {_, HurtList} ->
                                    HurtList;
                                _ ->
                                    []
                            end;
                        _ ->
                            []
                    end,
                    #{
                        hp => MonState#ob_act.object#scene_object.battle_attr#battle_attr.hp,
                        hp_lim => MonState#ob_act.object#scene_object.battle_attr#battle_attr.hp_lim,
                        klist => MonState#ob_act.klist,
                        support_list => MonState#ob_act.support_klist,
                        statistics_hurt_by_team => SelfHurt
                    };
                false ->
                    dead
            end;
        _ ->
            boss_id_error
    end,
    {reply, Res, State};

%% 获取单个boss复活时间
do_handle_call({get_boss_reborn_time, BossId}, _From, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{reborn_time = RebornTime} ->
            {reply, RebornTime, State};
        _ ->
            {reply, false, State}
    end;

do_handle_call(_Request, _From, State) ->
    io:format("module:~p: handle_call unexpect message:~p", [?MODULE, _Request]),
    {reply, ok, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @end
%%--------------------------------------------------------------------
-spec(handle_cast(Request :: term(), State :: #local_reward_boss{}) ->
    {noreply, NewState :: #local_reward_boss{}} |
    {noreply, NewState :: #local_reward_boss{}, timeout() | hibernate} |
    {stop, Reason :: term(), NewState :: #local_reward_boss{}}).
handle_cast(Msg, State) ->
    try
        do_handle_cast(Msg, State)
    catch _:_Error ->
        io:format("do handle_cast Msg:~w, Error:~w, ~p", [Msg, _Error, erlang:get_stacktrace()]),
        {noreply, State}
    end.

%% boss出生：记录怪物进程
do_handle_cast({when_boss_born, BossId, BossPid, MonId}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{last_killer = KillerName} = Boss ->
            %% 广播状态
            {ok, Bin} = pt_460:write(46018, [BossId, 0, KillerName]),
            lib_server_send:send_to_all(Bin),

            NewBossInfo = lists:keyreplace(BossId, #reward_boss_info.boss_id, BossInfo,
                Boss#reward_boss_info{mon_id = MonId, boss_pid = BossPid, reborn_time = 0}
            ),
            {noreply, State#local_reward_boss{boss_info = NewBossInfo}};
        _ ->
            {noreply, State}
    end;

%% 请求进入场景
do_handle_cast({ask_enter_reward_boss_scene, RoleId, BossId, Force}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{boss_pid = BossPid} ->
            case misc:is_process_alive(BossPid) of
                true  ->
                    case data_local_boss:get_reward_boss_info(BossId) of
                        #base_reward_boss_info{boss_scene = Scene} ->
                            Check =
                            case Force of
                                true  ->
                                    true;
                                false ->
                                    local_boss_api:check_role_num_limit(Scene, BossId, ?BOSS_SCENE_ROLE_NUM)
                            end,
                            case Check of
                                true  ->
                                    lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS,
                                        local_boss_api, successful_enter_reward_boss, [Scene, BossId, Force]);
                                {false, Error} ->
                                    {ok, Bin} = pt_460:write(46016, [Error, BossId]),
                                    lib_server_send:send_to_uid(RoleId, Bin)
                            end;
                        _ ->
                            {ok, Bin} = pt_460:write(46016, [0, BossId]),
                            lib_server_send:send_to_uid(RoleId, Bin)
                    end;
                false ->
                    {ok, Bin} = pt_460:write(46016, [?ERRCODE(err460_boss_dead), BossId]),
                    lib_server_send:send_to_uid(RoleId, Bin)
            end;
        _ ->
            ok
    end,
    {noreply, State};

%% 进入场景：发送BOSS伤害列表
do_handle_cast({enter_scene, RoleId, BossId}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{boss_pid = BossPid, mon_id = MonId} ->
            case misc:is_process_alive(BossPid) of
                true  ->
                    % old: BossPid ! {mod, ?MODULE, enter_boss_scene, [RoleId]};
                    mon_mgr:send(BossPid, MonId, {mod, ?MODULE, enter_boss_scene, [RoleId]});
                false ->
                    {ok, Bin} = pt_460:write(46007, [BossId, 0, []]),
                    lib_server_send:send_to_uid(RoleId, Bin)
            end;
        _ ->
            ok
    end,
    {noreply, State};

%% 离开场景
do_handle_cast({leave_scene, RoleId, BossId}, State) ->
    #local_reward_boss{encourage_info = EncourageInfo} = State,
    %% 清除鼓舞信息
    NewEncourageInfo = lists:keydelete(RoleId, 1, EncourageInfo),
    %% 通知怪物，离开场景
    Msg = {'leave', RoleId, [], ?BATTLE_SIGN_PLAYER},
    do_handle_cast({send_message_to_boss, BossId, Msg}, State),
    {noreply, State#local_reward_boss{encourage_info = NewEncourageInfo}};

%% 给BOSS发消息
do_handle_cast({send_message_to_boss, BossId, Msg}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{boss_pid = BossPid, mon_id = MonId} ->
            case misc:is_process_alive(BossPid) of
                true  ->
                    % old: BossPid ! Msg;
                    mon_mgr:send(BossPid, MonId, Msg);
                false ->
                    ok
            end;
        _ ->
            ok
    end,
    {noreply, State};

%% 请求BOSS数据
do_handle_cast({get_reward_boss_info, Sid, FocusList, CounterInfo}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    Info = [
        begin
            KillNum = case lists:keyfind(Id, 1, CounterInfo) of
                          {_, Num} -> Num;
                          _ -> 0
                      end,
            Focus = case lists:member(Id, FocusList) of
                        true  -> 1;
                        false -> 0
                    end,
            {Id, RebornTime, Killer, Focus, KillNum}
        end
        || #reward_boss_info{boss_id = Id, reborn_time = RebornTime, last_killer = Killer} <- BossInfo
    ],
    {ok, Bin} = pt_460:write(46012, [Info]),
    lib_server_send:send_to_sid(Sid, Bin),
    {noreply, State};

%% BOSS死亡
do_handle_cast({when_boss_die, BossId, BornTime, KillerName}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{} = Boss ->
            Now = utime:unixtime(),
            %% 保存状态
            db:execute(?SQL_SAVE_ONE_REWARD_BOSS, [BossId, ?MON_REWARD_BOSS, BornTime, Now, KillerName]),
            %% 通知清人
            OutTime = 30,
            erlang:send_after(OutTime*1000, self(), {clear_scene, BossId}),
            case data_local_boss:get_reward_boss_info(BossId) of
                #base_reward_boss_info{reborn_cfg = TimeCfg} ->
                    %% 定时复活
                    RebornTime = get_reborn_time(TimeCfg),
                    case is_integer(RebornTime) andalso RebornTime > 0 of
                        true  ->
                            Ref = erlang:send_after(RebornTime*1000, self(), {reborn_reward_boss, BossId}),
                            NextTime = RebornTime + Now;
                        false ->
                            Ref = undefined,
                            NextTime = Now+86400*100
                    end,
                    %% 重置BOSS
                    NewBoss = Boss#reward_boss_info{
                        boss_pid = undefined,
                        last_killer = KillerName,
                        ref_reborn = Ref,
                        reborn_time = NextTime
                    },
                    NewBossInfo = lists:keyreplace(BossId, #reward_boss_info.boss_id, BossInfo, NewBoss),
                    %% 广播状态
                    {ok, Bin} = pt_460:write(46018, [BossId, NextTime, KillerName]),
                    lib_server_send:send_to_all(Bin),
                    local_boss_api:one_local_boss_die(?MON_REWARD_BOSS, BossId),
                    {noreply, State#local_reward_boss{boss_info = NewBossInfo}};
                _ ->
                    {noreply, State}
            end;
        _ ->
            {noreply, State}
    end;

%% 战力鼓舞
do_handle_cast({encourage_attr, RoleId, RolePid, _BossId, Type,IsUnite}, State) ->
    #local_reward_boss{encourage_info = EncourageInfo} = State,
    case lists:keyfind(RoleId, 1, EncourageInfo) of
        {RoleId, ByGold, _ByBGold} = Info  when Type =:= 1 ->
            Had = ByGold;
        {RoleId, _ByGold, ByBGold} = Info  when Type =:= 2 ->
            Had = ByBGold;
        false ->
            Info = {RoleId, 0, 0},
            Had = 0
    end,
    Max = case Type of
              1 ->
                  data_local_boss:get_local_boss_kv(encourage_by_gold);
              2 ->
                  data_local_boss:get_local_boss_kv(encourage_by_bgold)
          end,
    Res =
        if
            Had >= Max  ->
                {false, ?ERRCODE(err460_encourage_limit)};
            Type =:= 2 andalso Had =:= 0 ->
                %% 绑玉鼓舞免费一次
                ok;
            Type =:= 1 andalso Had =:= 0 andalso IsUnite /= false->
                %% 钻石有buff的时候免费一次
                ok;
            true ->
                MFA = {?MODULE, cost_encourage_money, [Type, Had+1]},
                try gen_server:call(RolePid, {fast_call, MFA}, 3000) of
                    {false, Err} ->
                        {false, Err};
                    {ok, CostType} ->
                        {ok, CostType};
                    {ok} -> 
                        {ok};
                    _Err ->
                        ?ERR("~p", [_Err]),
                        {false, 0}
                catch Class:Reason -> %% 超时之类的
                    Error = {Class, Reason, erlang:get_stacktrace()},
                    ?ERR("~w:handle_bid_for_goods error:~p~n", [?MODULE, Error]),
                    {false, 0}
                end
        end,
    case Res of
        {false, ErrCode} ->
            {ok, Bin} = pt_460:write(46014, [ErrCode, Type]),
            lib_server_send:send_to_uid(RoleId, Bin),
            {noreply, State};
        _A ->
            case Res of
                {ok} -> CostType2 = default;
                ok   -> CostType2 = default;
                {ok, CostType1} -> CostType2 = CostType1
            end,
            {_, OldByGold, OldByBGold} = Info,
            case Type of
                1 ->
                    NewInfo = {RoleId, OldByGold+1, OldByBGold};
                2 ->
                    NewInfo = {RoleId, OldByGold, OldByBGold+1}
            end,
            lib_skill_api:add_buff(RoleId, ?SP_SKILL_BUFF_ENCOURAGE, OldByGold+OldByBGold+1),
            CountType = 
            if 
                Type == 1 -> ?INSPIRE_GOLD;
                Type == 2 andalso CostType2 == default -> ?INSPIRE_BGOLD;
                true -> ?INSPIRE_TICK
            end,
            lib_player:apply_cast(RoleId, ?APPLY_CAST_STATUS, ?MODULE, role_add_inspire_count, [CountType]),
            NewState = State#local_reward_boss{encourage_info = lists:keystore(RoleId, 1, EncourageInfo, NewInfo)},
            {ok, Bin} = pt_460:write(46014, [1, Type]),
            lib_server_send:send_to_uid(RoleId, Bin),
            {noreply, NewState}
    end;

%% 获得鼓舞数据
do_handle_cast({get_encourage_info, RoleId, BossId}, State) ->
    #local_reward_boss{encourage_info = EncourageInfo} = State,
    case lists:keyfind(RoleId, 1, EncourageInfo) of
        {RoleId, ByGold, ByBGold} ->
            ok;
        _ ->
            ByGold = 0, ByBGold = 0
    end,
    {ok, Bin} = pt_460:write(46019, [BossId, ByGold, ByBGold]),
    lib_server_send:send_to_uid(RoleId, Bin),
    {noreply, State};


%% 新增一条掉落日志
do_handle_cast({add_reward_boss_drop_log, OneLog}, State) ->
    #local_reward_boss{
        drop_log_low_quality = LogLow
        , drop_log_high_quality = LogHigh
    } = State,
    case data_goods_type:get(OneLog#boss_drop_log.goods_id) of
        #ets_goods_type{color = Color} ->
            case Color >= ?ORANGE of
                true  ->
                    Max = 20,
                    NewLogs = lists:sublist([OneLog|LogHigh], Max),
                    {noreply, State#local_reward_boss{drop_log_high_quality = NewLogs}};
                false ->
                    Max = 30,
                    NewLogs = lists:sublist([OneLog|LogLow], Max),
                    {noreply, State#local_reward_boss{drop_log_low_quality = NewLogs}}
            end;
        _ ->
            {noreply, State}
    end;

%% 请求掉落日志
do_handle_cast({get_reward_boss_drop_log, RoleSid}, State) ->
    #local_reward_boss{
        drop_log_low_quality = LogLow
        , drop_log_high_quality = LogHigh
    } = State,
    Data = [
        {BossType, SvrNum, Name, Scene, BossId, GoodsId, Time}
        ||#boss_drop_log{
            name = Name
            , scene = Scene
            , svr_num = SvrNum
            , boss = BossId
            , boss_type = BossType
            , goods_id = GoodsId
            , time = Time
        } <- LogHigh ++ LogLow
    ],
    {ok, Bin} = pt_460:write(46013, [Data]),
    lib_server_send:send_to_sid(RoleSid, Bin),
    {noreply, State};

%% BOSS重生
do_handle_cast(reborn_all_boss, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    Now = utime:unixtime(),
    [
        create_boss(BossId, Now)
        || #reward_boss_info{boss_id = BossId, reborn_time = RebornTime} <- BossInfo, RebornTime > 0
    ],
    {noreply, State};

%% 复活单个BOSS
do_handle_cast({boss_revive, BossId}, State) ->
    #local_reward_boss{boss_info = BossInfo} = State,
    case lists:keyfind(BossId, #reward_boss_info.boss_id, BossInfo) of
        #reward_boss_info{ref_reborn = Ref} ->
            util:cancel_timer(Ref),
            do_handle_info({reborn_reward_boss, BossId}, State);
        _ -> skip
    end;

do_handle_cast(_Request, State) ->
    io:format("module:~p: handle_cast unexpect message:~p", [?MODULE, _Request]),
    {noreply, State}.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
-spec(terminate(Reason :: (normal | shutdown | {shutdown, term()} | term()),
    State :: #local_reward_boss{}) ->
    term()).
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
-spec(code_change(OldVsn :: term() | {down, term()}, State :: #local_reward_boss{},
    Extra :: term()) ->
    {ok, NewState :: #local_reward_boss{}} | {error, Reason :: term()}).
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%%===================================================================
%%% Internal functions
%%%===================================================================
%% @doc BOSS生成 lib_mon:async_create_mon(14010101, 2001, 0, 7397,7984, 1, 0, 1, []).
create_boss(BossId, BornTime) ->
    case data_local_boss:get_reward_boss_info(BossId) of
        #base_reward_boss_info{boss_scene = Scene, boss_position = {X, Y}} ->
            AddKV = [
                {born_handler, {?MODULE, when_boss_born, []}},
                {hp_change_handler, {?MODULE, when_boss_be_hurt, []}},
                {die_handler, {?MODULE, when_boss_die, BornTime}},
                {origin, ?DROP_ORIGIN_REWARD_BOSS}
            ],
            lib_mon:async_create_mon(BossId, Scene, BossId, X, Y, 1, 0, 1, AddKV);
        _ ->
            ok
    end.

%% 获得BOSS下次重生时间
get_reborn_time(TimeCfg) ->
    get_reborn_time(util:get_open_day(), lists:reverse(lists:keysort(1, TimeCfg))).
get_reborn_time(OpDay, [{NeedDay, Time}|_]) when OpDay >= NeedDay -> Time;
get_reborn_time(OpDay, [_|T]) -> get_reborn_time(OpDay, T);
get_reborn_time(_, _) -> false.

%% 玩家进程处理鼓舞扣钱
cost_encourage_money(Player, From, Type, Count) ->
    case data_encourage_attr:get_encoourage_cost(Type, Count) of
        {Money, Goods} ->
            Cost = case Goods of
                       [] -> Money;
                       _  -> Goods
                   end,
            case lib_goods_api:cost_objects_with_auto_buy(Player, Cost, reward_boss_encourage, "") of
                {false, Err, _} ->
                    gen_server:reply(From, {false, Err}),
                    ok;
                {true, Player1, CostList} ->
                    [{GoodsType, _, _}|_] = CostList,
                    if Type == 2 andalso GoodsType == 0 ->
                            ReturnRes = {ok, cost_goods};
                        true ->
                            ReturnRes = {ok}
                    end,
                    gen_server:reply(From, ReturnRes),
                    {ok, Player1}
            end;
        _ ->
            gen_server:reply(From, {false, 0}),
            ok
    end.
%%%===================================================================
%% @doc 怪物进程
%%%===================================================================
get_hurt_list(#scene_object{mod_args = ModArgs}) ->
    case lists:keyfind(?LOCAL_BOSS_ARGS_HURT_LIST, 1, ModArgs) of
        {_, Top} -> Top;
        _ -> []
    end.

put_hurt_list(#scene_object{mod_args = ModArgs} = Object, HurtList) ->
    Object#scene_object{
        mod_args = lists:keystore(?LOCAL_BOSS_ARGS_HURT_LIST, 1, ModArgs, {?LOCAL_BOSS_ARGS_HURT_LIST, HurtList})
    }.

get_top_roles(#scene_object{mod_args = ModArgs}) ->
    case lists:keyfind(?LOCAL_BOSS_ARGS_TOP, 1, ModArgs) of
        {_, Top} -> Top;
        _ -> []
    end.

put_top_roles(#scene_object{mod_args = ModArgs} = Object, Top) ->
    Object#scene_object{
        mod_args = lists:keystore(?LOCAL_BOSS_ARGS_TOP, 1, ModArgs, {?LOCAL_BOSS_ARGS_TOP, Top})
    }.

%% 进入BOSS场景
%% 给单个玩家发送整个伤害列表：如果我是伤害第一，则增加标识
enter_boss_scene(MonState, RoleId) ->
    #ob_act{object = #scene_object{battle_attr = #battle_attr{hp_lim = HpLim}, config_id = BossId} = Object} = MonState,
    Klist = get_hurt_list(Object),
    %% 如果我是头名
    case get_top_roles(Object) of
        {_, _, _, RoleList} ->
            case lists:keymember(RoleId, #mon_atter.id, RoleList) of
                true  ->
                    lib_scene:change_scene_act_label(RoleId, ?ACT_LABEL_MAX_HURT, 1);
                false ->
                    ok
            end;
        _ ->
            ok
    end,
    Bin = pack_hurt_list(BossId, HpLim, Klist),
    lib_server_send:send_to_uid(RoleId, Bin),
    ok.

%% 玩家同意协助，需要将他从伤害列表中删除
go_supporting(MonState, RoleId) ->
    #ob_act{klist = Klist, object = #scene_object{mon = Mon}} = MonState,
    NewKlist = lists:keydelete(RoleId, #mon_atter.id, Klist),
    NewState = MonState#ob_act{klist = NewKlist},
    case NewKlist =/= Klist of
        true  -> re_statistics_hurt_list_by_team(Mon#scene_mon.boss, NewState);
        false -> NewState
    end.

%% 玩家取消协助，需要将他从协助伤害列表中清除
cancel_support(MonState, RoleId) ->
    #ob_act{support_klist = SupportList, klist = Klist, object = #scene_object{mon = Mon}} = MonState,
    % {NewSupportList, NewKlist} = mod_mon_active:calc_hurt_support_role_leave(RoleId, Klist, SupportList),
    {NewSupportList, NewKlist} = mon_state_logic:calc_hurt_support_role_leave(RoleId, Klist, SupportList),
    NewState = MonState#ob_act{support_klist = NewSupportList, klist = NewKlist},
    case NewKlist =/= Klist of
        true  -> re_statistics_hurt_list_by_team(Mon#scene_mon.boss, NewState);
        false -> NewState
    end.

%% 重新统计仇恨
%% 触发：玩家退出场景/离开BOSS区域/队伍变更
re_statistics_hurt_list_by_team(?MON_REWARD_BOSS, MonState) ->
    #ob_act{
        klist = Klist,
        object = #scene_object{
            battle_attr = #battle_attr{hp_lim = HpLim},
            config_id = BossId,
            scene = SceneId,
            scene_pool_id = PoolId
        } = Object
    } = MonState,
    HurtList = mon_state_logic:statistics_hurt_by_team(Klist),
    Object1 = put_hurt_list(Object, HurtList),
    Bin = pack_hurt_list(BossId, HpLim, HurtList),
    lib_server_send:send_to_scene(SceneId, PoolId, Bin),
    %% 刷新头名:
    OldTop = get_top_roles(Object),
    case HurtList of
        [{_, _, _, _} = NewTop|_] ->
            refresh_top_info(SceneId, PoolId, NewTop, OldTop);
        _ ->
            refresh_top_info(SceneId, PoolId, [], OldTop),
            NewTop = []
    end,
    Object2 = put_top_roles(Object1, NewTop),
    MonState#ob_act{object = Object2};
re_statistics_hurt_list_by_team(_, State) -> State.

check_new_top(SceneId, PoolId, Attack, []) ->
    refresh_top_info(SceneId, PoolId, Attack, []),
    Attack;
check_new_top(SceneId, PoolId, {_, _, NewHurt, _} = Attack, {_, _, OldHurt, _} = OldTop) ->
    case NewHurt > OldHurt of
        true  ->
            refresh_top_info(SceneId, PoolId, Attack, OldTop),
            Attack;
        false ->
            OldTop
    end.
%% 刷新伤害第一玩家头顶标识：
%% 重新统计的时候，返回的头名是不准确的，不要使用
refresh_top_info(SceneId, PoolId, [], {_, _, _OldHurt, OldRoleList}) ->
    [
        local_boss_api:update_act_label(One#mon_atter.id, SceneId, PoolId, ?ACT_LABEL_MAX_HURT, 0)
        ||One <- OldRoleList
    ],
    [];
refresh_top_info(SceneId, PoolId, {_, _, _, NewRoleList} = NewTop, []) ->
    [
        local_boss_api:update_act_label(One#mon_atter.id, SceneId, PoolId, ?ACT_LABEL_MAX_HURT, 1)
        || One <- NewRoleList
    ],
    NewTop;
refresh_top_info(SceneId, PoolId, {_, _, _, NewRoleList}, {_, _, _, OldRoleList}) ->
    [
        case lists:keymember(One#mon_atter.id, #mon_atter.id, OldRoleList) of
            true  ->
                ok;
            false ->
                local_boss_api:update_act_label(One#mon_atter.id, SceneId, PoolId, ?ACT_LABEL_MAX_HURT, 1)
        end
        || One <- NewRoleList
    ],
    [
        case lists:keymember(One#mon_atter.id, #mon_atter.id, NewRoleList) of
            true  ->
                ok;
            false ->
                local_boss_api:update_act_label(One#mon_atter.id, SceneId, PoolId, ?ACT_LABEL_MAX_HURT, 0)
        end
        ||One <- OldRoleList
    ];
refresh_top_info(_, _ ,_ ,_) -> [].

%% BOSS击杀结算
boss_die_settlement(BossId, Klist, SupportKlist) ->
    case data_local_boss:get_reward_boss_info(BossId) of
        #base_reward_boss_info{boss_name = BossName, enter_lv = BossLv} ->
            HurtList = mon_state_logic:statistics_hurt_by_team(Klist),
            case HurtList of
                [{TeamId, RoleId, _Hurt, [Role|_] = RoleList}|_] ->
                    boss_first_blood:boss_dead(BossId, BossName, BossLv, [{Id, Name}|| #mon_atter{id = Id, name = Name} <- RoleList]),
                    %% 传闻
                    case TeamId > 0 of
                        true  ->
                            local_boss_api:send_tv(reward_boss_max_hurt_team, [Role#mon_atter.team_leader_name, 0, BossName]);
                        false ->
                            local_boss_api:send_tv(reward_boss_max_hurt_role, [Role#mon_atter.name, RoleId, BossName])
                    end;
                _ ->
                    ignore
            end,
            {SupportNum, TeamRoleNum} = calc_top_hurt_support_num(HurtList, SupportKlist),
            boss_die_settlement_do(BossId, HurtList, 1, SupportNum, TeamRoleNum);
        _ ->
            ok
    end.
boss_die_settlement_do(BossId, [{_, _, AllHurt, RoleList}|T], Rank, SupportNum, TeamRoleNum) ->
    [
        begin
        {HurtPercent, HurtRank} = calc_role_hurt_and_rank(BossId, Rank, Id, Hurt, AllHurt, RoleList),
        lib_player:apply_cast(Id, ?APPLY_CAST_STATUS, ?MODULE, settlement_do_in_player, [BossId, Rank, {SupportNum, TeamRoleNum, HurtPercent, HurtRank}])
        end
        || #mon_atter{id = Id, hurt = Hurt} <- RoleList
    ],
    boss_die_settlement_do(BossId, T, Rank+1, SupportNum, TeamRoleNum);
boss_die_settlement_do(_, _, _, _, _) -> ok.

%% TA数据统计-获取归属玩家的协助人数|队伍人数
calc_top_hurt_support_num([{TeamId, RoleId, _Hurt, RoleList}|_], SupportKlist) ->
    SupportNum = lists:foldl(fun(#mon_atter{support_id = SupportId}, AccNum) -> 
        if TeamId == 0 ->
                if RoleId == SupportId -> AccNum+1;
                    true -> AccNum
                end;
            true -> %% 队伍归属
                case lists:keymember(SupportId, #mon_atter.id, RoleList) of
                    true -> AccNum+1;
                    _    -> AccNum
                end     
        end
    end, 0, SupportKlist),
    {SupportNum, length(RoleList)};
calc_top_hurt_support_num(_, _) -> {0, 0}.

%% TA数据统计-获取归属玩家的伤害百分比&伤害排名
calc_role_hurt_and_rank(BossId, Rank, _RoleId, RoleHurt, _AllHurt, _RoleList) ->
    #mon{hp_lim = TotalHurtLimit} = data_mon:get(BossId),
    HurtPercent = round(RoleHurt/TotalHurtLimit*100),
    {HurtPercent, Rank}.

%% 到玩家进程结算
settlement_do_in_player(Player, BossId, Rank, {SupportNum, TeamRoleNum, HurtPercent, TeamRank}) ->
    #player_status{
        scene = Scene,
        scene_pool_id = PoolId,
        sid = Sid,
        id = RoleId,
        figure = #figure{name = Name, lv = RoleLv},
        local_boss = #status_local_boss{ta_data = TAData}
    } = Player,
    #base_reward_boss_info{
        award_base = AwardBase,
        boss_scene = BossScene,
        boss_name = BossName,
        enter_lv = BossLv,
        grade = Grade
    } = Cfg =
        data_local_boss:get_reward_boss_info(BossId),
    IsSupport = lib_guild_support_mod:role_is_supporting(Player),
    IsTired = local_boss_api:reward_boss_is_tired(Player),
    LeftCount = lib_counter:get_count(RoleId, ?MOD_LOCAL_BOSS, ?COUNT_REWARD_BOSS_COUNTER_KILL, BossId),
    % 参与赏金BOSS击杀
    lib_elite_assess_api:reward_boss_event(Player, BossId),
    {ok, Player1} = lib_player_event:dispatch(Player, ?EVENT_REWARD_BOSS_PART, BossId),
    % {ok, NewPlayer} = lib_seven_days_goal:do_kill_boss(Player1, ?MOD_LOCAL_BOSS, 3, BossId),
    NewPlayer = Player1,
    %% 没完成赏金主线任务的要触发主线副本任务
    case lib_task:is_during_task(?REWARD_BOSS_TASK_ID) of
        false -> skip;
        _    -> lib_task_api:fin_dun_enter(RoleId, ?REWARD_BOSS_TASK_DUN)
    end,
    case Scene =:= BossScene
        andalso PoolId =:= BossId
        andalso not IsSupport
        andalso (LeftCount =:= 0 orelse not IsTired)
    of
        true  ->
            Now = utime:unixtime(),
            %% 非协助者走这里
            ExtraGoods = case Rank =:= 1 of
                true  ->
                    calc_extra_reward(Cfg);
                false ->
                    []
            end,
            %% 特殊，第一个物品传闻以及上墙
            case ExtraGoods of
                [{_, GoodsId, _}|_] ->
                    case data_goods_type:get(GoodsId) of
                        #ets_goods_type{color = Color} when Color >= ?PURPLE ->
                            local_boss_api:send_tv(reward_boss_extra_award, [Name, RoleId, GoodsId]);
                        _ ->
                            ok
                    end,
                    Log = #boss_drop_log{
                        name = Name
                        , svr_num = 0
                        , scene = Scene
                        , boss = BossId
                        , boss_type = ?MON_REWARD_BOSS
                        , goods_id = GoodsId
                        , time = Now
                    },
                    add_reward_boss_drop_log(Log);
                _ ->
                    ok
            end,
            {ok, Bin} = pt_460:write(46015, [BossName, AwardBase, ExtraGoods]),
            lib_server_send:send_to_sid(Sid, Bin),
            BeforeLeftCount = lib_counter:get_count(RoleId, ?MOD_LOCAL_BOSS, ?COUNT_REWARD_BOSS_COUNTER_KILL, BossId),
            Player2 = local_boss_api:cost_reward_boss_daily_count(NewPlayer, BossId),
            Produce = #produce{
                reward = AwardBase ++ ExtraGoods,
                type = reward_boss_kill,
                subtype = BossId,
                remark = lists:concat(["Rank=", Rank])
            },
            Player3 = lib_goods_api:send_reward(Player2, Produce),
            NowTime = utime:unixtime(),
            SvrNum = config:get_server_num(),
            IsFirstKill = ?IF(BeforeLeftCount == 0, 1, 0),
            lib_log_api:log_boss_belong([RoleId, Name, 0, SvrNum, RoleLv, ?MON_REWARD_BOSS, BossLv, BossId, [], IsFirstKill, NowTime]),
            %% 获得奖励-触发其他功能
            {ok, Player4} = lib_player_event:dispatch(Player3, ?EVENT_KILL_LOCAL_BOSS, [BossId, IsFirstKill]),
            %% TA上报并更新数据
            BossTAData  = maps:get(?MON_REWARD_BOSS, TAData, #{}),
            InspireTicket = maps:get(?INSPIRE_TICK, BossTAData, 0),
            InspireGold = maps:get(?INSPIRE_GOLD, BossTAData, 0),
            InspireBGold = maps:get(?INSPIRE_BGOLD, BossTAData, 0),
            ReviveCount = maps:get(?REVIVE_TIME, BossTAData, 0),
            EnterTime   = maps:get(?ENTER_TIME, BossTAData, 0),
            case data_mon:get(BossId) of
                #mon{lv = BossLv} -> ok;
                _ -> BossLv = 0
            end,
            ta_agent_fire:ta_gold_boss_belong(Player4, [BossId, BossLv, Grade, IsFirstKill, InspireTicket, InspireBGold, InspireGold, ReviveCount, TeamRoleNum, SupportNum,
                HurtPercent, TeamRank, round(Now - EnterTime)]),
            local_boss_api:kill_boss_refresh_ta_data(Player4, ?MON_REWARD_BOSS, Now);
        false ->
            %% 协助者飘个字
            IsSupport andalso lib_chat:send_error_code(Sid, ?ERRCODE(err460_supporter_no_award)),
            Player
    end.

after_mon_die_scene_user_do(Player) ->
    IsSupport = lib_guild_support_mod:role_is_supporting(Player),
    %% 协助者飘个字
    IsSupport andalso lib_chat:send_error_code(Player#player_status.sid, ?ERRCODE(err460_supporter_no_award)),
    Player.

%% 计算额外奖励
calc_extra_reward(#base_reward_boss_info{award_extra_num = ExtraNum, award_extra = AwardExtra}) ->
    ExtraGoods = case urand:list_rand_by_weight(AwardExtra, ExtraNum, true) of
        [_Temp] ->
            _Temp;
        _ ->
            []
    end,
    ExtraGoods.
%%%-------------------------------------------------------------------
%%%
%%%-------------------------------------------------------------------
pack_hurt_list(BossId, HpLim, Klist) ->
    HurtList = [
        get_one_info(One)||One <- Klist
    ],
    {ok, Bin} = pt_460:write(46007, [BossId, HpLim, HurtList]),
    Bin.

get_one_info(SendInfo) ->
    case SendInfo of
        {TeamId, _RoleId, Hurt, [#mon_atter{team_leader_name = Name}|_]} when TeamId > 0 ->
            {TeamId, 1, Name, Hurt};
        {_TeamId, RoleId, Hurt, [#mon_atter{name = Name}|_]} ->
            {RoleId, 0, Name, Hurt};
        _ ->
            {0, 0, "", 0}
    end.

role_add_inspire_count(Player, CountType) ->
    NewPlayer = local_boss_api:plus_inspire_count(Player, ?MON_REWARD_BOSS, CountType),
    {ok, NewPlayer}.