%%% -------------------------------------------------------
%%% @author huangyongxing@yeah.net
%%% @doc
%%% 战斗伤害计算相关接口
%%% @end
%%% -------------------------------------------------------
-module(lib_battle_hurt_calc).
-export([
        calc_hurt_type/4
        ,calc_hurt/6
    ]).

%% 调试战斗时使用的接口，仅供调试使用
-export([
        print_attr/1
        ,battler_base/1
    ]).

-include("common.hrl").
-include("battle.hrl").
-include("server.hrl").
-include("scene.hrl").
-include("skill.hrl").
-include("attr.hrl").

-include("figure.hrl").

%% -------------------------------------------------------
%% 策划战斗公式中的系数调整频率应该相当低，
%% 通常在项目之初基本已确定，如有调整往往并非单纯修改系数，
%% 而是要配合公式修改，故宜直接编码在代码之中，可以用宏来定义常量，
%% 而不应使用后台进行战斗参数的配置，增加额外的维护成本和风险。
%% -------------------------------------------------------
-define(HURT_FACTOR_PVP_MINOR,      0.25).  % PVP次要目标伤害系数
-define(HURT_FACTOR_CRIT_BASE,       1.5).  % 暴击伤害倍率基础值
-define(HURT_FACTOR_HEART_BASE,        2).  % 会心一击伤害倍率基础值
-define(HURT_FACTOR_PARRY,           0.5).  % 格挡伤害倍率
-define(HURT_FACTOR_PVP_MINOR_SPECAL,0.05). % PVP次要目标伤害系数（特殊场景）
%% -------------------------------------------------------

%% -------------------------------------------------------
%% 受击类型判定
%% -------------------------------------------------------

calc_hurt_type(_Aer, _Der, _IsCalc = 0, _Time) ->
    ?HURT_TYPE_IMMUE;
calc_hurt_type(Aer, Der, _IsCalc, BattleTime) ->
    % 攻击方
    #battle_status{
        battle_attr = #battle_attr{attr = AttrA}
    } = Aer,
    #attr{
        hit = HitA, hit_ratio = HitRatioA,
        crit = CritA, crit_ratio = CritRatioA,
        heart_ratio = HeartRatioA, stab_ratio = StabRatioA
    } = AttrA,
    %% 防守方
    #battle_status{
        kind = Kind, battle_attr = BAD,
        motion_no_injury = MotionNoJnuryTime
    } = Der,
    #battle_attr{attr = AttrD, skill_effect=SkillEffD} = BAD,
    #attr{
        dodge = DodgeD, dodge_ratio = DodgeRatioD,
        ten = TenD, uncrit_ratio = UnCritRatioD,
        heart_resist_ratio = HeartResistRatioD,
        parry_ratio = ParryRatioD
    } = AttrD,
    if

        SkillEffD#skill_effect.immue == 1
        orelse SkillEffD#skill_effect.no_battle == 1
        orelse Kind == ?MON_KIND_COLLECT
        orelse Kind == ?MON_KIND_TASK_COLLECT ->
            % ?INFO("--- 免疫 - [Aer:~ts, Der:~ts]", [battler_base(Aer), battler_base(Der)]),
            ?HURT_TYPE_IMMUE;

        SkillEffD#skill_effect.shield_count > 0 ->
            % ?INFO("--- 盾 - [Aer:~ts, Der:~ts]", [battler_base(Aer), battler_base(Der)]),
            ?HURT_TYPE_SHIELD;

        %% 免伤时间
        BattleTime < MotionNoJnuryTime ->
            ?HURT_TYPE_IMMUE;

        true ->
            %% 所有数值取整，以杜绝浮点数运算误差导致权重随机计算时超出范围的可能性
            DodgeRatio = calc_dodge_ratio(DodgeD, HitA, DodgeRatioD, HitRatioA),
            CritRatio  = calc_crit_ratio(CritA, TenD, CritRatioA, UnCritRatioD),
            HeartRatio = calc_heart_strike_ratio(HeartRatioA, HeartResistRatioD),
            ParryRatio = calc_parry_ratio(StabRatioA, ParryRatioD),
            RatioSum   = DodgeRatio + CritRatio + HeartRatio + ParryRatio,
            %% 普通伤害的机率不应低于1/5，
            %% 如果不能满足，需要调整权重和，将权重和调整为125%即可保证有20%的普通伤害
            %% 如果可以满足，则保证权重和为预设权重和，这种情况下普通伤害>=20%
            FixRandMax =
            case RatioSum > 0.8 * ?RATIO_MAX of
                true  ->    %% 向上取整可保证概率>=20%（四舍五入可能导致概率稍小于20%）
                    util:ceil(RatioSum * 1.25);
                false ->
                    ?RATIO_MAX
            end,
            NormalRatio = FixRandMax - RatioSum,
            %% 实际上，随机数为 Rand = urand:rand(1, FixRandMax),
            RandWeightList = [
                {DodgeRatio,    ?HURT_TYPE_MISS}
                ,{CritRatio,    ?HURT_TYPE_CRIT}
                ,{HeartRatio,   ?HURT_TYPE_HEART}
                ,{ParryRatio,   ?HURT_TYPE_PARRY}
                ,{NormalRatio,  ?HURT_TYPE_NORMAL}
            ],
            Val = urand:rand_with_weight(RandWeightList),
            % ?INFO("伤害类型判定:~w, - [Aer:~ts, Der:~ts]", [Val, battler_base(Aer), battler_base(Der)]),
            Val
    end.

