%% ---------------------------------------------------------------------------
%% @doc 属性通用模块
%% @author zzm
%% @since  2014-06-25
%% @deprecated 本模块主要用于各个功能模块中的属性保存，同时使得易于修改属性类型
%% ---------------------------------------------------------------------------
-module(lib_player_attr).

-include("predefine.hrl").
-include("attr.hrl").
-include("common.hrl").
-include("server.hrl").
-include("equipment.hrl").

%% 战斗力、属性计算相关
-export([
        calc_attr_power/1                   % 计算属性的战力价值
        ,ensure_attr_int/1                  % 确保属性值为整数
        ,attr_count_with_extra/1            % 属性额外加成计算
        ,calc_attr_power_partial/3          % 计算在全局属性影响下，某部分属性的战力价值
        ,update_module_power/3              % 计算模块战力
        ,calc_preview_power/2
        ,calc_attr_list_power/2
        ,calc_hp_while_hp_lim_change/3      % 血量上限属性变动时同步计算血量调整
        ,calc_hp_resume_add/4               % 根据相关属性计算单位时间血量自动回复值
    ]).

%% 属性转换相关
-export([
        get_value_by_id/2                   % 根据属性id从属性中获取值
        ,get_value_by_ids/2                 % 根据属性id列表从属性中获取值
        ,set_value_by_id/3                  % 对某个属性值赋值
        ,list_add_to_attr/2                 % 属性列表增加到属性Map
        ,add_attr/2                         % 属性相加
        ,partial_attr_convert/1             % 功能内部的基础属性加成转换成基础属性
        ,equipment_attr_convert/1           % 将功能内部的对装备系统的加成属性转为基础属性
        ,count_lv_attr/2                    % 计算等级基础属性百分比加成属性
        ,filter_specify_attr/2              % 从属性列表中筛选出指定属性
        ,set_battle_attr/2                  % 设置战斗属性
        ,set_attr_by_ratio/2                % 按万分比设置战斗属性

        ,attr_to_battle_attr/1              % 主属性转化为战斗属性
        ,get_list_base_attr_kv/1            % 返回八个基础属性
        ,get_list_base_attr/1               % 返回八个基础属性
    ]).

%% 属性列表类型
%% 详细编号(AttrbuteId)参考predefine.hrl文件中的编号
-type attr_key_value_list() :: [{AttrbuteId::integer(), Value::integer() | float()}].

%% ---------------------------------------------------------------------------
%% @doc 根据属性id从record中获取属性值
-spec get_value_by_id(AttributeId, AttrMaps) ->  Return when
    AttributeId :: integer(),       %% 属性id
    AttrMaps    :: #attr{} | #{},   %% 属性记录
    Return      :: integer().       %% 属性值
%% ---------------------------------------------------------------------------
get_value_by_id(AttributeId, AttrMaps) when is_map(AttrMaps) ->
    maps:get(AttributeId, AttrMaps, 0);
get_value_by_id(AttributeId, Attr) when is_record(Attr, attr)->
    Index = attr_conv:get_attr_index(AttributeId),
    case Index > 0 of
        true  -> element(Index, Attr);
        false -> 0
    end;
get_value_by_id(_, _) -> 0.

get_value_by_ids(AttributeIds, AttrMaps) ->
    [get_value_by_id(AttributeId, AttrMaps) || AttributeId <- AttributeIds].

%% ---------------------------------------------------------------------------
%% @doc 根据属性id从record中获取属性值
-spec set_value_by_id(AttributeId, Value, AttrMaps) ->  Return when
    AttributeId :: integer(),       %% 属性id
    Value       :: integer(),       %% 属性值
    AttrMaps    :: #attr{} | #{},   %% 属性记录
    Return      :: #attr{} | #{}.   %% 属性记录
%% ---------------------------------------------------------------------------
set_value_by_id(AttributeId, Value, AttrMaps) when is_map(AttrMaps) ->
    maps:put(AttributeId, Value, AttrMaps);
