| summaryrefslogtreecommitdiff | 
diff options
| author | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2019-08-18 16:05:23 +0200 | 
|---|---|---|
| committer | Nathanael Sensfelder <SpamShield0@MultiAgentSystems.org> | 2019-08-18 16:05:23 +0200 | 
| commit | 5266e24e01611fc8026dfa0498ee87d7fba65e88 (patch) | |
| tree | 72c73402dc959f5d618ac850b54d8eb724f60145 /src/balancer/struct | |
| parent | dc742fd9190eadd5eed2e45dd36262ea06550172 (diff) | |
...
Diffstat (limited to 'src/balancer/struct')
| -rw-r--r-- | src/balancer/struct/blc_armor.erl | 11 | ||||
| -rw-r--r-- | src/balancer/struct/blc_error.erl | 24 | ||||
| -rw-r--r-- | src/balancer/struct/blc_glyph.erl | 451 | ||||
| -rw-r--r-- | src/balancer/struct/blc_weapon.erl | 414 | 
4 files changed, 894 insertions, 6 deletions
| diff --git a/src/balancer/struct/blc_armor.erl b/src/balancer/struct/blc_armor.erl index 46189d2..9677f88 100644 --- a/src/balancer/struct/blc_armor.erl +++ b/src/balancer/struct/blc_armor.erl @@ -1,6 +1,6 @@  -module(blc_armor). --include("base_attributes.hrl"). +-include("tacticians/attributes.hrl").  -define  ( @@ -57,7 +57,6 @@  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  -export_type([proto_armor/0]). -% FIXME: quick debug  -export  (     [ @@ -97,7 +96,7 @@     )     -> {proto_armor(), non_neg_integer()}.  increase_health_by (Amount, Armor) -> -   NewHealth = Armor#proto_armor.health + Amount, +   NewHealth = (Armor#proto_armor.health + Amount),     case (NewHealth > ?ATTRIBUTE_HEALTH_MAX) of        true ->           { @@ -122,7 +121,7 @@ increase_health_by (Amount, Armor) ->     )     -> {proto_armor(), non_neg_integer()}.  increase_damage_modifier_by (Amount, Armor) -> -   NewDamageModifier = Armor#proto_armor.damage_modifier + Amount, +   NewDamageModifier = (Armor#proto_armor.damage_modifier + Amount),     case (NewDamageModifier > ?ATTRIBUTE_DAMAGE_MODIFIER_MAX) of        true ->           { @@ -153,7 +152,7 @@ increase_damage_modifier_by (Amount, Armor) ->     )     -> {proto_armor(), non_neg_integer()}.  increase_dodge_chance_by (Amount, Armor) -> -   NewDodgeChance = Armor#proto_armor.dodge + Amount, +   NewDodgeChance = (Armor#proto_armor.dodge + Amount),     case (NewDodgeChance > ?ATTRIBUTE_DODGE_CHANCE_MAX) of        true ->           { @@ -178,7 +177,7 @@ increase_dodge_chance_by (Amount, Armor) ->     )     -> {proto_armor(), non_neg_integer()}.  increase_movement_points_by (Amount, Armor) -> -   NewMvtPoints = Armor#proto_armor.mvt_points + Amount, +   NewMvtPoints = (Armor#proto_armor.mvt_points + Amount),     case (NewMvtPoints > ?ATTRIBUTE_MOVEMENT_POINTS_MAX) of        true ->           { diff --git a/src/balancer/struct/blc_error.erl b/src/balancer/struct/blc_error.erl new file mode 100644 index 0000000..9bd3548 --- /dev/null +++ b/src/balancer/struct/blc_error.erl @@ -0,0 +1,24 @@ +-module(blc_error). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-type type() :: +   ( +      {error, balance, non_neg_integer(), non_neg_integer()} +      | {error, incompatible} +   ). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/balancer/struct/blc_glyph.erl b/src/balancer/struct/blc_glyph.erl new file mode 100644 index 0000000..9b43f88 --- /dev/null +++ b/src/balancer/struct/blc_glyph.erl @@ -0,0 +1,451 @@ +-module(blc_glyph). + +-include("tacticians/attributes.hrl"). + +-define(SPENDABLE_GLYPH_POINTS, 100). +-define(NEGATIVE_POINTS_MODIFIER, 0.75). +-define(NEGATIVE_POINTS_MULTIPLIER, (2 - ?NEGATIVE_POINTS_MODIFIER)). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   proto_glyph, +   { +      remaining_positive_points :: non_neg_integer(), +      points_balance :: integer(), +      omnimods :: shr_omnimods:type(), +      defense_coef :: blc_damage_type:coefficient(), +      attack_coef :: blc_damage_type:coefficient(), +      defense_score :: non_neg_integer(), +      defense_sign :: integer(), +      attack_score :: non_neg_integer(), +      attack_sign :: integer() +   } +). + +-opaque type() :: #proto_glyph{}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0]). + +-export +( +   [ +      increase_attribute_by/3, +      decrease_attribute_by/3, +      increase_attribute_for/3, +      decrease_attribute_for/3, +      set_attack_coefficients/2, +      set_defense_coefficients/2 +   ] +). + +-export +( +   [ +      new/2, +      get_remaining_positive_points/1, +      get_points_balance/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec increase_attribute_by +   ( +      shr_attributes:meta_enum(), +      non_neg_integer(), +      type() +   ) +   -> ({ok, type()} | blc_error:type()). +increase_attribute_by (?ATTRIBUTE_ATTACK_SCORE, S0Amount, Glyph) -> +   S0NewAttackScore = (Glyph#proto_glyph.attack_score + S0Amount), +   {S1NewAttackScore, S1Amount} = +      case (S0NewAttackScore > ?ATTRIBUTE_ATTACK_SCORE_MAX) of +         true -> +            { +               ?ATTRIBUTE_ATTACK_SCORE_MAX, +               (?ATTRIBUTE_ATTACK_SCORE_MAX - Glyph#proto_glyph.attack_score) +            }; + +         false -> {S0NewAttackScore, S0Amount} +      end, + +   Cost = (S1Amount * ?ATTRIBUTE_ATTACK_SCORE_COST), + +   if +      (Glyph#proto_glyph.attack_sign == -1) -> {error, incompatible}; +      (Cost > (Glyph#proto_glyph.remaining_positive_points)) -> +         {error, balance, Glyph#proto_glyph.remaining_positive_points, Cost}; + +      true -> +         { +            ok, +            Glyph#proto_glyph +            { +               attack_score = S1NewAttackScore, +               attack_sign = 1, +               omnimods = +                  shr_omnimods:set_attack_modifiers +                  ( +                     blc_damage_type:generate_entries_from_score +                     ( +                        S1NewAttackScore, +                        Glyph#proto_glyph.attack_coef +                     ), +                     Glyph#proto_glyph.omnimods +                  ), +               remaining_positive_points = +                  (Glyph#proto_glyph.remaining_positive_points - Cost), +               points_balance = (Glyph#proto_glyph.points_balance - Cost) +            } +         } +   end; +increase_attribute_by (?ATTRIBUTE_DEFENSE_SCORE, S0Amount, Glyph) -> +   S0NewDefenseScore = (Glyph#proto_glyph.defense_score + S0Amount), +   {S1NewDefenseScore, S1Amount} = +      case (S0NewDefenseScore > ?ATTRIBUTE_DEFENSE_SCORE_MAX) of +         true -> +            { +               ?ATTRIBUTE_DEFENSE_SCORE_MAX, +               (?ATTRIBUTE_DEFENSE_SCORE_MAX - Glyph#proto_glyph.defense_score) +            }; + +         false -> {S0NewDefenseScore, S0Amount} +      end, + +   Cost = (S1Amount * ?ATTRIBUTE_DEFENSE_SCORE_COST), + +   if +      (Glyph#proto_glyph.defense_sign == -1) -> {error, incompatible}; +      (Cost > (Glyph#proto_glyph.remaining_positive_points)) -> +         {error, balance, Glyph#proto_glyph.remaining_positive_points, Cost}; + +      true -> +         { +            ok, +            Glyph#proto_glyph +            { +               defense_score = S1NewDefenseScore, +               defense_sign = 1, +               omnimods = +                  shr_omnimods:set_defense_modifiers +                  ( +                     blc_damage_type:generate_entries_from_score +                     ( +                        S1NewDefenseScore, +                        Glyph#proto_glyph.defense_coef +                     ), +                     Glyph#proto_glyph.omnimods +                  ), +               remaining_positive_points = +                  (Glyph#proto_glyph.remaining_positive_points - Cost), +               points_balance = (Glyph#proto_glyph.points_balance - Cost) +            } +         } +   end; +increase_attribute_by (Attribute, S0Amount, Glyph) -> +   {_AttMin, _AttDef, AttMax, AttCost} = blc_attribute:get_info(Attribute), +   CurrentOmnimods = Glyph#proto_glyph.omnimods, +   CurrentValue = shr_omnimods:get_attribute(Attribute, CurrentOmnimods), + +   S1Amount = +      case ((CurrentValue + S0Amount) > AttMax) of +         true -> (AttMax - CurrentValue); +         false -> S0Amount +      end, + +   Cost = (S1Amount * AttCost), + +   if +      (CurrentValue < 0) -> {error, incompatible}; +      (Cost > (Glyph#proto_glyph.remaining_positive_points)) -> +         {error, balance, Glyph#proto_glyph.remaining_positive_points, Cost}; + +      true -> +         { +            ok, +            Glyph#proto_glyph +            { +               omnimods = +                  shr_omnimods:mod_attribute +                  ( +                     Attribute, +                     S1Amount, +                     CurrentOmnimods +                  ), +               remaining_positive_points = +                  (Glyph#proto_glyph.remaining_positive_points - Cost), +               points_balance = (Glyph#proto_glyph.points_balance - Cost) +            } +         } +   end. + +-spec decrease_attribute_by +   ( +      shr_attributes:meta_enum(), +      non_neg_integer(), +      type() +   ) +   -> ({ok, type()} | blc_error:type()). +decrease_attribute_by (?ATTRIBUTE_ATTACK_SCORE, Amount, Glyph) -> +   NewAttackScore = (Glyph#proto_glyph.attack_score + Amount), + +   Cost = +      trunc +      ( +         (Amount * ?ATTRIBUTE_ATTACK_SCORE_COST) +         * ?NEGATIVE_POINTS_MULTIPLIER +      ), + +   if +      (Glyph#proto_glyph.attack_sign == -1) -> {error, incompatible}; +      true -> +         { +            ok, +            Glyph#proto_glyph +            { +               attack_score = NewAttackScore, +               attack_sign = -1, +               omnimods = +                  shr_omnimods:set_attack_modifiers +                  ( +                     lists:map +                     ( +                        fun ({Name, Value}) -> {Name, (-1 * Value)} end, +                        blc_damage_type:generate_entries_from_score +                        ( +                           NewAttackScore, +                           Glyph#proto_glyph.attack_coef +                        ) +                     ), +                     Glyph#proto_glyph.omnimods +                  ), +               points_balance = (Glyph#proto_glyph.points_balance + Cost) +            } +         } +   end; +decrease_attribute_by (?ATTRIBUTE_DEFENSE_SCORE, Amount, Glyph) -> +   NewDefenseScore = (Glyph#proto_glyph.defense_score + Amount), + +   Cost = +      trunc +      ( +         (Amount * ?ATTRIBUTE_DEFENSE_SCORE_COST) +         * ?NEGATIVE_POINTS_MULTIPLIER +      ), + +   if +      (Glyph#proto_glyph.defense_sign == -1) -> {error, incompatible}; +      true -> +         { +            ok, +            Glyph#proto_glyph +            { +               defense_score = NewDefenseScore, +               defense_sign = -1, +               omnimods = +                  shr_omnimods:set_defense_modifiers +                  ( +                     lists:map +                     ( +                        fun ({Name, Value}) -> {Name, (-1 * Value)} end, +                        blc_damage_type:generate_entries_from_score +                        ( +                           NewDefenseScore, +                           Glyph#proto_glyph.defense_coef +                        ) +                     ), +                     Glyph#proto_glyph.omnimods +                  ), +               points_balance = (Glyph#proto_glyph.points_balance + Cost) +            } +         } +   end; +decrease_attribute_by (Attribute, Amount, Glyph) -> +   {_AttMin, _AttDef, _AttMax, AttCost} = blc_attribute:get_info(Attribute), +   CurrentOmnimods = Glyph#proto_glyph.omnimods, +   CurrentValue = shr_omnimods:get_attribute(Attribute, CurrentOmnimods), + +   Cost = ((Amount * AttCost) * ?NEGATIVE_POINTS_MULTIPLIER), + +   if +      (CurrentValue > 0) -> {error, incompatible}; + +      true -> +         { +            ok, +            Glyph#proto_glyph +            { +               omnimods = +                  shr_omnimods:mod_attribute +                  ( +                     Attribute, +                     (-1 * Amount), +                     CurrentOmnimods +                  ), +               points_balance = (Glyph#proto_glyph.points_balance + Cost) +            } +         } +   end. + +-spec set_attack_coefficients +   ( +      list(blc_damage_type:coefficient()), +      type() +   ) +   -> type(). +set_attack_coefficients (Coefficients, Glyph) -> +   NewGlyph = +      Glyph#proto_glyph +      { +         attack_coef = blc_damage_type:sort_entries(Coefficients) +      }, + +   case (NewGlyph#proto_glyph.attack_sign) of +      0 -> NewGlyph; +      1 -> +         NewGlyph#proto_glyph +         { +            omnimods = +               shr_omnimods:set_attack_modifiers +               ( +                  blc_damage_type:generate_entries_from_score +                  ( +                     NewGlyph#proto_glyph.attack_score, +                     NewGlyph#proto_glyph.attack_coef +                  ), +                  NewGlyph#proto_glyph.omnimods +               ) +         }; +      -1 -> +         NewGlyph#proto_glyph +         { +            omnimods = +               shr_omnimods:set_attack_modifiers +               ( +                  lists:map +                  ( +                     fun ({Name, Value}) -> {Name, (-1 * Value)} end, +                     blc_damage_type:generate_entries_from_score +                     ( +                        NewGlyph#proto_glyph.attack_score, +                        NewGlyph#proto_glyph.attack_coef +                     ) +                  ), +                  NewGlyph#proto_glyph.omnimods +               ) +         } +   end. + +-spec set_defense_coefficients +   ( +      list(blc_damage_type:coefficient()), +      type() +   ) +   -> type(). +set_defense_coefficients (Coefficients, Glyph) -> +   NewGlyph = +      Glyph#proto_glyph +      { +         defense_coef = blc_damage_type:sort_entries(Coefficients) +      }, + +   case (NewGlyph#proto_glyph.defense_sign) of +      0 -> NewGlyph; +      1 -> +         NewGlyph#proto_glyph +         { +            omnimods = +               shr_omnimods:set_defense_modifiers +               ( +                  blc_damage_type:generate_entries_from_score +                  ( +                     NewGlyph#proto_glyph.defense_score, +                     NewGlyph#proto_glyph.defense_coef +                  ), +                  NewGlyph#proto_glyph.omnimods +               ) +         }; +      -1 -> +         NewGlyph#proto_glyph +         { +            omnimods = +               shr_omnimods:set_defense_modifiers +               ( +                  lists:map +                  ( +                     fun ({Name, Value}) -> {Name, (-1 * Value)} end, +                     blc_damage_type:generate_entries_from_score +                     ( +                        NewGlyph#proto_glyph.defense_score, +                        NewGlyph#proto_glyph.defense_coef +                     ) +                  ), +                  NewGlyph#proto_glyph.omnimods +               ) +         } +   end. + +-spec new +   ( +      list(blc_damage_type:coefficient()), +      list(blc_damage_type:coefficient()) +   ) +   -> type(). +new (AttackCoefficients, DefenseCoefficients) -> +   #proto_glyph +   { +      remaining_positive_points = ?SPENDABLE_GLYPH_POINTS, +      points_balance = 0, +      omnimods = omnimods:new(), +      attack_coef = blc_damage_type:sort_entries(AttackCoefficients), +      attack_score = 0, +      attack_sign = 0, +      defense_coef = blc_damage_type:sort_entries(DefenseCoefficients), +      defense_score = 0, +      defense_sign = 0 +   }. + +-spec increase_attribute_for +   ( +      shr_attributes:meta_enum(), +      non_neg_integer(), +      type() +   ) +   -> ({ok, type} | blc_error:type()). +increase_attribute_for (Attribute, GivenPoints, Glyph) -> +   {_AttMin, _AttDef, _AttMax, AttCost} = blc_attribute:get_info(Attribute), +   AmountOfIncrease = trunc(GivenPoints / AttCost), +   increase_attribute_by(Attribute, AmountOfIncrease, Glyph). + +-spec decrease_attribute_for +   ( +      shr_attributes:meta_enum(), +      non_neg_integer(), +      type() +   ) +   -> ({ok, type} | blc_error:type()). +decrease_attribute_for (Attribute, GivenPoints, Glyph) -> +   {_AttMin, _AttDef, _AttMax, AttCost} = blc_attribute:get_info(Attribute), +   AmountOfDecrease = +      trunc((GivenPoints * ?NEGATIVE_POINTS_MULTIPLIER) / AttCost), + +   increase_attribute_by(Attribute, AmountOfDecrease, Glyph). + +-spec get_remaining_positive_points (type()) -> non_neg_integer(). +get_remaining_positive_points (Glyph) -> +   Glyph#proto_glyph.remaining_positive_points. + +-spec get_points_balance (type()) -> non_neg_integer(). +get_points_balance (Glyph) -> +   Glyph#proto_glyph.points_balance. diff --git a/src/balancer/struct/blc_weapon.erl b/src/balancer/struct/blc_weapon.erl new file mode 100644 index 0000000..0edeb35 --- /dev/null +++ b/src/balancer/struct/blc_weapon.erl @@ -0,0 +1,414 @@ +-module(blc_weapon). + +-include("tacticians/attributes.hrl"). + +-define(WEAPON_ATTRIBUTE_RANGE_MIN,       0). +-define(WEAPON_ATTRIBUTE_RANGE_MAX,       2). +-define(WEAPON_ATTRIBUTE_RANGE_DEFAULT,   0). +-define(WEAPON_ATTRIBUTE_RANGE_COST,      1). + +-define(WEAPON_ATTRIBUTE_TYPE_MIN,     0). +-define(WEAPON_ATTRIBUTE_TYPE_MAX,     1). +-define(WEAPON_ATTRIBUTE_TYPE_DEFAULT, 0). +-define(WEAPON_ATTRIBUTE_TYPE_COST,    100). + + +-define +( +   SPENDABLE_WEAPON_POINTS, +   ( +      ( +         ?ATTRIBUTE_ACCURACY_COST +         * (?ATTRIBUTE_ACCURACY_DEFAULT - ?ATTRIBUTE_ACCURACY_MIN) +      ) +      + +      ( +         ?ATTRIBUTE_CRITICAL_HIT_CHANCE_COST +         * +         ( +            ?ATTRIBUTE_CRITICAL_HIT_CHANCE_DEFAULT +            - ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MIN +         ) +      ) +      + +      ( +         ?ATTRIBUTE_DOUBLE_HIT_CHANCE_COST +         * +         ( +            ?ATTRIBUTE_DOUBLE_HIT_CHANCE_DEFAULT +            - ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MIN +         ) +      ) +      + +      ( +         ?ATTRIBUTE_ATTACK_SCORE_COST +         * (?ATTRIBUTE_ATTACK_SCORE_DEFAULT - ?ATTRIBUTE_ATTACK_SCORE_MIN) +      ) +      + +      ( +         ?WEAPON_ATTRIBUTE_RANGE_COST +         * (?WEAPON_ATTRIBUTE_RANGE_DEFAULT - ?WEAPON_ATTRIBUTE_RANGE_MIN) +      ) +   ) +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   proto_weapon, +   { +      range :: non_neg_integer(), +      type :: non_neg_integer(), +      accuracy :: non_neg_integer(), +      critical_hit_chance :: non_neg_integer(), +      double_hit_chance :: non_neg_integer(), +      attack :: list(blc_damage_type:entry()), +      attack_coef :: list(blc_damage_type:coefficient()), +      attack_score :: non_neg_integer() +   } +). + +-opaque proto_weapon() :: #proto_weapon{}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([proto_weapon/0]). + +-export +( +   [ +      increase_range_by/2, +      increase_type_by/2, +      increase_accuracy_by/2, +      increase_critical_hit_chance_by/2, +      increase_double_hit_chance_by/2, +      increase_attack_score_by/2, +      increase_range_for/2, +      increase_type_for/2, +      increase_accuracy_for/2, +      increase_critical_hit_chance_for/2, +      increase_double_hit_chance_for/2, +      increase_attack_score_for/2, +      set_attack_coefficients/2 +   ] +). + +-export +( +   [ +      new/1, +      get_spendable_points/0 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec increase_accuracy_by +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_accuracy_by (Amount, Weapon) -> +   NewAccuracy = (Weapon#proto_weapon.accuracy + Amount), +   case (NewAccuracy > ?ATTRIBUTE_ACCURACY_MAX) of +      true -> +         { +            Weapon#proto_weapon{ accuracy = ?ATTRIBUTE_ACCURACY_MAX }, +            ( +               (?ATTRIBUTE_ACCURACY_MAX - Weapon#proto_weapon.accuracy) +               * ?ATTRIBUTE_ACCURACY_COST +            ) +         }; + +      false -> +         { +            Weapon#proto_weapon{ accuracy = NewAccuracy }, +            (Amount * ?ATTRIBUTE_ACCURACY_COST) +         } +   end. + +-spec increase_range_by +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_range_by (Amount, Weapon) -> +   NewDamageModifier = Weapon#proto_weapon.range + Amount, +   case (NewDamageModifier > ?WEAPON_ATTRIBUTE_RANGE_MAX) of +      true -> +         { +            Weapon#proto_weapon +            { +               range = ?WEAPON_ATTRIBUTE_RANGE_MAX +            }, +            ( +               ( +                  ?WEAPON_ATTRIBUTE_RANGE_MAX +                  - Weapon#proto_weapon.range +               ) +               * ?WEAPON_ATTRIBUTE_RANGE_COST +            ) +         }; + +      false -> +         { +            Weapon#proto_weapon{ range = NewDamageModifier }, +            (Amount * ?WEAPON_ATTRIBUTE_RANGE_COST) +         } +   end. + +-spec increase_type_by +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_type_by (Amount, Weapon) -> +   NewType = Weapon#proto_weapon.type + Amount, +   case (NewType > ?WEAPON_ATTRIBUTE_TYPE_MAX) of +      true -> +         { +            Weapon#proto_weapon { type = ?WEAPON_ATTRIBUTE_TYPE_MAX }, +            ( +               (?WEAPON_ATTRIBUTE_TYPE_MAX - Weapon#proto_weapon.type) +               * ?WEAPON_ATTRIBUTE_TYPE_COST +            ) +         }; + +      false -> +         { +            Weapon#proto_weapon{ type = NewType }, +            (Amount * ?WEAPON_ATTRIBUTE_TYPE_COST) +         } +   end. + +-spec increase_critical_hit_chance_by +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_critical_hit_chance_by (Amount, Weapon) -> +   NewCriticalHitChance = (Weapon#proto_weapon.critical_hit_chance + Amount), +   case (NewCriticalHitChance > ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MAX) of +      true -> +         { +            Weapon#proto_weapon +            { +               critical_hit_chance = ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MAX +            }, +            ( +               ( +                  ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MAX +                  - Weapon#proto_weapon.critical_hit_chance +               ) +               * ?ATTRIBUTE_CRITICAL_HIT_CHANCE_COST +            ) +         }; + +      false -> +         { +            Weapon#proto_weapon{ critical_hit_chance = NewCriticalHitChance }, +            (Amount * ?ATTRIBUTE_CRITICAL_HIT_CHANCE_COST) +         } +   end. + +-spec increase_double_hit_chance_by +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_double_hit_chance_by (Amount, Weapon) -> +   NewDoubleHitChance = Weapon#proto_weapon.double_hit_chance + Amount, +   case (NewDoubleHitChance > ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MAX) of +      true -> +         { +            Weapon#proto_weapon +            { +               double_hit_chance = ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MAX +            }, +            ( +               ( +                  ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MAX +                  - Weapon#proto_weapon.double_hit_chance +               ) +               * ?ATTRIBUTE_DOUBLE_HIT_CHANCE_COST +            ) +         }; + +      false -> +         { +            Weapon#proto_weapon{ double_hit_chance = NewDoubleHitChance }, +            (Amount * ?ATTRIBUTE_DOUBLE_HIT_CHANCE_COST) +         } +   end. + + +-spec increase_attack_score_by +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_attack_score_by (Amount, Weapon) -> +   NewAttackScore = (Weapon#proto_weapon.attack_score + Amount), +   case (NewAttackScore > ?ATTRIBUTE_ATTACK_SCORE_MAX) of +      true -> +         { +            Weapon#proto_weapon +            { +               attack_score = ?ATTRIBUTE_ATTACK_SCORE_MAX, +               attack = +                  blc_damage_type:generate_entries_from_score +                  ( +                     NewAttackScore, +                     Weapon#proto_weapon.attack_coef +                  ) +            }, +            ( +               (?ATTRIBUTE_ATTACK_SCORE_MAX - Weapon#proto_weapon.attack_score) +               * Amount +            ) +         }; + +      false -> +         { +            Weapon#proto_weapon +            { +               attack_score = NewAttackScore, +               attack = +                  blc_damage_type:generate_entries_from_score +                  ( +                     NewAttackScore, +                     Weapon#proto_weapon.attack_coef +                  ) +            }, +            (Amount * ?ATTRIBUTE_ATTACK_SCORE_COST) +         } +   end. + +-spec set_attack_coefficients +   ( +      list(blc_damage_type:coefficient()), +      proto_weapon() +   ) +   -> proto_weapon(). +set_attack_coefficients (Coefficients, Weapon) -> +   {Result, 0} = +      increase_attack_score_by +      ( +         0, +         Weapon#proto_weapon +         { +            attack_coef = blc_damage_type:sort_entries(Coefficients) +         } +      ), + +   Result. + +-spec new (list(blc_damage_type:coefficient())) -> proto_weapon(). +new (Coefficients) -> +   {Result, _AttackScoreIncreaseCost} = +      increase_attack_score_by +      ( +         ?ATTRIBUTE_ATTACK_SCORE_MIN, +         #proto_weapon +         { +            range = ?WEAPON_ATTRIBUTE_RANGE_MIN, +            type = ?WEAPON_ATTRIBUTE_TYPE_MIN, +            accuracy = ?ATTRIBUTE_ACCURACY_MIN, +            critical_hit_chance = ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MIN, +            double_hit_chance = ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MIN, +            attack = [], +            attack_coef = blc_damage_type:sort_entries(Coefficients), +            attack_score = 0 +         } +      ), + +   Result. + +-spec increase_range_for +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_range_for (GivenPoints, Weapon) -> +   AmountOfIncrease = trunc(GivenPoints / ?WEAPON_ATTRIBUTE_RANGE_COST), +   {Result, SpentPoints} = increase_range_by(AmountOfIncrease, Weapon), +   {Result, (GivenPoints - SpentPoints)}. + +-spec increase_type_for +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_type_for (GivenPoints, Weapon) -> +   AmountOfIncrease = trunc(GivenPoints / ?WEAPON_ATTRIBUTE_TYPE_COST), +   {Result, SpentPoints} = increase_type_by(AmountOfIncrease, Weapon), +   {Result, (GivenPoints - SpentPoints)}. + +-spec increase_accuracy_for +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_accuracy_for (GivenPoints, Weapon) -> +   AmountOfIncrease = trunc(GivenPoints / ?ATTRIBUTE_ACCURACY_COST), +   {Result, SpentPoints} = increase_accuracy_by(AmountOfIncrease, Weapon), +   {Result, (GivenPoints - SpentPoints)}. + +-spec increase_critical_hit_chance_for +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_critical_hit_chance_for (GivenPoints, Weapon) -> +   AmountOfIncrease = trunc(GivenPoints / ?ATTRIBUTE_CRITICAL_HIT_CHANCE_COST), +   {Result, SpentPoints} = +      increase_critical_hit_chance_by(AmountOfIncrease, Weapon), + +   {Result, (GivenPoints - SpentPoints)}. + +-spec increase_double_hit_chance_for +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_double_hit_chance_for (GivenPoints, Weapon) -> +   AmountOfIncrease = trunc(GivenPoints / ?ATTRIBUTE_DOUBLE_HIT_CHANCE_COST), +   {Result, SpentPoints} = +      increase_double_hit_chance_by(AmountOfIncrease, Weapon), + +   {Result, (GivenPoints - SpentPoints)}. + + +-spec increase_attack_score_for +   ( +      non_neg_integer(), +      proto_weapon() +   ) +   -> {proto_weapon(), non_neg_integer()}. +increase_attack_score_for (GivenPoints, Weapon) -> +   AmountOfIncrease = trunc(GivenPoints / ?ATTRIBUTE_ATTACK_SCORE_COST), +   {Result, SpentPoints} = increase_attack_score_by(AmountOfIncrease, Weapon), +   {Result, (GivenPoints - SpentPoints)}. + + +-spec get_spendable_points () -> non_neg_integer(). +get_spendable_points () -> ?SPENDABLE_WEAPON_POINTS. | 