%% -------------------------------------------------------
%% 伤害值计算
%% -------------------------------------------------------

%% 计算伤害 - 免疫、闪避、无敌等不伤状态
calc_hurt(_Aer, Der, _SkillConfig, ?HURT_TYPE_IMMUE, _SceneType, _) ->
    {Der#battle_status.battle_attr#battle_attr.hp, 0};
calc_hurt(_Aer, Der, _SkillConfig, ?HURT_TYPE_MISS, _SceneType, _) ->
    {Der#battle_status.battle_attr#battle_attr.hp, 0};
calc_hurt(_Aer, Der, _SkillConfig, ?HURT_TYPE_SHIELD, _SceneType, _) ->
    {Der#battle_status.battle_attr#battle_attr.hp, 0};

%% 计算伤害 - 固定伤害
calc_hurt(_Aer, Der = #battle_status{
        sign = Sign,
        battle_attr = #battle_attr{del_hp_each_time = DelHpEachTime}
    }, _SkillConfig, _HurtType, _SceneType, _) when Sign =:= ?BATTLE_SIGN_MON andalso DelHpEachTime =/= [] ->
    % ?INFO("固定伤害"),
    calc_del_hp_each(Der, DelHpEachTime);

%% 计算伤害 - 技能致死效果
calc_hurt(_Aer, _Der = #battle_status{
        battle_attr = #battle_attr{hp = DerHp, skill_effect = #skill_effect{killed = 1}}
    }, _SkillConfig, _HurtType, _SceneType, _) ->
    % ?INFO("致死效果"),
    {0, DerHp};

%% 计算伤害 - 通常情况下的伤害计算逻辑
calc_hurt(Aer, Der, SkillConfig, HurtType, SceneType, GuardDunBuff) ->
    %% 攻击方
    #battle_status{sign = SignAer} =  Aer,
    %% 防守方
    #battle_status{sign = SignDer, scene = DerScene, boss = _BossD,
        battle_attr = #battle_attr{hp = HpD},
        boss_crush_r = BossCrushR
    } = Der,
    AerDerType = calc_aer_der_union_type(SignAer, SignDer),

    % RealSignA = mod_battle:calc_real_sign(SignA),
    % IsBoss = ?IS_BOSS(BossD),

    %% 伤害计算
    HurtBase0 = calc_hurt_base(Aer, Der, SkillConfig),
    
    %% 赏金幻魔场景内，pvp人对人伤害强制缩减为1%
    case mod_battle:calc_real_sign(SignAer) =:= ?BATTLE_SIGN_PLAYER
        andalso mod_battle:calc_real_sign(SignDer) =:= ?BATTLE_SIGN_PLAYER
        andalso local_boss_api:is_reward_boss_scene(DerScene)
    of
        true  ->
            LastHurt = round(HurtBase0 * 0.01);
        false ->
            %%联合BUFF对伤害造成影响
            HurtBase  = custom_unite_buff:calc_buff_hurt(Aer,Der,HurtBase0),
    
            %% PVP、PVE调整伤害
            HurtFixBattlerType = calc_hurt_battler_type(Aer, Der, AerDerType, HurtBase, SceneType),
    
            %% 碾压系数
            BossFactor = calc_boss_crush(BossCrushR, Aer, Der, DerScene),
    
            HurtFix = calc_with_hurt_type(Aer, Der, SkillConfig, HurtFixBattlerType, BossFactor, HurtType),
    
            BuffHurt = lib_dungeon_guard:calc_buff_hurt(HurtFix, GuardDunBuff),
    
            LastHurt = round(BuffHurt)
    end,
    % ?INFO("伤害计算：HurtBase:~w, LastHurt:~w, Aer:~ts, Der:~ts", [HurtBase, LastHurt, battler_base(Aer), battler_base(Der)]),
    % print_attr(Aer),
    % print_attr(Der),
    {max(0, HpD - LastHurt), min(HpD, LastHurt)}.