set_value_by_id(AttributeId, Value, Attr) when is_record(Attr, attr)->
    Index = attr_conv:get_attr_index(AttributeId),
    case Index > 0 of
        true  -> setelement(Index, Attr, Value);
        false -> Attr
    end;
set_value_by_id(_, _, Attr) -> Attr.

%% 属性列表增加到属性
%% return map
list_add_to_attr([], AttrMaps) -> AttrMaps;
list_add_to_attr([{AttributeId, Value} | T], AttrMaps) ->
    OldValue = maps:get(AttributeId, AttrMaps, 0),
    list_add_to_attr(T, AttrMaps#{AttributeId => OldValue + Value}).

%% ---------------------------------------------------------------------------
%% @doc %% 属性相加
-spec add_attr(OutPutType, AttrListList) -> AttrMaps | AttrInfo | Attr when
    OutPutType      :: list|map|record,
    AttrListList    :: [AttrInfo],
    AttrInfo        :: attr_key_value_list() | #attr{}| #{},
    AttrMaps        :: #{},
    Attr            :: #attr{}.
%% ---------------------------------------------------------------------------
add_attr(OutPutType, AttrList) ->
    NewAttrList = [add_attr_helper(Attr) || Attr <- AttrList],
    PlusAttrList = ulists:kv_list_plus_extra(NewAttrList),
    case OutPutType of
        list    -> PlusAttrList;
        map     -> maps:from_list(PlusAttrList);
        record  -> attr_conv:to_attr_record(PlusAttrList)
    end.

%% 转化为通用格式
add_attr_helper(Attr) when is_map(Attr) orelse is_record(Attr, attr) ->
    attr_conv:to_attr_tuple_list(Attr);
add_attr_helper([{_, _} | _] = Attr) ->
    Attr;
add_attr_helper(_) -> [].

%% 功能内部的基础属性加成转换成基础属性
%% 有全属性加成的要转化到单属性加成列表
%% 转换完后会把原属性表的局部属性剔除掉
%% 属性系数万分比(即:放大了10000倍,计算的时候要除以10000)
partial_attr_convert(AttrList) ->
    AttrList1 = util:combine_list(AttrList),
    CombineList = case lists:keyfind(?PARTIAL_WHOLE_ADD_RATIO, 1, AttrList1) of
        {?PARTIAL_WHOLE_ADD_RATIO, WholeAddRatio} when WholeAddRatio > 0 ->
            WholeAdd = [{AttrId + ?PARTIAL2GLOBAL_INTERVAL, WholeAddRatio} || AttrId <- ?BASE_ATTR_LIST],
            AttrList2 = lists:keydelete(?PARTIAL_WHOLE_ADD_RATIO, 1, AttrList1),
            util:combine_list(WholeAdd ++ AttrList2);
        _ -> AttrList1
    end,
    %% 筛选出全局的属性
    GlobalAttrList = lists:filter(fun({TmpKey, _TmpVal}) ->
                lists:member(TmpKey, ?PARTIAL_TYPE) == false
        end, CombineList),
    lists:foldl(fun({TmpKey, TmpVal}, AccList) ->
                case ?PARTIAL2GLOBAL(TmpKey) of
                    TmpCKey when is_integer(TmpCKey) ->
                        case lists:keyfind(TmpCKey, 1, AccList) of
                            {TmpCKey, AttrVal} ->
                                lists:keystore(TmpCKey, 1, AccList, {TmpCKey, round(AttrVal * (1 + TmpVal / ?RATIO_MAX))});
                            _ -> AccList
                        end;
                    _ -> AccList
                end
        end, GlobalAttrList, CombineList).

%% 计算等级属性
%% 以配置的等级基础属性为基数，按等级加成属性进行调整，计算最终等级属性
count_lv_attr(LvAttr, AddAttrList) ->
    %% 等级基础属性
    BaseKvList = [ AttrInfo || {AttrId, _} = AttrInfo <- LvAttr, lists:member(AttrId, ?BASE_ATTR_LIST)],
    %% 按等级加成属性进行调整计算；如果无加成，则为配置的等级基础属性
    AllAddAttrList = ulists:kv_list_plus_extra(AddAttrList),
    lists:foldl(fun({AddAttrId, AddAttrVal}, AccAttrList) when AddAttrVal > 0 ->
                case lists:member(AddAttrId, ?LV_ADD_RATIO_TYPE) of
                    true  ->
                        %% 等级加成属性：按百分比对等级基础属性进行提升调整
                        BaseAttrId = AddAttrId - ?LV_ADD_ATTR_DIFF,
                        case lists:keyfind(BaseAttrId, 1, AccAttrList) of
                            {_, AttrVal} when AttrVal > 0 ->
                                NewAttrVal = round(AttrVal * (1 + AddAttrVal / ?RATIO_MAX)),
                                lists:keystore(BaseAttrId, 1, AccAttrList, {BaseAttrId, NewAttrVal});
                            _ ->
                                AccAttrList
                        end;
                    false ->
                        %% 其他属性直接忽略，不参与等级属性的计算
                        AccAttrList
                end;
            (_, AccAttrList) ->
                AccAttrList
        end, BaseKvList, AllAddAttrList).

%% 将功能内部的对装备系统的加成属性转为基础属性
%% 转换完后会把原属性表的装备系统加成属性剔除掉
%%-define(WEAPON_ATT_ADD_RATIO,     221).  %% 武器基础攻击增加百分比
%%-define(PROTECTION_HP_ADD_RATIO,  223).  %% 防具基础生命增加百分比
%%-define(PROTECTION_DEF_ADD_RATIO, 224).  %% 防具基础防御增加百分比
%%-define(JEWELRY_ATT_ADD_RATIO,    225).  %% 饰品基础攻击增加百分比
%% 属性系数万分比(即:放大了10000倍,计算的时候要除以10000)
%% 注意！！！目前直接统计装备，所以需要在玩家进程
equipment_attr_convert(AttrList) ->
    AttrList1 = util:combine_list(AttrList),
    AllEquipment = equipment_api:get_all_equipment(),
    lists:foldl(
        fun
            ({?WEAPON_ATT_ADD_RATIO, _Value} = KV, Temp) ->
                equipment_add_turn_to_base_attr(Temp, AllEquipment, ?ATT, KV, [?EQUIPMENT_WEAPON]);
            ({?PROTECTION_HP_ADD_RATIO, _Value} = KV, Temp) ->
                equipment_add_turn_to_base_attr(Temp, AllEquipment, ?HP, KV, ?EQUIPMENT_ATTR_PROTECTION);
            ({?PROTECTION_DEF_ADD_RATIO, _Value} = KV, Temp) ->
                equipment_add_turn_to_base_attr(Temp, AllEquipment, ?DEF, KV, ?EQUIPMENT_ATTR_PROTECTION);
            ({?JEWELRY_ATT_ADD_RATIO, _Value} = KV, Temp) ->
                equipment_add_turn_to_base_attr(Temp, AllEquipment, ?ATT, KV, ?EQUIPMENT_ATTR_JEWELRY);
            (_KeyValue, Temp) ->
                Temp
        end, AttrList1, AttrList1
    ).
equipment_add_turn_to_base_attr(AttrList, AllEquipment, AttrId, {_, AttrValue} = KV, EquipmentTyp) ->
    WeaponsBaseAttr = equipment_api:get_equipment_part_attr(AllEquipment, EquipmentTyp),
    Add = case lists:keyfind(AttrId, 1, WeaponsBaseAttr) of
        {_, Attr} ->
            Attr*AttrValue/?RATIO_MAX;
        false ->
            0
    end,
    case lists:keyfind(AttrId, 1, AttrList) of
        {_, OldValue} ->
            lists:keyreplace(AttrId, 1, AttrList, {AttrId, OldValue+Add}) -- [KV];
        false ->
            [{AttrId, Add}|AttrList] -- [KV]
    end.
%%--------------------------------------------------
%% 从属性列表中筛选出指定属性
%% @param  AttrL          属性列表[{属性id, 属性值}]
%% @param  SpecifyAttrMap 要筛选出的指定属性Map #{属性id => 值}
%% @return                筛选出的指定属性Map #{属性id => 值}
%%--------------------------------------------------
filter_specify_attr(AttrL, SpecifyAttrMap) ->
    lists:foldl(fun({TmpKey, TmpVal}, TmpMap) ->
                case maps:is_key(TmpKey, TmpMap) of
                    true ->
                        #{TmpKey := PreVal} = TmpMap,
                        TmpMap#{TmpKey => PreVal + TmpVal};
                    false -> TmpMap
                end
        end, SpecifyAttrMap, AttrL).

%% 从列表中拿出基础属性:AttrList不能有重复键
%% 返回[{k,v}...]列表
get_list_base_attr_kv(AttrList)->
    F = fun(K, TL)->
            case lists:keyfind(K, 1, AttrList) of
                false -> [{K, 0}|TL];
                E -> [E|TL]
            end
    end,
    lists:reverse(lists:foldl(F, [], ?BASE_ATTR_LIST)).

%% 从列表中拿出基础属性:AttrList不能有重复键
%% 返回[V,V1...]列表
get_list_base_attr(AttrList)->
    F = fun(K, TL)->
            case lists:keyfind(K, 1, AttrList) of
                false -> [0|TL];
                {K, V} -> [V|TL]
            end
    end,
    lists:reverse(lists:foldl(F, [], ?BASE_ATTR_LIST)).

%% 一般属性转换为战斗属性
attr_to_battle_attr(AttrMaps) when is_map(AttrMaps) ->
    Attr = attr_conv:to_attr_record(AttrMaps),
    attr_to_battle_attr(Attr);
attr_to_battle_attr(AttrList) when is_list(AttrList) ->
    Attr = attr_conv:to_attr_record(AttrList),
    attr_to_battle_attr(Attr);
attr_to_battle_attr(Attr) ->
    #battle_attr{
        hp = Attr#attr.hp, hp_lim = Attr#attr.hp,
        attr = Attr, speed = Attr#attr.speed
    }.

