%% ---------------------------------------------------------------------------
%% @doc lib_revive

%% @author zzm
%% @since  2015-04-23
%% @deprecated  复活模块库函数
%% ---------------------------------------------------------------------------
-module(lib_revive).
-export([revive/2, revive/3, revive_without_check/3, send_revive/10]).

-include("server.hrl").
-include("scene.hrl").
-include("common.hrl").
-include("figure.hrl").
-include("attr.hrl").
-include("def_event.hrl").
-include("dungeon.hrl").
-include("def_goods.hrl").
-include("errcode.hrl").
-include("wasteland_war.hrl").
-include("def_module.hrl").
-define(GOLD, 20).
-define(DEFAULT_COST_TUPLE, {true, 0, 0, 0}).
-define(DEFAULT_GOLD_COST_TUPLE, {true, gold, ?GOLD, revive}).
-define(USE_REVIVE_TICKET, {true, revive_ticket, [{0, 102000, 1}], revive}).


%% 复活保护需要调整精度，目前在战斗那边会div 1000来进行比较
%% 这个实际上也需要游戏服与跨服做时间校正来判断，后续统一做全局时间校正再改
%% 前端动画可能超2秒，策划需求2秒会不够，所以改为3秒
-define(REVIVE_PROTECT_TIME, 3).       % 复活保护时间（单位：s）

%%复活方法
%%@param Status #player_status
%%@param Type   1元宝原地复活 2绑定元宝原地复活 3回城复活 4根据参数Status的血量复活
%%              5原地满血复活 8挂机自动复活 9通用副本复活 16复活券复活
revive(Status, Type) ->
    revive(Status, Type, []).