%% -------------------------------------------------------
%% Internal Functions
%% -------------------------------------------------------

%% 计算闪避率机率
%% MAX(0, 守方闪避/（攻方命中+守方闪避+500）*0.15+守方闪避几率-攻方命中几率）
calc_dodge_ratio(DodgeD, HitA, DodgeRatioD, HitRatioA) ->
    DodgeRatio = DodgeD / (HitA + DodgeD + 500) * 0.15 * ?RATIO_MAX + (DodgeRatioD - HitRatioA),
    max(0, round(DodgeRatio) ).

%% 计算暴击机率
%% MAX(0, 攻方暴击/（攻方暴击+守方坚韧+500）*0.3+攻方暴击几率-守方暴击抵抗）
calc_crit_ratio(CritA, TenD, CritRatioA, UnCritRatioD) ->
    CritRatio = CritA / (CritA + TenD + 500) * 0.3 * ?RATIO_MAX + (CritRatioA - UnCritRatioD),
    max(0, round(CritRatio) ).

%% 计算会心一击机率
calc_heart_strike_ratio(HeartRatioA, HeartResistRatioD) ->
    max(0, round(HeartRatioA - HeartResistRatioD) ).

%% 计算格挡机率
calc_parry_ratio(StabRatioA, ParryRatioD) ->
    max(0, round(ParryRatioD - StabRatioA) ).

%% 对战类型: 1pvp | 2pve
calc_aer_der_union_type(?BATTLE_SIGN_PLAYER, ?BATTLE_SIGN_PLAYER)   -> 1;
calc_aer_der_union_type(?BATTLE_SIGN_DUMMY, ?BATTLE_SIGN_DUMMY)     -> 1;
calc_aer_der_union_type(?BATTLE_SIGN_DUMMY, ?BATTLE_SIGN_PLAYER)    -> 1;
calc_aer_der_union_type(?BATTLE_SIGN_PLAYER, ?BATTLE_SIGN_DUMMY)    -> 1;
calc_aer_der_union_type(?BATTLE_SIGN_PLAYER, ?BATTLE_SIGN_MON)      -> 2;
calc_aer_der_union_type(?BATTLE_SIGN_MON, ?BATTLE_SIGN_PLAYER)      -> 2;
calc_aer_der_union_type(?BATTLE_SIGN_MON, ?BATTLE_SIGN_MON)         -> 2;
calc_aer_der_union_type(_, _) -> 2.

%% 计算固定伤害
calc_del_hp_each(Der, DelHpEachTime) ->
    #battle_status{
        battle_attr = #battle_attr{hp = HpD, hp_lim = HpLim, attr = #attr{hurt_del_ratio = HurtDelRatioD}}
    } = Der,
    case DelHpEachTime of
        [DelHp, DelHp|_] when is_integer(DelHp)->
            NewDelHp = round(DelHp * (1 - max(HurtDelRatioD/?RATIO_MAX, 0))),
            {max(0, HpD-NewDelHp), NewDelHp};
        [MinDelHp, MaxDelHp|_] when is_integer(MinDelHp), is_integer(MaxDelHp), MinDelHp > 0, MaxDelHp > 0 ->
            DelHp = urand:rand(MinDelHp, MaxDelHp),
            NewDelHp = round(DelHp * (1 - max(HurtDelRatioD/?RATIO_MAX, 0))),
            {max(0, HpD-NewDelHp), NewDelHp};
        [MinDelHpP, MaxDelHpP|_] when is_float(MinDelHpP), is_float(MaxDelHpP), MinDelHpP > 0, MaxDelHpP > 0 ->
            MinDelHp = round(MinDelHpP*HpLim),
            MaxDelHp = round(MaxDelHpP*HpLim),
            DelHp = urand:rand(MinDelHp, MaxDelHp),
            NewDelHp = round(DelHp * (1 - max(HurtDelRatioD/?RATIO_MAX, 0))),
            {max(0, HpD-NewDelHp), NewDelHp};
        _ ->
            {HpD-1, 1}
    end.

%% 计算boss的碾压伤害
calc_boss_crush(BossCrushR, #battle_status{sign = ?BATTLE_SIGN_MON, mid = MonId, boss = BossType},
 #battle_status{sign = ?BATTLE_SIGN_PLAYER, battle_attr = #battle_attr{attr = Attr}, figure = #figure{lv = RoleLv, power = Power}}, DerScene) ->
    IsRewardBossScene = local_boss_api:is_reward_boss_scene(DerScene),
    IsDesertedBossScene = local_boss_api:is_deserted_boss_scene(DerScene),
    IsHomeBossScene   = local_boss_api:is_home_boss_scene(DerScene),
    if BossCrushR =< 0 andalso (IsDesertedBossScene orelse IsHomeBossScene) ->
            local_boss_api:calc_boss_crush_r(BossType, MonId, [Power, RoleLv, Attr]);
        BossCrushR > 1 andalso IsRewardBossScene ->
            BossCrushR;
        true ->
            1
    end;
% calc_boss_crush(0, _Atter, _Der, _DerScene) -> 1;
% calc_boss_crush(BossCrushR, ?BATTLE_SIGN_MON, ?BATTLE_SIGN_PLAYER, DerScene) when BossCrushR > 1->
%     IsRewardBossScene = local_boss_api:is_reward_boss_scene(DerScene),
%     IsDesertedBossScene = local_boss_api:is_deserted_boss_scene(DerScene),
%     if
%         IsRewardBossScene   -> BossCrushR;
%         IsDesertedBossScene -> BossCrushR;
%         true -> 1
%     end;
calc_boss_crush(_BossCrushR, _Atter, _Der, _DerScene) -> 1.

%% 计算基础伤害
calc_hurt_base(Aer, Der, SkillConfig) ->
    %% 攻击方
    #battle_status{battle_attr = BAAer, sign = AerSign, entity_attr = AerEntityAttr} =  Aer,
    #battle_attr{
        attr = #attr{
            att = AttAer
            ,hurt_add_ratio = HurtAddRatioAer
            ,skill_hurt_add_ratio = SkillHurtAddRatioAer
        }
    } = BAAer,
    %% 防守方
    #battle_status{battle_attr = BADer} = Der,
    #battle_attr{
        attr = #attr{
            def = DefDer
            ,hurt_del_ratio = HurtDelRatioDer
            ,skill_hurt_del_ratio = SkillHurtDelRatioDer
        }
    } = BADer,
    #skill{id = SkillId, lv_data = #skill_lv{hurt = SkillHurtAddRatio} } = SkillConfig,
    IsNormalSkill = lib_skill_api:is_normal(SkillId),
    %% 技能伤害系数
    SkillHurtFactor = if
        IsNormalSkill ->
            SkillHurtAddRatio / ?RATIO_MAX;
        true ->
            (SkillHurtAddRatio + SkillHurtAddRatioAer - SkillHurtDelRatioDer) / ?RATIO_MAX
    end,
    if
        AttAer =< DefDer ->
            %% 不能破防情况
            % ?INFO("未破防 [aer:~ts, der:~ts]", [battler_base(Aer), battler_base(Der)]),
            AttAer * 0.05;
        AerSign =:= ?BATTLE_SIGN_PARTNER ->
            #attr{att = PartnerAtt} = AerEntityAttr,
            TotalAtt = erlang:round(AttAer * 0.1 + PartnerAtt + 100),
            erlang:round(TotalAtt * (1 + SkillHurtFactor));
        AerSign =:= ?BATTLE_SIGN_WEAPON ->
            #attr{att = BabyAtt} = AerEntityAttr,
            TotalAtt = erlang:round(AttAer * 0.2 + BabyAtt + 200),
            erlang:round(TotalAtt * (1 + SkillHurtFactor));
        AerSign =:= ?BATTLE_SIGN_CHILD ->
            #attr{att = ChildAtt} = AerEntityAttr,
            TotalAtt = erlang:round(AttAer * 0.1 + ChildAtt + 100),
            erlang:round(TotalAtt * (1 + SkillHurtFactor));
        true  ->
            HurtSkillAdjust = (AttAer - DefDer) * (1 + SkillHurtFactor) + AttAer * 0.08,
            % ?INFO("破防 [aer:~ts, der:~ts], HurtAddRatioAer:~w,HurtDelRatioDer:~w~n,"
            %     "   AttAer:~w,DefDer:~w,SkillHurtFactor:~w, HurtSkillAdjust:~w",
            %     [battler_base(Aer), battler_base(Der), HurtAddRatioAer, HurtDelRatioDer,
            %         AttAer, DefDer, SkillHurtFactor, HurtSkillAdjust
            %     ]
            % ),
            %% 分子分母都放大，节省计算
            FinalHurt = HurtSkillAdjust * (1 +
                (HurtAddRatioAer - HurtDelRatioDer) /
                max(?RATIO_MAX, HurtAddRatioAer + HurtDelRatioDer + 0.8 * ?RATIO_MAX)
            ),
            FinalHurt
    end.

