%%%-------------------------------------------------------------------
%%% @author liushl
%%% @doc
%%%     离线托管战斗
%%% @end
%%%-------------------------------------------------------------------
-module(offline_hosting_battle).
-author("liushl").

-include("scene.hrl").
-include("skill.hrl").
-include("battle.hrl").
-include("attr.hrl").
-include("def_fun.hrl").
-include("common.hrl").
-include("predefine.hrl").
-include("figure.hrl").
-include("team.hrl").
%% API
-export([
    battle/3,
    stop_battle/1,
    check_stop_battle/2,
    target_battle/5,
    user_target_battle/5,
    start_battle/3,
    host_battle_info/4,
    combo/3
]).

%% 自由攻击 FindType:1怪优先|2人优先|3只找怪
battle(EtsScene, RoleId, FindType) ->
    case lib_scene_agent:get_user(RoleId) of
        #ets_scene_user{online=?ONLINE_OFF_HOSTING}=User ->
            Ref = start_battle(User, FindType, EtsScene),
            put({onhook_ref, RoleId}, Ref);
        _ ->
            skip
    end.

%% 停止攻击
stop_battle(RoleId) ->
    case lib_scene_agent:get_user(RoleId) of
        #ets_scene_user{online=?ONLINE_OFF_HOSTING}=User ->
            User1 = User#ets_scene_user{offline_hosting =[]},
            lib_scene_agent:put_user(User1),
            case erase({onhook_ref, RoleId}) of
                Ref when is_reference(Ref) ->
                    util:cancel_timer(Ref);
                _ ->
                    ok
            end;
        _ ->
            skip
    end.

