summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/balancer/struct')
-rw-r--r--src/balancer/struct/blc_armor.erl11
-rw-r--r--src/balancer/struct/blc_error.erl24
-rw-r--r--src/balancer/struct/blc_glyph.erl451
-rw-r--r--src/balancer/struct/blc_weapon.erl414
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.