%% PVP的情况下，需要对伤害进行调整
calc_hurt_battler_type(Aer, Der, _AerDerType = 1, HurtBase, SceneType) ->
    %% 攻击方
    #battle_status{battle_attr = BAAer} =  Aer,
    #battle_attr{attr = #attr{pvp_hurt_add_ratio = PVPHurtAddRatioAer}} = BAAer,
    %% 防守方
    #battle_status{battle_attr = BADer, is_main = IsMain} =  Der,
    #battle_attr{attr = #attr{pvp_hurt_del_ratio = PVPHurtDelRatioDer}} = BADer,
    %% PVP伤害修正（分子分母都放大，节省计算）
    PVPHurtAddFactor = (PVPHurtAddRatioAer - PVPHurtDelRatioDer) /
    max(?RATIO_MAX, (PVPHurtAddRatioAer + PVPHurtDelRatioDer) + 0.8 * ?RATIO_MAX),
    Hurt = HurtBase * (1 + PVPHurtAddFactor),
    %% PVP伤害系数 - PVP非主目标伤害衰减系数
    case IsMain == 0 of
        true  ->
            case lists:member(SceneType, [?SCENE_TYPE_DESERTED_BOSS, ?SCENE_TYPE_REWARD_BOSS]) of
                true  -> Hurt * ?HURT_FACTOR_PVP_MINOR_SPECAL;
                false -> Hurt * ?HURT_FACTOR_PVP_MINOR
            end;
        false -> Hurt
    end;