revive(Status, Type, PlayerArgs) ->
    Result =
    case check_revive(Status, Type) of
        {false, Res} ->
            {Res, Status};
        {true, MoneyType, Money, ConsumeType} ->
            Comment = lists:concat(["scene:", Status#player_status.scene, " revive_type:", Type]),
            revive_cost_money(Status, MoneyType, Money, ConsumeType, Comment)
    end,

    %% 处理血量
    case Result of
        {1, CostStatus} ->
            {1, revive_set_data(CostStatus, Type, PlayerArgs)};
        {LastRes, _}    ->
            {LastRes, Status}
    end.

%% 直接复活
revive_without_check(Status, Type, PlayerArgs) ->
    Status1 = revive_set_data(Status, Type, PlayerArgs),
    %% 告诉客户端复活成功
    {ok, BinData} = pt_200:write(20004, [Type, 1]),
    lib_server_send:send_to_uid(Status1#player_status.id, BinData),
    mod_scene_agent:update(Status, [{battle_attr, Status1#player_status.battle_attr}]),
    Status2 =
    case Status1#player_status.online == ?ONLINE_ON of
        true -> Status1;
        false ->
            case data_scene:get(Status1#player_status.scene) of
                #ets_scene{type=?SCENE_TYPE_DUNGEON} -> {ok, TmpStatus} = pp_scene:handle(12002, Status1, ok), TmpStatus;
                _ -> Status1
            end
    end,
    {ok, Status2}.

%% 检查除货币外的复活条件
check_revive(Status, Type) ->
    CheckReviveOnDun = lib_dungeon:check_revive_on_dungeon(Status, Type),
    CheckRevive3v3 = lib_3v3_api:check_revive(Status, Type),
    CheckReviveWasteland = wasteland_war_api:check_cd_time(Type),
    CheckDesertBoss = local_boss_api:is_deserted_boss_scene(Status#player_status.scene),
    if
        %% 宠物生活技能，星域幻魔每日免费复活次数
        CheckDesertBoss =:= true ->
            check_deserted_boss_revive_cost(Status, Type);
        CheckReviveOnDun =/= true -> CheckReviveOnDun;
        CheckRevive3v3 =/= true -> CheckRevive3v3;
        CheckReviveWasteland =/= true -> CheckReviveWasteland;
        true ->
            check_revive_on_normal(Status, Type)
    end.

%% 星域幻魔只能安全区复活和原地复活
check_deserted_boss_revive_cost(_Status, Type)
    when Type =/= 1 andalso Type =/= 3 ->
    {false, ?ERRCODE(err200_revive_type_error)};
check_deserted_boss_revive_cost(Status, Type) ->
    case Type =:= ?REVIVE_FOR_GOODS orelse Type =:= 1 of
        true ->
            HasFreeTimes = lib_pet_api:pet_life_skill_about_deserted_revive_free(Status),
            UseTimes = lib_daily:get_count(Status#player_status.id, ?MOD_DESERTED_BOSS, 3),
            case UseTimes < HasFreeTimes of
                true ->
                    lib_daily:increment(Status#player_status.id, ?MOD_DESERTED_BOSS, 3),
                    lib_server_send:send_to_sid(Status#player_status.sid, pt_461, 46108,
                        [max(0, HasFreeTimes-UseTimes-1)]
                    ),
                    {true, 0, 0, 0};
                _ -> check_revive_on_normal(Status, Type)
            end;
        _ ->
            check_revive_on_normal(Status, Type)
    end.

check_revive_on_normal(_Status, Type) ->
    if
        Type == 1 -> %% 元宝复活
            case lib_dungeon:check_revive_cost(_Status) of
                {true, Cost} ->
                    Cost;
                _ ->
                    ?DEFAULT_GOLD_COST_TUPLE
            end;
        Type == 2 ->
            ?DEFAULT_COST_TUPLE;                       %% 绑定元宝复活已经不用花费（注：登录复活用到此类型）
        Type == 8 ->
            ?DEFAULT_GOLD_COST_TUPLE;                  %% 离线挂机复活操作
        Type == ?REVIVE_FOR_GOODS ->
            ?USE_REVIVE_TICKET;                        %% 使用复活券复活
        true ->
            ?DEFAULT_COST_TUPLE
    end.

%% 复活扣费
revive_cost_money(Status, ?TYPE_COIN, Money, ConsumeType, Comment) ->
    case lib_goods_api:cost_money(Status, coin, Money, ConsumeType, Comment) of
        {1, NewStatus} -> {1, NewStatus};
        _              -> {?ERRCODE(coin_not_enough), Status}
    end;
revive_cost_money(Status, gold, Money, ConsumeType, Comment) ->
    case lib_goods_api:cost_money(Status, ?TYPE_GOLD, Money, ConsumeType, Comment) of
        {1, NewStatus} -> {1, NewStatus};
        _              -> {?ERRCODE(gold_not_enough), Status}
    end;
revive_cost_money(Status, bgold_and_gold, Money, ConsumeType, Comment) ->
    case lib_goods_api:cost_money(Status, ?TYPE_BGOLD, Money, ConsumeType, Comment) of
        {1, NewStatus} -> {1, NewStatus};
        _              -> {?ERRCODE(gold_not_enough), Status}
    end;
revive_cost_money(Status, revive_ticket, Money, ConsumeType, Comment) ->
    case lib_goods_api:cost_object_list_with_check(Status, Money, ConsumeType, Comment) of
        {true, NewStatus,_} ->
            {1, NewStatus};
        {false, ErrorCode, _NPlayerTmp} ->
            {ErrorCode, Status}
    end;

revive_cost_money(Status, _, _, _, _) -> {1, Status}.

%% 复活数据处理
%% 原地复活以上次被击杀坐标为复活点
revive_set_data(Status, Type, PlayerArgs) ->
    NowTime = utime:unixtime(),
    #player_status{scene=PlayerSceneId,copy_id=CopyId, battle_attr=BA, revive_status = ReviveStatus,
     dungeon = StatusDungeon, killed_pos = KilledPos, x = OldX, y = OldY} = Status,
    case KilledPos of
        [{KilledX, KilledY}|_] -> ok;
        _ -> KilledX = OldX, KilledY = OldY
    end,
    #battle_attr{hp=OldHp, hp_lim=HpLim, group = GroupId} = BA,
    Scene = data_scene:get(PlayerSceneId),
    #revive_status{revive_coord = {_ReviveSceneId, _ReviveX, _ReviveY}} = ReviveStatus,
    #status_dungeon{dun_id = DunId, revive_count = ReviveCount} = StatusDungeon,
    %% 特殊放前面
    if
        DunId > 0 andalso Type =:= ?REVIVE_DUNGEON ->   %% 通用副本复活
            Hp          = HpLim,
            {X, Y, ReviveType} = lib_dungeon:get_revive_xy(Status),
            Args        = [{hp, Hp}, {x,X}, {y,Y}, {status_dungeon, [{revive_count, ReviveCount}]}];

        OldHp > HpLim * 3 div 100 ->
            Hp          = OldHp,
            Args        = [{hp, Hp}, {x, KilledX}, {y, KilledY}],
            ReviveType  = 1;

        %%前面这4个判断选项顺序不能变，如有添加，请从第5个判断开始添加
        Scene=:=[]->  %% 找不到场景数据(10%原地站起)
            Hp          = HpLim*10 div 100,
            Args        = [{hp, Hp}],
            ReviveType  = 2;

        Type =:= 1 -> %% 元宝复活
            Hp          = HpLim,
            Args        = [{hp, Hp}, {x, KilledX}, {y, KilledY}],
            ReviveType  = 1;
        Type =:= 2 -> %% 绑定元宝复活
            Hp          = HpLim *30 div 100,
            Args        = [{hp, Hp}, {x, KilledX}, {y, KilledY}],
            ReviveType  = 1;

        Type =:= 4 -> %% 原血量复活
            Args        = [{x, KilledX}, {y, KilledY}],
            ReviveType  = 1;
        Type =:= 5 -> %% 原地满血复活
            Hp          = HpLim,
	        IsWastelandScene = lib_wasteland_war:is_wasteland_scene(PlayerSceneId),
	        {BornX, BornY} = lib_wasteland_war:get_war_pos(PlayerSceneId),
	        case IsWastelandScene of
				true -> Args = [{hp, Hp}, {x, BornX}, {y, BornY}];
				_    -> Args = [{hp, Hp}, {x, KilledX}, {y, KilledY}]
	        end,
            ReviveType  = 1;

        Type =:= ?REVIVE_KF_3V3 ->
            Hp          = HpLim,
            %% [{x, X}, {y, Y}] = lib_3v3_center:revive(GroupId),
            Args        = lib_3v3_center:revive(GroupId) ++ [{hp, Hp}],
            ReviveType  = 2;
        Type =:= ?REVIVE_DRUMWARD ->
            {BornX, BornY} = lib_role_drum:revive(Status),
            Args = [{hp, HpLim}, {x, BornX}, {y, BornY}],
            ReviveType  = 2;
        Status#player_status.figure#figure.lv =< 20 -> %% 新手挂掉(100%原地站起)
            Hp          = HpLim,
            Args        = [{hp, Hp}, {x, KilledX}, {y, KilledY}],
            ReviveType  = 1;
        Type =:= 16 -> %% 复活券复活
            Hp          = HpLim,
            Args        = [{hp, Hp}, {x, KilledX}, {y, KilledY}],
            ReviveType  = 1;

        true-> %% 正常死亡(默认复活方式)
            IsDungeon = lib_dungeon:is_on_dungeon(Status),
            Hp = HpLim,
            ReviveType  = 2,
            IsCGWarScene= cross_guild_war_api:is_in_cross_guild_war(PlayerSceneId),
            IsCampWar   = camp_war_api:is_on_camp_war(PlayerSceneId),
            IsWastelandScene = lib_wasteland_war:is_wasteland_scene(PlayerSceneId),
            if
                IsDungeon == true ->
                    {BornX, BornY, _} = lib_dungeon:get_revive_xy(Status),
                    Args = [{hp, Hp}, {x, BornX}, {y, BornY}];
                IsCGWarScene ->             %% 跨服帮派场景
                    {BornX, BornY} = cross_guild_war_api:get_revive_xy(CopyId, GroupId, Scene),
                    Args = [{hp, Hp}, {x, BornX}, {y, BornY}];
                IsCampWar ->
                    {BornX, BornY} = camp_war_api:get_revive_xy(Status),
                    Args = [{hp, Hp}, {x, BornX}, {y, BornY}];
                IsWastelandScene ->
                    {BornX, BornY} = lib_wasteland_war:get_war_pos(PlayerSceneId),
                    Args = [{hp, Hp}, {x, BornX}, {y, BornY}];
                true ->
                    %% 通用复活，在场景配置的复活坐标复活
                    #ets_scene{fuhuoscene=RebornScene} = Scene,
                    [Xrb, Yrb] = case RebornScene =:= 0 orelse RebornScene =:= PlayerSceneId of
                         true  ->
                             OkScene = PlayerSceneId,
                             lib_scene:get_born_xy(Scene);
                         false ->
                             OkScene = RebornScene,
                             lib_scene:get_born_xy(RebornScene)
                     end,
                    Args = [{hp, Hp}, {scene, OkScene}, {x, Xrb}, {y, Yrb}]
            end
    end,
    %% 复活保护时间 与 复活控制参数
    {ProtectTime, ReviveSetArgs} =
    if
        OldHp > 0 ->
            %% 防止未死发复活刷保护时间
            {Status#player_status.battle_attr#battle_attr.pk#pk.pk_protect_time, Args};
        true ->
            case lib_wasteland_war:is_wasteland_scene(PlayerSceneId) of
                true ->
                    PkProtectTime = NowTime + ?WASTELAND_PROTECT_TIME;
                _ ->
                    PkProtectTime = NowTime + ?REVIVE_PROTECT_TIME
            end,
            {PkProtectTime, [{pk_protect_time, PkProtectTime} | Args]}
    end,
    AfterHpStatus = revive_set_data_hepler([{ghost, 0}, {killed_pos, []}|lists:keydelete(ghost, 1, PlayerArgs)] ++ ReviveSetArgs, Status),

    %%判断是否要离开场景
    #player_status{x=NewX, y=NewY} = AfterHpStatus,
    case ReviveType of
        1 ->    %% 原地复活
            %% 特殊技能的触发在这边判断，减少场景非必要开销
            TriggerSkill = lib_skill_buff:check_revive_trigger(Status, Type),
            mod_scene_agent:revive(Status, TriggerSkill, AfterHpStatus#player_status.battle_attr, KilledPos);
        _ ->
            %% 通知离开场景
            lib_scene:leave_scene(Status)
    end,

    NewSceneId = AfterHpStatus#player_status.scene,
    case NewSceneId=/=PlayerSceneId of
        true  -> SceneName = lib_scene:get_scene_name(NewSceneId);
        false -> SceneName = Scene#ets_scene.name
    end,

    %% 加载场景
    AfterReviveStatus = send_revive(
        AfterHpStatus, ReviveType,
        AfterHpStatus#player_status.scene, AfterHpStatus#player_status.x, AfterHpStatus#player_status.y,
        SceneName, AfterHpStatus#player_status.battle_attr#battle_attr.hp,
        AfterHpStatus#player_status.gold, AfterHpStatus#player_status.bgold,
        ProtectTime),

    %% 触发怪物ai
    mod_scene_agent:move(NewX, NewY, NewX, NewY, 0, 0, 0, AfterReviveStatus),
    %% 派发复活事件
    {ok, AfEventStatus} = lib_player_event:dispatch(AfterReviveStatus, ?EVENT_REVIVE, Type),
    %% 玩家复活疲劳值添加
    %add_revive_tired(Type, Status),

    NewReviveStatus = ReviveStatus#revive_status{last_revive_time = NowTime},
    AfEventStatus#player_status{revive_status = NewReviveStatus}.

%% 数据载入
revive_set_data_hepler([H|T], Status) ->
    BA = Status#player_status.battle_attr,
    PK = BA#battle_attr.pk,
    NewStatus =
    case H of
        {hp, V}     -> Status#player_status{battle_attr=BA#battle_attr{hp=V}};
        {scene, V}  -> Status#player_status{scene=V};
        {copy_id, V}-> Status#player_status{copy_id=V};
        {x, V}      -> Status#player_status{x=V};
        {y, V}      -> Status#player_status{y=V};
        {ghost, V}  -> Status#player_status{battle_attr=BA#battle_attr{ghost=V}};
        {killed_pos, V} -> Status#player_status{killed_pos = V};
        {hide, V}   -> Status#player_status{battle_attr=BA#battle_attr{hide=V}};
        {pk_protect_time, V} ->Status#player_status{battle_attr=BA#battle_attr{pk=PK#pk{pk_protect_time=V}}};
        %% 恢复速度
        {speed, restore} -> lib_player:count_player_speed(Status);
        {status_dungeon, V} -> lib_dungeon:update_status_dungeon(V, Status);
        _ -> Status
    end,
    revive_set_data_hepler(T, NewStatus);
revive_set_data_hepler([], Status) ->
    %% 重置BUFF状态
    BA = Status#player_status.battle_attr,
    NewBA = BA#battle_attr{attr_buff_list = [], other_buff_list = []},
    Status#player_status{battle_attr = NewBA}.

send_revive(Status, ReviveType, SceneId, X, Y, SceneName, Hp, Gold, BGold, AttProtected) ->
    {ok, BinData} = pt_120:write(12083, [ReviveType, SceneId, X, Y, SceneName, Hp, Gold, BGold, AttProtected]),
    lib_server_send:send_to_sid(Status#player_status.sid, BinData),
    NewStatus = Status,
    NewStatus.

%% 玩家复活疲劳值
%add_revive_tired(_Type, Status)->
%    #player_status{id = Id, scene = Scene} = Status,
%    IsBossScene = lib_boss:is_in_boss(Scene),
%    if
%        IsBossScene ->
%           NowTime = utime:unixtime(),
%            case get({Id, revive_tired}) of
%                {LastTime, Num} when NowTime - LastTime < 300 ->
%                    NewReviveTired = Num + 1,
%                    LTime = NowTime + 300,
%                    put({Id, revive_tired}, {NowTime, NewReviveTired});
%                _ ->
%                    NewReviveTired = 1,
%                    LTime = NowTime,
%                    put({Id, revive_tired}, {NowTime, NewReviveTired})
%            end,
%            {ok, BinData} = pt_200:write(20017, [NewReviveTired, LTime]),
%            lib_server_send:send_to_uid(Id, BinData);
%        true ->
%            ok
%    end.
