summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/tacticians/attributes.hrl.m4 (renamed from include/base_attributes.hrl)20
-rw-r--r--include/tacticians/damage_types.hrl.m4 (renamed from include/damage_types.hrl.m4)0
-rw-r--r--src/balancer/blc_attribute.erl100
-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
-rw-r--r--src/shared/struct/shr_attributes.erl110
-rw-r--r--src/shared/struct/shr_damage_type.erl2
-rw-r--r--src/shared/struct/shr_omnimods.erl115
10 files changed, 1179 insertions, 68 deletions
diff --git a/include/base_attributes.hrl b/include/tacticians/attributes.hrl.m4
index 09bc136..3c0e731 100644
--- a/include/base_attributes.hrl
+++ b/include/tacticians/attributes.hrl.m4
@@ -1,48 +1,60 @@
+m4_include(__MAKEFILE_DATA_DIR/names.m4.conf)
+
+-define(ATTRIBUTE_DAMAGE_MODIFIER, __SN_DAMAGE_MODIFIER).
-define(ATTRIBUTE_DAMAGE_MODIFIER_MIN, 0).
-define(ATTRIBUTE_DAMAGE_MODIFIER_MAX, 300).
-define(ATTRIBUTE_DAMAGE_MODIFIER_DEFAULT, 100).
-define(ATTRIBUTE_DAMAGE_MODIFIER_COST, 1).
+-define(ATTRIBUTE_MOVEMENT_POINTS, __SN_MOVEMENT_POINTS).
-define(ATTRIBUTE_MOVEMENT_POINTS_MIN, 8).
-define(ATTRIBUTE_MOVEMENT_POINTS_MAX, 200).
-define(ATTRIBUTE_MOVEMENT_POINTS_DEFAULT, 32).
-define(ATTRIBUTE_MOVEMENT_POINTS_COST, 1).
+-define(ATTRIBUTE_HEALTH, __SN_MAX_HEALTH).
-define(ATTRIBUTE_HEALTH_MIN, 1).
-define(ATTRIBUTE_HEALTH_MAX, 500).
-define(ATTRIBUTE_HEALTH_DEFAULT, 100).
-define(ATTRIBUTE_HEALTH_COST, 1).
--define(ATTRIBUTE_DODGE_CHANCE_MIN, 0).
--define(ATTRIBUTE_DODGE_CHANCE_MAX, 175).
--define(ATTRIBUTE_DODGE_CHANCE_DEFAULT, 50).
--define(ATTRIBUTE_DODGE_CHANCE_COST, 1).
+-define(ATTRIBUTE_DODGE_CHANCE, __SN_DODGE).
+-define(ATTRIBUTE_DODGE_CHANCE_MIN, 0).
+-define(ATTRIBUTE_DODGE_CHANCE_MAX, 175).
+-define(ATTRIBUTE_DODGE_CHANCE_DEFAULT, 50).
+-define(ATTRIBUTE_DODGE_CHANCE_COST, 1).
+-define(ATTRIBUTE_PARRY_CHANCE, __SN_PARRY).
-define(ATTRIBUTE_PARRY_CHANCE_MIN, 0).
-define(ATTRIBUTE_PARRY_CHANCE_MAX, 100).
-define(ATTRIBUTE_PARRY_CHANCE_DEFAULT, 5).
-define(ATTRIBUTE_PARRY_CHANCE_COST, 1).
+-define(ATTRIBUTE_ACCURACY, __SN_ACCURACY).
-define(ATTRIBUTE_ACCURACY_MIN, 0).
-define(ATTRIBUTE_ACCURACY_MAX, 100).
-define(ATTRIBUTE_ACCURACY_DEFAULT, 50).
-define(ATTRIBUTE_ACCURACY_COST, 1).
+-define(ATTRIBUTE_DOUBLE_HIT_CHANCE, __SN_DOUBLE_HITS).
-define(ATTRIBUTE_DOUBLE_HIT_CHANCE_MIN, 0).
-define(ATTRIBUTE_DOUBLE_HIT_CHANCE_MAX, 100).
-define(ATTRIBUTE_DOUBLE_HIT_CHANCE_DEFAULT, 5).
-define(ATTRIBUTE_DOUBLE_HIT_CHANCE_COST, 1).
+-define(ATTRIBUTE_CRITICAL_HIT_CHANCE, __SN_CRITICAL_HIT).
-define(ATTRIBUTE_CRITICAL_HIT_CHANCE_MIN, 0).
-define(ATTRIBUTE_CRITICAL_HIT_CHANCE_MAX, 100).
-define(ATTRIBUTE_CRITICAL_HIT_CHANCE_DEFAULT, 10).
-define(ATTRIBUTE_CRITICAL_HIT_CHANCE_COST, 1).
+-define(ATTRIBUTE_DEFENSE_SCORE, def_score).
-define(ATTRIBUTE_DEFENSE_SCORE_MIN, 0).
-define(ATTRIBUTE_DEFENSE_SCORE_MAX, 300).
-define(ATTRIBUTE_DEFENSE_SCORE_DEFAULT, 50).
-define(ATTRIBUTE_DEFENSE_SCORE_COST, 1).
+-define(ATTRIBUTE_ATTACK_SCORE, atk_score).
-define(ATTRIBUTE_ATTACK_SCORE_MIN, 0).
-define(ATTRIBUTE_ATTACK_SCORE_MAX, 300).
-define(ATTRIBUTE_ATTACK_SCORE_DEFAULT, 50).
diff --git a/include/damage_types.hrl.m4 b/include/tacticians/damage_types.hrl.m4
index df82e59..df82e59 100644
--- a/include/damage_types.hrl.m4
+++ b/include/tacticians/damage_types.hrl.m4
diff --git a/src/balancer/blc_attribute.erl b/src/balancer/blc_attribute.erl
new file mode 100644
index 0000000..55becfa
--- /dev/null
+++ b/src/balancer/blc_attribute.erl
@@ -0,0 +1,100 @@
+-module(blc_attribute).
+
+-include("tacticians/attributes.hrl").
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export
+(
+ [
+ get_info/1
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec get_info
+ (
+ shr_attributes:meta_enum()
+ )
+ ->
+ {
+ non_neg_integer(),
+ non_neg_integer(),
+ non_neg_integer(),
+ non_neg_integer()
+ }.
+get_info (?ATTRIBUTE_ACCURACY) ->
+ {
+ ?ATTRIBUTE_ACCURACY_MIN,
+ ?ATTRIBUTE_ACCURACY_DEFAULT,
+ ?ATTRIBUTE_ACCURACY_MAX,
+ ?ATTRIBUTE_ACCURACY_COST
+ };
+get_info (?ATTRIBUTE_ATTACK_SCORE) ->
+ {
+ ?ATTRIBUTE_ATTACK_SCORE_MIN,
+ ?ATTRIBUTE_ATTACK_SCORE_DEFAULT,
+ ?ATTRIBUTE_ATTACK_SCORE_MAX,
+ ?ATTRIBUTE_ATTACK_SCORE_COST
+ };
+get_info (?ATTRIBUTE_CRITICAL_HIT_CHANCE) ->
+ {
+ ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MIN,
+ ?ATTRIBUTE_CRITICAL_HIT_CHANCE_DEFAULT,
+ ?ATTRIBUTE_CRITICAL_HIT_CHANCE_MAX,
+ ?ATTRIBUTE_CRITICAL_HIT_CHANCE_COST
+ };
+get_info (?ATTRIBUTE_DEFENSE_SCORE) ->
+ {
+ ?ATTRIBUTE_DEFENSE_SCORE_MIN,
+ ?ATTRIBUTE_DEFENSE_SCORE_DEFAULT,
+ ?ATTRIBUTE_DEFENSE_SCORE_MAX,
+ ?ATTRIBUTE_DEFENSE_SCORE_COST
+ };
+get_info (?ATTRIBUTE_DODGE_CHANCE) ->
+ {
+ ?ATTRIBUTE_DODGE_CHANCE_MIN,
+ ?ATTRIBUTE_DODGE_CHANCE_DEFAULT,
+ ?ATTRIBUTE_DODGE_CHANCE_MAX,
+ ?ATTRIBUTE_DODGE_CHANCE_COST
+ };
+get_info (?ATTRIBUTE_DOUBLE_HIT_CHANCE) ->
+ {
+ ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MIN,
+ ?ATTRIBUTE_DOUBLE_HIT_CHANCE_DEFAULT,
+ ?ATTRIBUTE_DOUBLE_HIT_CHANCE_MAX,
+ ?ATTRIBUTE_DOUBLE_HIT_CHANCE_COST
+ };
+get_info (?ATTRIBUTE_HEALTH) ->
+ {
+ ?ATTRIBUTE_HEALTH_MIN,
+ ?ATTRIBUTE_HEALTH_DEFAULT,
+ ?ATTRIBUTE_HEALTH_MAX,
+ ?ATTRIBUTE_HEALTH_COST
+ };
+get_info (?ATTRIBUTE_MOVEMENT_POINTS) ->
+ {
+ ?ATTRIBUTE_MOVEMENT_POINTS_MIN,
+ ?ATTRIBUTE_MOVEMENT_POINTS_DEFAULT,
+ ?ATTRIBUTE_MOVEMENT_POINTS_MAX,
+ ?ATTRIBUTE_MOVEMENT_POINTS_COST
+ };
+get_info (?ATTRIBUTE_PARRY_CHANCE) ->
+ {
+ ?ATTRIBUTE_PARRY_CHANCE_MIN,
+ ?ATTRIBUTE_PARRY_CHANCE_DEFAULT,
+ ?ATTRIBUTE_PARRY_CHANCE_MAX,
+ ?ATTRIBUTE_PARRY_CHANCE_COST
+ }.
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.
diff --git a/src/shared/struct/shr_attributes.erl b/src/shared/struct/shr_attributes.erl
index cd3aedf..44d2e04 100644
--- a/src/shared/struct/shr_attributes.erl
+++ b/src/shared/struct/shr_attributes.erl
@@ -1,5 +1,7 @@
-module(shr_attributes).
+-include("tacticians/attributes.hrl").
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -9,18 +11,36 @@
{
movement_points :: non_neg_integer(),
health :: non_neg_integer(),
- dodges :: integer(),
- parries :: integer(),
+ dodge_chance :: integer(),
+ parry_chance :: integer(),
accuracy :: integer(),
- double_hits :: integer(),
- critical_hits :: integer(),
+ double_hit_chance :: integer(),
+ critical_hit_chance :: integer(),
damage_modifier :: integer()
}
).
-opaque type() :: #attributes{}.
-
--export_type([type/0]).
+-type enum() ::
+ (
+ ?ATTRIBUTE_ACCURACY
+ | ?ATTRIBUTE_CRITICAL_HIT_CHANCE
+ | ?ATTRIBUTE_DAMAGE_MODIFIER
+ | ?ATTRIBUTE_DODGE_CHANCE
+ | ?ATTRIBUTE_DOUBLE_HIT_CHANCE
+ | ?ATTRIBUTE_HEALTH
+ | ?ATTRIBUTE_MOVEMENT_POINTS
+ | ?ATTRIBUTE_PARRY_CHANCE
+ ).
+
+-type meta_enum() ::
+ (
+ enum()
+ | ?ATTRIBUTE_ATTACK_SCORE
+ | ?ATTRIBUTE_DEFENSE_SCORE
+ ).
+
+-export_type([type/0,enum/0,meta_enum/0]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -31,11 +51,11 @@
[
get_movement_points/1,
get_health/1,
- get_dodges/1,
- get_parries/1,
+ get_dodge_chance/1,
+ get_parry_chance/1,
get_accuracy/1,
- get_double_hits/1,
- get_critical_hits/1,
+ get_double_hit_chance/1,
+ get_critical_hit_chance/1,
get_damage_modifier/1,
get_damage_multiplier/1,
@@ -64,25 +84,25 @@ mod_movement_points (Mod, Atts) ->
mod_health (Mod, Atts) ->
Atts#attributes{ health = (Atts#attributes.health + Mod) }.
--spec mod_dodges (integer(), type()) -> type().
-mod_dodges (Mod, Atts) ->
- Atts#attributes{ dodges = (Atts#attributes.dodges + Mod) }.
+-spec mod_dodge_chance (integer(), type()) -> type().
+mod_dodge_chance (Mod, Atts) ->
+ Atts#attributes{ dodge_chance = (Atts#attributes.dodge_chance + Mod) }.
--spec mod_parries (integer(), type()) -> type().
-mod_parries (Mod, Atts) ->
- Atts#attributes{ parries = (Atts#attributes.parries + Mod) }.
+-spec mod_parry_chance (integer(), type()) -> type().
+mod_parry_chance (Mod, Atts) ->
+ Atts#attributes{ parry_chance = (Atts#attributes.parry_chance + Mod) }.
-spec mod_accuracy (integer(), type()) -> type().
mod_accuracy (Mod, Atts) ->
Atts#attributes{ accuracy = (Atts#attributes.accuracy + Mod) }.
--spec mod_double_hits (integer(), type()) -> type().
-mod_double_hits (Mod, Atts) ->
- Atts#attributes{ double_hits = (Atts#attributes.double_hits + Mod) }.
+-spec mod_double_hit_chance (integer(), type()) -> type().
+mod_double_hit_chance (Mod, Atts) ->
+ Atts#attributes{ double_hit_chance = (Atts#attributes.double_hit_chance + Mod) }.
--spec mod_critical_hits (integer(), type()) -> type().
-mod_critical_hits (Mod, Atts) ->
- Atts#attributes{ critical_hits = (Atts#attributes.critical_hits + Mod) }.
+-spec mod_critical_hit_chance (integer(), type()) -> type().
+mod_critical_hit_chance (Mod, Atts) ->
+ Atts#attributes{ critical_hit_chance = (Atts#attributes.critical_hit_chance + Mod) }.
-spec mod_damage_modifier (integer(), type()) -> type().
mod_damage_modifier (Mod, Atts) ->
@@ -101,20 +121,20 @@ get_movement_points (Atts) -> max(0, Atts#attributes.movement_points).
-spec get_health (type()) -> non_neg_integer().
get_health (Atts) -> max(1, Atts#attributes.health).
--spec get_dodges (type()) -> non_neg_integer().
-get_dodges (Atts) -> max(0, Atts#attributes.dodges).
+-spec get_dodge_chance (type()) -> non_neg_integer().
+get_dodge_chance (Atts) -> max(0, Atts#attributes.dodge_chance).
--spec get_parries (type()) -> non_neg_integer().
-get_parries (Atts) -> max(0, Atts#attributes.parries).
+-spec get_parry_chance (type()) -> non_neg_integer().
+get_parry_chance (Atts) -> max(0, Atts#attributes.parry_chance).
-spec get_accuracy (type()) -> non_neg_integer().
get_accuracy (Atts) -> max(0, Atts#attributes.accuracy).
--spec get_double_hits (type()) -> non_neg_integer().
-get_double_hits (Atts) -> max(0, Atts#attributes.double_hits).
+-spec get_double_hit_chance (type()) -> non_neg_integer().
+get_double_hit_chance (Atts) -> max(0, Atts#attributes.double_hit_chance).
--spec get_critical_hits (type()) -> non_neg_integer().
-get_critical_hits (Atts) -> max(0, Atts#attributes.critical_hits).
+-spec get_critical_hit_chance (type()) -> non_neg_integer().
+get_critical_hit_chance (Atts) -> max(0, Atts#attributes.critical_hit_chance).
-spec get_damage_modifier (type()) -> non_neg_integer().
get_damage_modifier (Atts) -> max(0, Atts#attributes.damage_modifier).
@@ -128,20 +148,24 @@ default () ->
{
movement_points = 0,
health = 1,
- dodges = 0,
- parries = 0,
+ dodge_chance = 0,
+ parry_chance = 0,
accuracy = 0,
- double_hits = 0,
- critical_hits = 0,
+ double_hit_chance = 0,
+ critical_hit_chance = 0,
damage_modifier = 100
}.
--spec apply_mod (atom(), integer(), type()) -> type().
-apply_mod(mheal, Value, Atts) -> mod_health(Value, Atts);
-apply_mod(mpts, Value, Atts) -> mod_movement_points(Value, Atts);
-apply_mod(dodg, Value, Atts) -> mod_dodges(Value, Atts);
-apply_mod(pary, Value, Atts) -> mod_parries(Value, Atts);
-apply_mod(accu, Value, Atts) -> mod_accuracy(Value, Atts);
-apply_mod(dhit, Value, Atts) -> mod_double_hits(Value, Atts);
-apply_mod(crit, Value, Atts) -> mod_critical_hits(Value, Atts);
-apply_mod(dmgm, Value, Atts) -> mod_damage_modifier(Value, Atts).
+-spec apply_mod (enum(), integer(), type()) -> type().
+apply_mod(?ATTRIBUTE_HEALTH, Mod, Atts) -> mod_health(Mod, Atts);
+apply_mod(?ATTRIBUTE_DODGE_CHANCE, Mod, Atts) -> mod_dodge_chance(Mod, Atts);
+apply_mod(?ATTRIBUTE_PARRY_CHANCE, Mod, Atts) -> mod_parry_chance(Mod, Atts);
+apply_mod(?ATTRIBUTE_ACCURACY, Mod, Atts) -> mod_accuracy(Mod, Atts);
+apply_mod(?ATTRIBUTE_MOVEMENT_POINTS, Mod, Atts) ->
+ mod_movement_points(Mod, Atts);
+apply_mod(?ATTRIBUTE_DOUBLE_HIT_CHANCE, Mod, Atts) ->
+ mod_double_hit_chance(Mod, Atts);
+apply_mod(?ATTRIBUTE_CRITICAL_HIT_CHANCE, Mod, Atts) ->
+ mod_critical_hit_chance(Mod, Atts);
+apply_mod(?ATTRIBUTE_DAMAGE_MODIFIER, Mod, Atts) ->
+ mod_damage_modifier(Mod, Atts).
diff --git a/src/shared/struct/shr_damage_type.erl b/src/shared/struct/shr_damage_type.erl
index 9bcd79f..d739514 100644
--- a/src/shared/struct/shr_damage_type.erl
+++ b/src/shared/struct/shr_damage_type.erl
@@ -1,6 +1,6 @@
-module(shr_damage_type).
--include("damage_types.hrl").
+-include("tacticians/damage_types.hrl").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/src/shared/struct/shr_omnimods.erl b/src/shared/struct/shr_omnimods.erl
index 7602e1f..e4993c8 100644
--- a/src/shared/struct/shr_omnimods.erl
+++ b/src/shared/struct/shr_omnimods.erl
@@ -3,22 +3,36 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--type entry() :: {atom(), integer()}.
--type mods() :: dict:dict(atom(), integer()).
+-type attribute_entry() :: {shr_attributes:enum(), integer()}.
+-type attribute_mods() :: dict:dict(shr_attributes:enum(), integer()).
+
+-type damage_type_entry() :: {shr_damage_type:type(), integer()}.
+-type damage_type_mods() :: dict:dict(shr_damage_type:type(), integer()).
+
+-type entry() :: (attribute_entry() | damage_type_entry()).
+-type mods() :: (attribute_mods() | damage_type_mods()).
-record
(
omnimods,
{
- attmods :: mods(),
- atkmods :: mods(),
- defmods :: mods()
+ attmods :: attribute_mods(),
+ atkmods :: damage_type_mods(),
+ defmods :: damage_type_mods()
}
).
-opaque type() :: #omnimods{}.
--export_type([type/0, entry/0]).
+-export_type
+(
+ [
+ type/0,
+ attribute_entry/0,
+ damage_type_entry/0,
+ entry/0
+ ]
+).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -27,7 +41,7 @@
-export
(
[
- default/0,
+ new/0,
new/3
]
).
@@ -37,7 +51,10 @@
(
[
merge/2,
- apply_coefficient/2
+ apply_coefficient/2,
+ set_attribute_modifiers/2,
+ set_attack_modifiers/2,
+ set_defense_modifiers/2
]
).
@@ -46,7 +63,13 @@
(
[
apply_to_attributes/2,
- get_attack_damage/3
+ get_attack_damage/3,
+ get_attribute_modifier/2,
+ get_attack_modifier/2,
+ get_defense_modifier/2,
+ get_attribute_modifiers/1,
+ get_attack_modifiers/1,
+ get_defense_modifiers/1
]
).
@@ -61,11 +84,15 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec apply_coefficient_to_mods (float(), mods()) -> mods().
+-spec apply_coefficient_to_mods
+ (float(), attribute_mods()) -> attribute_mods();
+ (float(), damage_type_mods()) -> damage_type_mods().
apply_coefficient_to_mods (Coef, Mods) ->
dict:map(fun (_Name, Val) -> shr_math_util:ceil(Coef * Val) end, Mods).
--spec merge_mods (mods(), mods()) -> mods().
+-spec merge_mods
+ (attribute_mods(), attribute_mods()) -> attribute_mods();
+ (damage_type_mods(), damage_type_mods()) -> damage_type_mods().
merge_mods (ModsA, ModsB) ->
dict:merge(fun (_Name, ValA, ValB) -> (ValA + ValB) end, ModsA, ModsB).
@@ -88,7 +115,13 @@ encode_mods (Mods) ->
%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Creation
--spec new (list(entry()), list(entry()), list(entry())) -> type().
+-spec new
+ (
+ list(attribute_entry()),
+ list(damage_type_entry()),
+ list(damage_type_entry())
+ )
+ -> type().
new (AttributeMods, AttackMods, DefenseMods) ->
#omnimods
{
@@ -97,8 +130,8 @@ new (AttributeMods, AttackMods, DefenseMods) ->
defmods = dict:from_list(DefenseMods)
}.
--spec default () -> type().
-default () -> new([], [], []).
+-spec new () -> type().
+new () -> new([], [], []).
%%% Modification
-spec merge (type(), type()) -> type().
@@ -119,6 +152,28 @@ apply_coefficient (Coef, Omnimods) ->
defmods = apply_coefficient_to_mods(Coef, Omnimods#omnimods.defmods)
}.
+-spec set_attribute_modifiers (list(attribute_entry()), type()) -> type().
+set_attribute_modifiers (NewAttributeModifiers, Omnimods) ->
+ Omnimods#omnimods
+ {
+ attmods = dict:from_list(NewAttributeModifiers)
+ }.
+
+-spec set_defense_modifiers (list(damage_type_entry()), type()) -> type().
+set_defense_modifiers (NewDefenseModifiers, Omnimods) ->
+ Omnimods#omnimods
+ {
+ defmods = dict:from_list(NewDefenseModifiers)
+ }.
+
+-spec set_attack_modifiers (list(damage_type_entry()), type()) -> type().
+set_attack_modifiers (NewAttackModifiers, Omnimods) ->
+ Omnimods#omnimods
+ {
+ atkmods = dict:from_list(NewAttackModifiers)
+ }.
+
+%%%% Access
-spec apply_to_attributes
(
type(),
@@ -133,6 +188,7 @@ apply_to_attributes (Omnimods, Attributes) ->
Omnimods#omnimods.attmods
).
+% FIXME: 'base' is no longer used.
-spec get_attack_damage (float(), type(), type()) -> non_neg_integer().
get_attack_damage (AttackModifier, AttackerOmnimods, DefenderOmnimods) ->
AttackerOmnimodsAttmods = AttackerOmnimods#omnimods.atkmods,
@@ -191,6 +247,37 @@ get_attack_damage (AttackModifier, AttackerOmnimods, DefenderOmnimods) ->
Result.
+-spec get_attribute_modifier (shr_attributes:enum(), type()) -> integer().
+get_attribute_modifier (Attribute, Omnimods) ->
+ case dict:find(Attribute, Omnimods#omnimods.attmods) of
+ {ok, Value} -> Value;
+ error -> 0
+ end.
+
+-spec get_attack_modifier (shr_damage_type:type(), type()) -> integer().
+get_attack_modifier (DamageType, Omnimods) ->
+ case dict:find(DamageType, Omnimods#omnimods.atkmods) of
+ {ok, Value} -> Value;
+ error -> 0
+ end.
+
+-spec get_defense_modifier (shr_damage_type:type(), type()) -> integer().
+get_defense_modifier (DamageType, Omnimods) ->
+ case dict:find(DamageType, Omnimods#omnimods.defmods) of
+ {ok, Value} -> Value;
+ error -> 0
+ end.
+
+-spec get_attribute_modifiers (type()) -> list(attribute_entry()).
+get_attribute_modifiers (Omnimods) -> lists:to_list(Omnimods#omnimods.attmods).
+
+-spec get_attack_modifiers (type()) -> list(damage_type_entry()).
+get_attack_modifiers (Omnimods) -> lists:to_list(Omnimods#omnimods.atkmods).
+
+-spec get_defense_modifiers (type()) -> list(damage_type_entry()).
+get_defense_modifiers (Omnimods) -> lists:to_list(Omnimods#omnimods.defmods).
+
+
%%% Export
-spec encode (type()) -> {list(any())}.
encode (Omnimods) ->