%% 设置战斗属性
set_battle_attr(BattleAttr, AttrKeyValueList) ->
    #battle_attr{attr = MonAttr} = BattleAttr,
    NewMonAttr = lists:foldl(fun attr_conv:set_attr_val/2, MonAttr, AttrKeyValueList),
    BattleAttr#battle_attr{
        hp = NewMonAttr#attr.hp,
        hp_lim = NewMonAttr#attr.hp,
        attr = NewMonAttr,
        speed = NewMonAttr#attr.speed
    }.

%%--------------------------------------------------
%% 按万分比设置属性
%% @param  AttrKeyValueList          属性列表[{属性id, 属性值}]
%% @param  Ratio                     万分比值
%% @return                           换算后的属性列表 [{属性id, 属性值}]
%%--------------------------------------------------
set_attr_by_ratio(AttrKeyValueList, ?RATIO_MAX) -> AttrKeyValueList;
set_attr_by_ratio(AttrKeyValueList, Ratio) ->
    F = fun({AttrId, Value}, AttrList) -> [{AttrId, trunc(Value * Ratio / ?RATIO_MAX)} | AttrList] end,
    lists:foldl(F, [], AttrKeyValueList).

%% 计算属性的战力价值
-spec calc_attr_power(Attr) -> AttrPower :: integer() when
    Attr :: #attr{} | map() | [{AttrId, AttrVal}],
    AttrId :: non_neg_integer(), AttrVal :: number().