%% PVE（或怪物PK）的情况下
calc_hurt_battler_type(Aer, Der, _AerDerType, HurtBase, _SceneType) ->
    #battle_status{battle_attr = BattleAttrAer,
        boss = BossTypeAer, kind = KindAer,
        sign = SignAer
    } = Aer,
    #battle_status{battle_attr = BattleAttrDer,
        boss = BossTypeDer, kind = KindDer,
        sign = SignDer
    } = Der,
    #battle_attr{attr = #attr{
            boss_hurt_add_ratio = BossHurtAddRatio
            ,mon_hurt_add_ratio = MonHurtAddRatio
        }} = BattleAttrAer,
    #battle_attr{attr = #attr{
            boss_hurt_del_ratio = BossHurtDelRatio
            ,mon_hurt_del_ratio = MonHurtDelRatio
        }} = BattleAttrDer,
    RealSignAer = mod_battle:calc_real_sign(SignAer),
    RealSignDer = mod_battle:calc_real_sign(SignDer),
    %% 忽略怪物之间PK的情况，如果是怪物互相PK，
    %% 相关属性理论上应为0，使用任意一个公式均OK
    BossTypeFactor =
    if
        %% 非一般性质的怪物（怪物包括BOSS及普通怪），通常例如采集怪、塔防怪等
        (RealSignAer =:= ?BATTLE_SIGN_MON andalso KindAer =/= 0) orelse
        (RealSignDer =:= ?BATTLE_SIGN_MON andalso KindDer =/= 0) ->
            % ?INFO("攻方或守方是非一般性质的怪物，不计bossType伤害调整"),
            1;
        %% 攻击者是一般怪物
        RealSignAer =:= ?BATTLE_SIGN_MON andalso
        BossTypeAer >= ?MON_NORMAL andalso BossTypeAer =< ?MON_ELITE ->
            % ?INFO("攻击者是一般怪物，计算mon_hurt_del_ratio"),
            1 - MonHurtDelRatio / ?RATIO_MAX;
        %% 防守者是一般怪物
        RealSignDer =:= ?BATTLE_SIGN_MON andalso
        BossTypeDer >= ?MON_NORMAL andalso BossTypeDer =< ?MON_ELITE ->
            % ?INFO("防守者是一般怪物，计算mon_hurt_add_ratio"),
            1 + MonHurtAddRatio / ?RATIO_MAX;
        %% 攻击者是BOSS
        RealSignAer =:= ?BATTLE_SIGN_MON andalso
        BossTypeAer >= ?MON_REWARD_BOSS andalso BossTypeAer =< ?MON_DESERTED_ELITE ->
            % ?INFO("攻击者是BOSS，计算boss_hurt_del_ratio"),
            1 - BossHurtDelRatio / ?RATIO_MAX;
        %% 防守者是BOSS
        RealSignDer =:= ?BATTLE_SIGN_MON andalso
        BossTypeDer >= ?MON_REWARD_BOSS andalso BossTypeDer =< ?MON_DESERTED_ELITE ->
            % ?INFO("防守者是BOSS，计算boss_hurt_add_ratio"),
            1 + BossHurtAddRatio / ?RATIO_MAX;
        true ->
            % ?INFO("超出bossType伤害调整的其他情况，不计算"),
            1
    end,
    % ?INFO("boss type hurt factor: ~w", [BossTypeFactor]),
    max(0.0001, BossTypeFactor) * HurtBase.

