%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% 随机自动行为
%%% 移动 及 战斗
%%% @end
%%% -------------------------------------------------------
-module(cli_simu_auto).
-export([
        auto_do/1
    ]).
-include("cli_simu.hrl").

%% -------------------------------------------------------------------
%% 角色主进程内部进程字典存储怪物、角色列表数据
%% -------------------------------------------------------------------

%% 自动行动
auto_do(State) ->
    RandDoList = get_rand_weight(),
    AutoDo = urand:rand_with_weight(RandDoList),
    minus_rand_weight(AutoDo, -3),
    case AutoDo of
        rand_move ->
            rand_move(State),
            State;
        battle ->
            %% 搜索怪物
            do_battle(State);
        _ ->    %% 未定义的行为
            State
    end.

get_rand_weight() ->
    case get(rand_weight) of
        [_|_] = RandWeightList ->
            % [{V, K} || {V, K} <- RandWeight, is_integer(V)];
            RandWeightList;
        _ ->
            [{10, rand_move}, {90, battle}]
    end.

rand_weight_max(Action) ->
    List = [
        {rand_move, 90}
        ,{battle,   80}
    ],
    case lists:keyfind(Action, 1, List) of
        {_, Val} when is_integer(Val) ->
            Val;
        _ -> 50
    end.

minus_rand_weight(Action, ChangeVal) when ChangeVal =< 0 ->
    RandWeightList = get_rand_weight(),
    case lists:keyfind(Action, 2, RandWeightList) of
        {OldVal, Action} ->
            TmpVal = max(0, OldVal + ChangeVal),
            NewVal =
            case TmpVal =:= 0 of
                true  -> rand_weight_max(Action);
                false -> TmpVal
            end,
            NewRandWeightList = lists:keystore(Action, 2, RandWeightList, {NewVal, Action}),
            put(rand_weight, NewRandWeightList);
        _ ->
            ignore
    end;
minus_rand_weight(_Action, _ChangeVal) ->
    ignore.

rand_move(#cli_role{scene_id = SceneId, x = X, y = Y}) ->
    TargetX = X + urand:list_rand([-1, 1]) * urand:rand(90, 220),
    TargetY = Y + urand:list_rand([-1, 1]) * urand:rand(90, 220),
    [BroadcastX, BroadcastY] = [TargetX, TargetY],
    [FlyX, FlyY] = [TargetX, TargetY],
    MoveType = 0,
    Data = [SceneId, TargetX, TargetY, MoveType, BroadcastX, BroadcastY, FlyX, FlyY],
    cli_simu_proto:pack_send(12001, Data).

%% 活着的时候，而且懂打人技术才可以战斗
do_battle(State = #cli_role{x = MyX, y = MyY, skill_list = [_|_], hp = Hp}) when Hp > 0 ->
    MonList = cli_scene:get_mon_list(),
    RoleList = cli_scene:get_scene_role_list(),
    case MonList =:= [] andalso RoleList =:= [] of
        true  ->
            rand_move(State),
            State;
        false ->
            NearRoleList = find_near_list(MyX, MyY, RoleList, []),
            NearMonList  = find_near_list(MyX, MyY, MonList, []),
            case NearRoleList =:= [] andalso NearMonList =:= [] of
                true  ->
                    %% TODO 找到最近的，跑到那边，或者直接飞到那里
                    %% 暂时改为随机移动
                    rand_move(State),
                    State;
                false ->
                    do_battle_near(State, NearRoleList, NearMonList)
            end
    end;
do_battle(State) ->
    rand_move(State),
    State.

%% 找到附近活着的对象
find_near_list(MyX, MyY, [Target = #scene_role{x = X, y = Y, hp = Hp} | TargetList], Acc) when Hp > 0 ->
    NewAcc =
    case check_near(MyX, MyY, X, Y) of
        true  -> [Target | Acc];
        false -> Acc
    end,
    find_near_list(MyX, MyY, TargetList, NewAcc);
find_near_list(MyX, MyY, [Target = #cli_mon{x = X, y = Y, hp = Hp} | TargetList], Acc) when Hp > 0 ->
    NewAcc =
    case check_near(MyX, MyY, X, Y) of
        true  -> [Target | Acc];
        false -> Acc
    end,
    find_near_list(MyX, MyY, TargetList, NewAcc);
find_near_list(MyX, MyY, [_|TargetList], Acc) ->
    find_near_list(MyX, MyY, TargetList, Acc);
find_near_list(_MyX, _MyY, _, Acc) ->
    Acc.

check_near(Xa, Ya, Xb, Yb) ->
    abs(Xa - Xb) < 600 andalso abs(Ya - Yb) < 600.

do_battle_near(State = #cli_role{skill_list = SkillList, x = MyX, y = MyY}, NearRoleList, NearMonList) ->
    %% 技能CD未理会，有可能选中冷却中的技能
    {SkillId, _SkillLv} = urand:list_rand(SkillList),
    %% TODO
    %% 应当优化为记录当前有无攻击对象，一定机制切换对象。
    %% 一定机率只攻击怪物不攻击人物
    %% 因为打人的影响因素太多，可能打不了，测试达不到效果
    HitRoles = urand:get_rand_list(3, NearRoleList),
    HitMons  = urand:get_rand_list(5, NearMonList),
    AttAngle = 0,      %% 要计算角度，这里不算了，不影响简单测试（貌似前端也没用了）
    {AttX, AttY} = case {HitRoles, HitMons} of
        {[#scene_role{x = X, y = Y} | _], _} -> {X, Y};
        {_, [#cli_mon{x = X, y = Y} | _]} -> {X, Y};
        _ -> {MyX, MyY}
    end,
    HitRoleIds = [RoleIdX || #scene_role{id = RoleIdX} <- HitRoles],
    HitMonIds  = [MonIdX  || #cli_mon{id = MonIdX} <- HitMons],
    cli_simu_proto:pack_send(20001, [HitMonIds, HitRoleIds, SkillId, AttX, AttY, AttAngle]),
    State.