calc_attr_power(Attr) when is_record(Attr, attr) ->
    #attr{
        att = Att, hp = Hp, def = Def, hit = Hit, dodge = Dodge, crit = Crit, ten = Ten,
        hurt_add_ratio = HurtAddRatio, hurt_del_ratio = HurtDelRatio,
        hit_ratio = HitRatio, dodge_ratio = DodgeRatio,
        crit_ratio = CritRatio, uncrit_ratio = UnCritRatio,
        crit_hurt_add_ratio = CritHurtAddRatio, crit_hurt_del_ratio = CritHurtDelRatio,
        skill_hurt_add_ratio = SkillHurtAddRatio, skill_hurt_del_ratio = SkillHurtDelRatio,
        pvp_hurt_add_ratio = PVPHurtAddRatio, pvp_hurt_del_ratio = PVPHurtDelRatio,
        heart_ratio = HeartRatio, heart_resist_ratio = HeartResistRatio,
        heart_add_hurt = HeartAddHurt, heart_del_hurt = HeartDelHurt,
        parry_ratio = ParryRatio, stab_ratio = StabRatio,
        final_hurt_add = FinalHurtAdd, final_hurt_del = FinalHurtDel,
        boss_hurt_add_ratio = BossHurtAddRatio, boss_hurt_del_ratio = BossHurtDelRatio,
        mon_hurt_add_ratio = MonHurtAddRatio, mon_hurt_del_ratio = MonHurtDelRatio,
        suck_blood_add = SuckBloodAdd, suck_blood_minus = SuckBloodMinus,
        suck_blood = SuckBlood
    } = Attr,
    %% 直接数值型基础属性战力
    BasePower = (
        (Att + Def) * 5
        + Hp * 0.5
        + (Hit + Dodge + Crit + Ten) * 15
        + (FinalHurtAdd + FinalHurtDel) * 5
    ),
    %% 合并相同战力系数的属性值，减少后面各自单个属性计算的反复乘除法运算
    PartF10 = [
        SuckBloodAdd, SuckBloodMinus
    ],
    PartF40 = [
        HeartAddHurt, HeartDelHurt
        , CritHurtAddRatio, CritHurtDelRatio
        , BossHurtAddRatio, BossHurtDelRatio, MonHurtAddRatio, MonHurtDelRatio
    ],
    PartF100 = [
        ParryRatio, StabRatio
        , CritRatio, UnCritRatio
        , SkillHurtAddRatio, SkillHurtDelRatio
    ],
    PartF200 = [
        HurtAddRatio, HurtDelRatio
        , HeartRatio, HeartResistRatio
        , HitRatio, DodgeRatio
        , PVPHurtAddRatio, PVPHurtDelRatio
        , SuckBlood
    ],
    %% 系数型基础属性战力
    FactorAttrAddSum = (
        calc_factor_attr_add_list(PartF10, 10) +
        calc_factor_attr_add_list(PartF40, 40) +
        calc_factor_attr_add_list(PartF100, 100) +
        calc_factor_attr_add_list(PartF200, 200)
    ),
    round(BasePower * (1 + FactorAttrAddSum));