calc_with_hurt_type(
    #battle_status{sign = ?BATTLE_SIGN_PARTNER}, _Der, _SkillConfig, Hurt, _BossFactor, _HurtType
) ->
    Hurt;
calc_with_hurt_type(
    #battle_status{sign = ?BATTLE_SIGN_WEAPON}, _Der, _SkillConfig, Hurt, _BossFactor, _HurtType
) ->
    Hurt;
calc_with_hurt_type(
        #battle_status{sign = ?BATTLE_SIGN_CHILD}, _Der, _SkillConfig, Hurt, _BossFactor, _HurtType
) ->
    Hurt;
calc_with_hurt_type(Aer, Der, SkillConfig, Hurt, BossFactor, HurtType) ->
    #battle_status{battle_attr = #battle_attr{
            attr = #attr{
                att = AttAer
                ,crit_hurt_add_ratio = CritHurtAddRatioAer
                ,heart_add_hurt = HeartAddHurtAer
                ,final_hurt_add = FinalHurtAddAer
            }
        }
    } = Aer,
    #battle_status{battle_attr = #battle_attr{
            attr = #attr{
                crit_hurt_del_ratio = CritHurtDelRatioDer
                ,heart_del_hurt = HeartDelHurtDer
                ,final_hurt_del = FinalHurtDelDer
            }
        }
    } = Der,
    #skill{lv_data = #skill_lv{hurt_val = HurtVal}} = SkillConfig,
    HurtFactor =
    case HurtType of
        ?HURT_TYPE_CRIT ->
            ?HURT_FACTOR_CRIT_BASE + (CritHurtAddRatioAer - CritHurtDelRatioDer) / ?RATIO_MAX;
        ?HURT_TYPE_HEART ->
            ?HURT_FACTOR_HEART_BASE + (HeartAddHurtAer - HeartDelHurtDer) / ?RATIO_MAX;
        ?HURT_TYPE_PARRY ->
            ?HURT_FACTOR_PARRY;
        _ ->    % 普通倍率伤害 （免疫、无敌之类在上层逻辑已经检查，不会计算伤害值）
            1
    end,
    %% 判定的伤害类型造成的倍率浮动 及 自然浮动
    HurtAfterFactor = HurtFactor * Hurt * urand:rand(9000, 11000) / ?RATIO_MAX,
    %% 计入最终伤害加成与减免（固定伤害）（为防止负值，加入伤害保底计算）
    %% 最后才算BOSS碾压（发生BOSS碾压会放大最终伤害加成值）
    max(
        AttAer * 0.05,
        HurtAfterFactor + HurtVal + FinalHurtAddAer - FinalHurtDelDer
    ) * BossFactor.

%% -------------------------------------------------------
%% 调试辅助专用接口
%% -------------------------------------------------------
print_attr(Battler = #battle_status{battle_attr = BA}) ->
    sub_print_attr(Battler, BA);
print_attr(Battler = #player_status{battle_attr = BA}) ->
    sub_print_attr(Battler, BA);
print_attr(_) ->
    ignore.

sub_print_attr(Battler, #battle_attr{attr = Attr}) ->
    case get(print_attr) of
        undefined ->
            k:l(),
            put(print_attr, 1);
        _ -> ignore
    end,
    ?INFO("[~ts], ~ts", [battler_base(Battler), recon_rec:format_tuple(Attr)]).

%% 获取战斗方基本信息，便于调试打印
battler_base(#battle_status{id = Id, sign = Sign, figure = #figure{name = Name}}) ->
    io_lib:format("~w,~ts,sign-~w", [Id, Name, Sign]);
battler_base(#player_status{id = Id, figure = #figure{name = Name}}) ->
    io_lib:format("~w,~ts,sign-null", [Id, Name]).

%% -------------------------------------------------------