%% 检查停止攻击
check_stop_battle(true, #ets_scene_user{online=?ONLINE_OFF_HOSTING, id = RoleId} = User) ->
    case erase({onhook_ref, RoleId}) of
        Ref when is_reference(Ref) ->
            util:cancel_timer(Ref);
        _ ->
            ok
    end,
    User#ets_scene_user{offline_hosting =[]};
check_stop_battle(_, User) -> User.

%% 争对性攻击，指定一个目标
target_battle(EtsScene, RoleId, Sign, Id, FindType) ->
    case lib_scene_agent:get_user(RoleId) of
        #ets_scene_user{online=?ONLINE_OFF_HOSTING}=User ->
            user_target_battle(EtsScene, User, Sign, Id, FindType);
        _ ->
            skip
    end.

user_target_battle(EtsScene, User, Sign, Id, FindType) ->
    #ets_scene_user{id = RoleId}=User,
    util:cancel_timer(erase({onhook_ref, RoleId})),
    User1 = User#ets_scene_user{offline_hosting ={Sign, Id}},
    Ref = start_battle(User1, FindType, EtsScene),
    put({onhook_ref, RoleId}, Ref).

%% 攻击 FindType:1怪优先|2人优先|3只找怪
start_battle(User, FindType, EtsScene) ->
    #ets_scene_user{id = Id, battle_attr = BA, offline_hosting = OfflineHosting, server_id = ServerId,
        scene = SceneId, scene_pool_id = ScenePoolId, copy_id = CopyId, x = X, y = Y, team = Team,
        quickbar_skills = SkillL, skill_cd = SkillCd, skill_link = SkillLink, figure=Figure} = User,

    case lib_scene_object_ai:select_a_skill(SkillL, SkillCd, 800, SkillLink, false, 0) of
        {false, NextSelectTime} -> %% 下一次攻击时间
            erlang:send_after(NextSelectTime, self(), {'host_battle_info', skill_cd, Id, FindType});

        %% 辅助技能
        {SkillId, SkillLv, _, ?SKILL_TYPE_ASSIST, IsReFindT, SpellTime, _, _} ->
            #skill{is_combo = IsCombo} = data_skill:get(SkillId, SkillLv),
            case lib_battle:assist_to_anyone(EtsScene, Id, Id, IsCombo, SkillId, SkillLv) of
                #skill_return{aer_info = User1, main_skill = MainSkillId} ->
                    case lib_scene_object_ai:is_combo(MainSkillId, User1#ets_scene_user.skill_combo) of
                        false -> skip;
                        {NextSkillId, NextSkillLv, NextSkillTime} -> %% 施放combo技能
                            ComboArgs = {X, Y, X, Y, NextSkillId, NextSkillLv, IsReFindT, 0},
                            erlang:send_after(NextSkillTime, self(), {'combo', Id, ComboArgs})
                    end,
                    erlang:send_after(SpellTime, self(), {'host_battle_info', assist_go_on, Id, FindType});
                _ ->
                    erlang:send_after(5000, self(), {'host_battle_info', assist_error, Id, FindType})
            end;

        %% 主动技能
        {SkillId, SkillLv, SkillDistance, ?SKILL_TYPE_ACTIVE, IsReFindT, SpellTime, SkillLinkInfo1, IsNormal} ->
            Res = case OfflineHosting of
                      {?BATTLE_SIGN_PLAYER, Id1} ->
                          case lib_scene_agent:get_user(Id1) of
                              #ets_scene_user{x=X1, y=Y1, battle_attr=#battle_attr{hp=Hp}} when Hp > 0 ->
                                  IsSafe = scene_landform:is_safe_pos(EtsScene#ets_scene.id, X1, Y1),
                                  case IsSafe of
                                      true  -> false;
                                      false -> {?BATTLE_SIGN_PLAYER, Id1, X1, Y1}
                                  end;
                              _ ->
                                  false
                          end;
                      {Sign1, Id1} ->
                          case lib_scene_object_agent:get_object(Id1) of
                              #scene_object{x=X1, y=Y1, battle_attr=#battle_attr{hp=Hp}, is_be_atted = 1} when Hp > 0 ->
                                  {Sign1, Id1, X1, Y1};
                              _ ->
                                  false
                          end;
                      _ ->
                          false
                  end,

            %% 获取攻击目标
            TargetInfo = case Res of
                             false ->
                                 Args = {BA#battle_attr.group, ?BATTLE_SIGN_PLAYER, Id, 0, 0},
                                 Pk = BA#battle_attr.pk,
                                 F = fun(Obj) ->
                                         case Obj of
                                             #scene_object{figure = ObjFigure, sign = ObjSign} ->
                                                 ObjServerId = 0, ObjTempId = 0;
                                             #ets_scene_user{figure = ObjFigure, server_id = ObjServerId, team = #status_team{team_id = ObjTempId}} ->
                                                 ObjSign = ?BATTLE_SIGN_PLAYER
                                         end,
                                        if
                                            Pk#pk.pk_status == ?PK_PEACE andalso ObjSign =/= ?BATTLE_SIGN_MON ->
                                                %% 和平状态只能打怪物
                                                false;
                                            Pk#pk.pk_status == ?PK_GUILD andalso (ObjFigure#figure.guild_id == Figure#figure.guild_id) ->
                                                %% 社团模式只能打不同社团的
                                                false;
                                            Pk#pk.pk_status == ?PK_FORCE andalso
                                            (ObjFigure#figure.guild_id == Figure#figure.guild_id orelse Team#status_team.team_id =:= ObjTempId) ->
                                                %% 强制只能打不同社团和不同组队的
                                                false;
                                            Pk#pk.pk_status == ?PK_DIFF_SERVER andalso ServerId == ObjServerId ->
                                                %% 服务器状态只能打不同服务器的
                                                false;
                                            true ->
                                                true
                                        end
                                     end,
                                 case lib_scene_calc:get_area_for_trace_mon_first(CopyId, X, Y, 600, Args, F, FindType) of
                                     false ->
                                         false;
                                     {FSign, FId, _, Xf, Yf} ->
                                         {FSign, FId, Xf, Yf}
                                 end;
                             _ ->
                                 Res
                         end,
            case TargetInfo of
                false ->
                    %% 没有找到可攻击目标:目标丢失
                    lost_target(Id);

                {TSign, TId, TX, TY} -> %% 将目标锁定
                    User1 = User#ets_scene_user{offline_hosting ={TSign, TId}},
                    lib_scene_agent:put_user(User1),

                    NowTime = utime:longunixtime(),
                    %%　防止站太远放技能不好看，这里攻击距离写死400
                    case lib_scene_object_ai:get_next_step(X, Y, SkillDistance, SceneId, CopyId, TX, TY, false) of
                        attack ->
                            case lib_skill_buff:is_can_attack(false, ?BATTLE_SIGN_PLAYER, BA#battle_attr.other_buff_list, NowTime) of
                                {false, _K, AttWaitMs} ->
                                    erlang:send_after(AttWaitMs, self(), {'host_battle_info', self_cannot_attack, Id, FindType});

                                true ->
                                    %% 发起攻击
                                    case lib_battle:object_start_battle(EtsScene, ?BATTLE_SIGN_PLAYER, Id, {target, TSign, TId}, SkillId, SkillLv, [], 0, undefined) of
                                        #skill_return{
                                            aer_info = BackUser,
                                            rx = OX, ry = OY, tx = AttX, ty = AttY, radian = Radian,
                                            main_skill = MainSkillId
                                        } ->
                                            case lib_scene_object_ai:is_combo(MainSkillId, BackUser#ets_scene_user.skill_combo) of
                                                false -> skip;
                                                {NextSkillId, NextSkillLv, NextSkillTime} ->
                                                    ComboArgs = {OX, OY, AttX, AttY, NextSkillId, NextSkillLv, IsReFindT, Radian},
                                                    erlang:send_after(NextSkillTime+100, self(), {'combo', Id, ComboArgs})
                                            end,
                                            lib_scene_agent:put_user(BackUser#ets_scene_user{skill_link=SkillLinkInfo1}),
                                            NSpellTime = ?IF(IsNormal == 1, SpellTime+300, SpellTime+600), %% +200 +500
                                            erlang:send_after(NSpellTime, self(), {'host_battle_info', active_go_on, Id, FindType});
                                        _O ->
                                            erlang:send_after(5000, self(), {'host_battle_info', active_error, Id, FindType})
                                    end
                            end;
                        {Xnext, Ynext} ->
                            #battle_attr{speed=Speed} = BA,
                            case lib_skill_buff:is_can_move(BA#battle_attr.other_buff_list, Speed, NowTime) of
                                {false, MoveWaitMs} ->
                                    erlang:send_after(MoveWaitMs, self(), {'host_battle_info', pursuit_no, Id, FindType});
                                false ->
                                    erlang:send_after(5000, self(), {'host_battle_info', pursuit_cannot_move, Id, FindType});
                                true ->
                                    mod_scene_agent:cast_to_scene(SceneId, ScenePoolId,  {'move', [CopyId, Xnext, Ynext, 0, X, Y, Xnext, Ynext, Id]}),
                                    lib_player:update_player_info(Id, [{xy, {Xnext, Ynext}}]),
                                    SleepTime = util:ceil(umath:distance({X,Y},{Xnext,Ynext})*1000/max(Speed, 1)),
                                    erlang:send_after(SleepTime+200, self(), {'host_battle_info', pursuit_yes, Id, FindType}) %% +200
                            end
                    end
            end;
        _Other->
            erlang:send_after(5000, self(), {'host_battle_info', skill_error, Id, FindType})
    end.

%% 战斗之后
host_battle_info(#ets_scene_user{battle_attr = BA} = User, EtsScene, _Return, FindType) ->
    if
        %% 死亡停止, 玩法自己会处理死亡后的行为
        BA#battle_attr.hp =< 0 orelse BA#battle_attr.ghost == 1 orelse BA#battle_attr.hide == 1 ->
            ok;

        true ->
            start_battle(User, FindType, EtsScene)
    end.

combo({OX, OY, X, Y, SkillId, SkillLv, IsReFindT, Radian}, User, EtsScene) ->
    #ets_scene_user{id = Id} = User,
    case data_skill:get(SkillId, SkillLv) of
        #skill{type = ?SKILL_TYPE_ACTIVE, is_combo = 1} ->
            Args = if
                IsReFindT -> find_target;
                true -> {xy, OX, OY, X, Y}
            end,

            case lib_battle:object_start_battle(EtsScene, ?BATTLE_SIGN_PLAYER, Id, Args, SkillId, SkillLv, Radian, [], undefined) of
                {false, _ErrCode} -> skip;
                #skill_return{
                    aer_info = BackUser,
                    rx = OX1, ry = OY1, tx = AttX, ty = AttY, radian = Radian,
                    main_skill = MainSkillId
                } ->
                    case lib_scene_object_ai:is_combo(MainSkillId, BackUser#ets_scene_user.skill_combo) of
                        false -> skip;
                        {NextSkillId, NextSkillLv, NextSkillTime} ->
                            ComboArgs = {OX1, OY1, AttX, AttY, NextSkillId, NextSkillLv, IsReFindT, Radian},
                            erlang:send_after(NextSkillTime, self(), {'combo', Id, ComboArgs})
                    end,
                    skip;
                _O ->
                    skip
            end;
        #skill{type = ?SKILL_TYPE_ASSIST, is_combo = 1} ->
            case lib_battle:assist_to_anyone(EtsScene, Id, Id, 1, SkillId, SkillLv) of
                #skill_return{aer_info = BackUser, main_skill = MainSkillId} ->
                    case lib_scene_object_ai:is_combo(MainSkillId, BackUser#ets_scene_user.skill_combo) of
                        false -> skip;
                        {NextSkillId, NextSkillLv, NextSkillTime} ->
                            ComboArgs = {OX, OY, X, Y, NextSkillId, NextSkillLv, IsReFindT, 0},
                            erlang:send_after(NextSkillTime, self(), {'combo', Id, ComboArgs})
                    end,
                    skip;
                _ -> skip
            end;
        _ -> skip
    end.

%% TODO 丢失攻击目标
lost_target(RoleId) ->
    erlang:send_after(3000, self(), {hosting_lost_target, RoleId}),
    ok.