calc_attr_power(AttrData) ->
    Attr = attr_conv:to_attr_record(AttrData),
    case Attr of
        #attr{} -> calc_attr_power(Attr);
        _       -> error({attr, invalid})
    end.

%% 计算相同战力系数的多个基础属性的战力
%% （多个相同战力系数的属性可以相加后计算，减少运算量）
%% ----------------------------------------------------------------------
%% 通用的系数型属性战力计算，采用相同的公式：
%% 策划的原始公式：(1 + (AttrVal/100/20-1)/(AttrVal/100/10*0.2+1) ) * 20/100 * PowerFactor/1000
%% 技术简化除法后：(1 + (5 * AttrVal - 10000) / (2 * AttrVal + 10000) ) * PowerFactor * 0.0002
calc_factor_attr_add_list(AttrValList, PowerFactor) ->
    Sum = lists:sum([
            calc_factor_attr_add(AttrVal) ||
            AttrVal <- AttrValList
        ]),
    Sum * PowerFactor * 0.0002.
%% 计算单个系数型基础属性的战力
calc_factor_attr_add(AttrVal) ->
    (1 + (5 * AttrVal - ?RATIO_MAX) / (2 * AttrVal + ?RATIO_MAX) ).
%% ----------------------------------------------------------------------

%% 确保属性值为整数
-spec ensure_attr_int(Attr :: #attr{}) -> NewAttr :: #attr{}.
ensure_attr_int(Attr = #attr{}) ->
    [attr | AttrValList] = tuple_to_list(Attr),
    NewAttrValList = [
        if
            is_integer(AttrVal) -> AttrVal;
            is_float(AttrVal)   -> round(AttrVal);
            true -> 0
        end || AttrVal <- AttrValList
    ],
    list_to_tuple([attr | NewAttrValList]).


%% 以原始基本属性及额外加成属性计算加成后的最终属性数据
%% 注意：参数OriginAttr必须是未计算系数型额外属性影响前的基础属性结果
%%       调用此接口后，会得到受系数型额外属性影响后的新属性结果
-spec attr_count_with_extra(OriginAttr :: #attr{}) -> Attr :: #attr{}.
attr_count_with_extra(OriginAttr) ->
    #attr{
        %% 直接数值型基础属性
        att = Att, hp = Hp, def = Def, hit = Hit, dodge = Dodge, crit = Crit, ten = Ten,
        final_hurt_add = FinalHurtAdd, final_hurt_del = FinalHurtDel,
        %% 系数型额外属性（万倍数，计算时要除以10000，用于对直接数值型基础属性进行加成计算）
        att_add_ratio = AttAddR, hp_add_ratio = HpAddR, def_add_ratio = DefAddR,
        hit_add_ratio = HitAddR, dodge_add_ratio = DodgeAddR,
        crit_add_ratio = CritAddR, ten_add_ratio = TenAddR,
        final_hurt_add_ratio = FinalHurtAddR, final_hurt_del_ratio = FinalHurtDelR
    } = OriginAttr,
    NewAtt          = round(Att          * (1 + AttAddR       / ?RATIO_MAX)),
    NewHp           = round(Hp           * (1 + HpAddR        / ?RATIO_MAX)),
    NewDef          = round(Def          * (1 + DefAddR       / ?RATIO_MAX)),
    NewHit          = round(Hit          * (1 + HitAddR       / ?RATIO_MAX)),
    NewDodge        = round(Dodge        * (1 + DodgeAddR     / ?RATIO_MAX)),
    NewCrit         = round(Crit         * (1 + CritAddR      / ?RATIO_MAX)),
    NewTen          = round(Ten          * (1 + TenAddR       / ?RATIO_MAX)),
    NewFinalHurtAdd = round(FinalHurtAdd * (1 + FinalHurtAddR / ?RATIO_MAX)),
    NewFinalHurtDel = round(FinalHurtDel * (1 + FinalHurtDelR / ?RATIO_MAX)),
    OriginAttr#attr{
        att = NewAtt, hp = NewHp, def = NewDef,
        hit = NewHit, dodge = NewDodge, crit = NewCrit, ten = NewTen,
        final_hurt_add = NewFinalHurtAdd, final_hurt_del = NewFinalHurtDel
    }.

%% 计算在全局属性影响下，某部分属性的战力价值
%% AttrPower    : 指的是BaseAttr的战力价值，已经包含了PartialAttr部分的战力价值
%% BaseAttr     : 基础属性（包含PartialAttr部分的属性），一般指未计算百分比加成之前的全局基础属性
%% PartialAttr  : 需要计算的某部分属性，包含该部分的基础属性及该部分对全局基础属性加成的系数型属性
%% 理论上，BaseAttr中已经包含了PartialAttr中的基础属性部分
-spec calc_attr_power_partial(AttrPower, BaseAttr, PartialAttr) -> PartialPower when
    AttrPower :: integer(),
    BaseAttr :: #attr{}, PartialAttr :: #attr{},
    PartialPower :: integer().
calc_attr_power_partial(AttrPower, BaseAttr, PartialAttr) ->
    OldBase      = attr_conv:attr_minus(BaseAttr, PartialAttr),
    OldAttr      = attr_count_with_extra(OldBase),
    OldAttrPower = calc_attr_power(OldAttr),
    AttrPower    - OldAttrPower.

%% 计算模块战力
-spec update_module_power(Player, AttrPower, BaseAttr) -> {NewPlayer, SkillPowerAcc} when
    Player :: #player_status{}, NewPlayer :: #player_status{},
    AttrPower :: integer(), BaseAttr :: #attr{},
    SkillPowerAcc :: integer().
update_module_power(Player, AttrPower, BaseAttr) when is_record(BaseAttr, attr) ->
    %% 模块战力计算回调列表
    %% @return :  {NewPlayer, SkillPowerAll}
    %% NewPlayer中保存相关模块战力信息，SkillPowerAcc相关模块的技能固定战力（用于总战力计算）
    Callbacks = [
        {equipment_api,          calc_power,         []}
        ,{lib_role_foster,       calc_power,         []}
        ,{lib_role_foster_skin,  calc_power,         []}
        ,{lib_fashion,           calc_power,         []}
        ,{mate_api,              calc_power,         []}
        ,{lib_liveness,          calc_power,         []}
        ,{lib_designation,       calc_power,         []}
        ,{lib_role_visus,        calc_power,         []}
        ,{lib_role_nucleon,      calc_power,         []}
        ,{lib_sup_vip,           calc_power,         []}
        ,{god_api,               calc_god_power,     []}
        ,{lib_role_galaxy,       calc_power,         []}
        ,{warsoul_api,           calc_power,         []}
        ,{lib_role_uranium,      calc_power,         []}
        ,{lib_dress_up,          calc_power,         []}
    ],
    do_calc_module_power(Player, AttrPower, BaseAttr, Callbacks, 0);
update_module_power(Player, _AttrPower, _BaseAttr) ->
    {Player, 0}.

do_calc_module_power(Player, AttrPower, BaseAttr, [{M, F, OtherArgs} | Callbacks], SkillPowerAcc) ->
    {NewPlayer, ModuleSkillPower} =
    case OtherArgs of
        [] -> M:F(Player, AttrPower, BaseAttr);
        _  -> erlang:apply(M, F, [Player, AttrPower, BaseAttr | OtherArgs])
    end,
    do_calc_module_power(NewPlayer, AttrPower, BaseAttr, Callbacks, SkillPowerAcc + ModuleSkillPower);
do_calc_module_power(Player, _AttrPower, _BaseAttr, [], SkillPowerAcc) ->
    {Player, SkillPowerAcc}.

%% 传入属性列表计算战力，该属性列表是玩家尚未拥有的属性，一般是包含全局属性加成的属性列表，对于纯属性值列表一般前端就可计算
calc_preview_power(Player, AttrList) ->
    #player_status{role_base_attr = {AttrPower, BaseAttr}} = Player,
    CalcAttr     = attr_conv:to_attr_record(AttrList),
    NewBase      = attr_conv:attr_plus(BaseAttr, CalcAttr),
    NewAttr      = attr_count_with_extra(NewBase),
    NewAttrPower = calc_attr_power(NewAttr),
    NewAttrPower - AttrPower.
%% 传入属性列表计算战力，该属性列表是玩家已经拥有的属性，一般是包含全局属性加成的属性列表
calc_attr_list_power(Player, AttrList) ->
    #player_status{role_base_attr = {AttrPower, BaseAttr}} = Player,
    CalcAttr = attr_conv:to_attr_record(AttrList),
    calc_attr_power_partial(AttrPower, BaseAttr, CalcAttr).

%% 血量上限属性变动时，同步调整血量值
calc_hp_while_hp_lim_change(OldHp, OldHpLim, NewHpLim) ->
    HpLimChange = NewHpLim - OldHpLim,
    NewHp =
        if
            OldHp == 0 -> OldHp; %% 死亡状态就不变更血量了
            HpLimChange > 0 -> min(OldHp + HpLimChange, NewHpLim);
            HpLimChange < 0 -> max(OldHp + HpLimChange, 1);
            true -> OldHp
        end,
    NewHp.

%% 根据相关属性计算单位时间血量自动回复值（角色自动恢复能力）
calc_hp_resume_add(HpLim, HpResume, HpResumeRatio, HpResumeSpclAdd) ->
    HpResume + HpResumeSpclAdd + round(HpLim * HpResumeRatio / ?RATIO_MAX).
