summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authornsensfel <SpamShield0@noot-noot.org>2019-06-05 11:24:52 +0200
committernsensfel <SpamShield0@noot-noot.org>2019-06-05 11:24:52 +0200
commit1afb69a11b0e291c7bfd6c24bdd8e55742e61889 (patch)
tree21c09b15ddcc3272bbb8fa8d41676ffa56ca3130 /src
parent1aec9784102855c4bf2e5d2ad9a945166aed2051 (diff)
[Broken] Changing how actions are handled...
Diffstat (limited to 'src')
-rw-r--r--src/battle/mechanic/btl_attack.erl554
-rw-r--r--src/battle/mechanic/btl_turn_actions_management.erl50
-rw-r--r--src/battle/reply/btl_add_char.erl2
-rw-r--r--src/battle/struct/btl_action.erl102
-rw-r--r--src/battle/struct/btl_attack.erl28
-rw-r--r--src/battle/struct/btl_battle.erl112
-rw-r--r--src/battle/struct/btl_character.erl20
-rw-r--r--src/battle/struct/btl_character_turn_request.erl14
-rw-r--r--src/battle/struct/btl_character_turn_update.erl12
-rw-r--r--src/shared/struct/shr_character.erl7
10 files changed, 767 insertions, 134 deletions
diff --git a/src/battle/mechanic/btl_attack.erl b/src/battle/mechanic/btl_attack.erl
new file mode 100644
index 0000000..cbc1baa
--- /dev/null
+++ b/src/battle/mechanic/btl_attack.erl
@@ -0,0 +1,554 @@
+-module(btl_attack).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export
+(
+ [
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec roll_precision
+ (
+ shr_statistics:type(),
+ shr_statistics:type(),
+ integer()
+ )
+ -> {precision(), integer(), integer()}.
+roll_precision
+(
+ AttackerStatistics,
+ DefenderStatistics,
+ DefenderLuck
+) ->
+ DefenderDodges = shr_statistics:get_dodges(DefenderStatistics),
+ AttackerAccuracy = shr_statistics:get_accuracy(AttackerStatistics),
+ MissChance = max(0, (DefenderDodges - AttackerAccuracy)),
+
+ {Roll, _IsSuccess, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(MissChance, DefenderLuck),
+
+ {
+ case Roll of
+ X when (X =< MissChance) -> misses;
+ X when (X =< (MissChance * 2)) -> grazes;
+ _ -> hits
+ end,
+ PositiveModifier,
+ NegativeModifier
+ }.
+
+-spec roll_critical_hit
+ (
+ shr_statistics:type(),
+ integer()
+ )
+ -> {boolean(), integer(), integer()}.
+roll_critical_hit (AttackerStatistics, AttackerLuck) ->
+ CriticalHitChance = shr_statistics:get_critical_hits(AttackerStatistics),
+ {_Roll, IsSuccess, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(CriticalHitChance, AttackerLuck),
+
+ {IsSuccess, PositiveModifier, NegativeModifier}.
+
+-spec roll_parry
+ (
+ shr_statistics:type(),
+ integer()
+ )
+ -> {boolean(), integer(), integer()}.
+roll_parry (DefenderStatistics, DefenderLuck) ->
+ DefenderParryChance = shr_statistics:get_parries(DefenderStatistics),
+ {_Roll, IsSuccess, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(DefenderParryChance, DefenderLuck),
+
+ {IsSuccess, PositiveModifier, NegativeModifier}.
+
+-spec get_damage
+ (
+ precision(),
+ boolean(),
+ float(),
+ shr_omnimods:type(),
+ shr_omnimods:type()
+ )
+ -> non_neg_integer().
+get_damage
+(
+ Precision,
+ IsCritical,
+ StartingDamageMultiplier,
+ AttackerOmnimods,
+ DefenderOmnimods
+) ->
+ ActualDamageMultiplier =
+ (
+ StartingDamageMultiplier
+ *
+ (
+ case Precision of
+ misses -> 0;
+ grazes -> 0.5;
+ hits -> 1
+ end
+ )
+ *
+ (
+ case IsCritical of
+ true -> 2;
+ _ -> 1
+ end
+ )
+ ),
+
+ ActualDamage =
+ shr_omnimods:get_attack_damage
+ (
+ ActualDamageMultiplier,
+ AttackerOmnimods,
+ DefenderOmnimods
+ ),
+
+ ActualDamage.
+
+-spec effect_of_attack
+ (
+ order(),
+ shr_character:type(),
+ shr_character:type(),
+ boolean(),
+ integer(),
+ integer()
+ )
+ -> type().
+effect_of_attack
+(
+ Order,
+ Attacker,
+ Defender,
+ CanParry,
+ AttackerLuck,
+ DefenderLuck
+) ->
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%% Roll parry to see if the roles have to be swapped. %%%%%%%%%%%%%%%%%%%%%
+
+ DefenderStats = shr_character:get_statistics(Defender),
+ {ParryIsSuccessful, ParryPositiveLuckMod, ParryNegativeLuckMod} =
+ case CanParry of
+ true -> roll_parry(DefenderStats, DefenderLuck);
+ false -> {false, 0, 0}
+ end,
+
+ {
+ ActualAttacker,
+ ActualDefender,
+ ActualAttackerLuck,
+ ActualDefenderLuck
+ } =
+ case ParryIsSuccessful of
+ true -> {Defender, Attacker, DefenderLuck, AttackerLuck};
+ false -> {Attacker, Defender, AttackerLuck, DefenderLuck}
+ end,
+
+ ActualAttackerStats = shr_character:get_statistics(ActualAttacker),
+ ActualAttackerOmnimods = shr_character:get_omnimods(ActualAttacker),
+ ActualDefenderStats = shr_character:get_statistics(ActualDefender),
+ ActualDefenderOmnimods = shr_character:get_omnimods(ActualDefender),
+
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ {Precision, PrecisionPositiveLuckMod, PrecisionNegativeLuckMod} =
+ roll_precision
+ (
+ ActualAttackerStats,
+ ActualDefenderStats,
+ ActualDefenderLuck
+ ),
+
+
+ {IsCritical, CriticalPositiveLuckMod, CriticalNegativeLuckMod} =
+ roll_critical_hit(ActualAttackerStats, ActualAttackerLuck),
+
+ ActualAttackerDamageModifier =
+ shr_statistics:get_damage_modifier(ActualAttackerStats),
+
+ Damage =
+ get_damage
+ (
+ Precision,
+ IsCritical,
+ ActualAttackerDamageModifier,
+ ActualAttackerOmnimods,
+ ActualDefenderOmnimods
+ ),
+
+ {FinalAttackerLuckMod, FinalDefenderLuckMod} =
+ case {ParryIsSuccessful, Precision} of
+ {true, misses} ->
+ {
+ (
+ % Attacker wasn't the one parrying
+ ParryNegativeLuckMod
+ % Attacker was the one evading
+ + PrecisionPositiveLuckMod
+ % miss -> no critical hit luck modifier
+ ),
+ (
+ % Defender was the one parrying
+ ParryPositiveLuckMod
+ % Defender wasn't the one evading
+ + PrecisionNegativeLuckMod
+ % miss -> no critical hit luck modifier
+ )
+ };
+
+ {true, _} ->
+ {
+ (
+ % Attacker wasn't the one parrying
+ ParryNegativeLuckMod
+ % Attacker was the one evading
+ + PrecisionPositiveLuckMod
+ % Attacker wasn't the one doing a critical
+ + CriticalNegativeLuckMod
+ ),
+ (
+ % Defender was the one parrying
+ ParryPositiveLuckMod
+ % Defender wasn't the one evading
+ + PrecisionNegativeLuckMod
+ % Defender was the one doing a critical
+ + CriticalPositiveLuckMod
+ )
+ };
+
+ {false, misses} ->
+ {
+ (
+ % Attacker wasn't the one parrying
+ ParryNegativeLuckMod
+ % Defender was the one evading
+ + PrecisionNegativeLuckMod
+ % miss -> no critical hit luck modifier
+ ),
+ (
+ % Defender was the one parrying
+ ParryPositiveLuckMod
+ % Defender was the one evading
+ + PrecisionPositiveLuckMod
+ % miss -> no critical hit luck modifier
+ )
+ };
+
+ {false, _} ->
+ {
+ (
+ % Attacker wasn't the one parrying
+ ParryNegativeLuckMod
+ % Attacker wasn't the one evading
+ + PrecisionNegativeLuckMod
+ % Attacker was the one doing a critical
+ + CriticalPositiveLuckMod
+ ),
+ (
+ % Defender was the one parrying
+ ParryPositiveLuckMod
+ % Defender was the one evading
+ + PrecisionPositiveLuckMod
+ % Defender wasn't the one doing a critical
+ + CriticalNegativeLuckMod
+ )
+ }
+ end,
+
+ #attack
+ {
+ order = Order,
+ precision = Precision,
+ is_critical = IsCritical,
+ is_parry = ParryIsSuccessful,
+ damage = Damage,
+ attacker_luck_mod = FinalAttackerLuckMod,
+ defender_luck_mod = FinalDefenderLuckMod
+ }.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec get_description_of
+ (
+ step(),
+ shr_character:type(),
+ shr_character:type(),
+ integer(),
+ integer()
+ )
+ -> maybe_type().
+get_description_of
+(
+ {first, CanParry},
+ Attacker,
+ Defender,
+ AttackerLuck,
+ DefenderLuck
+) ->
+ effect_of_attack
+ (
+ first,
+ Attacker,
+ Defender,
+ CanParry,
+ AttackerLuck,
+ DefenderLuck
+ );
+get_description_of
+(
+ {second, CanParry},
+ Attacker,
+ Defender,
+ AttackerLuck,
+ DefenderLuck
+) ->
+ AttackerStats = shr_character:get_statistics(Attacker),
+ AttackerDoubleAttackChance =
+ shr_statistics:get_double_hits(AttackerStats),
+ {_Roll, IsSuccessful, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(AttackerDoubleAttackChance, AttackerLuck),
+
+ NewAttackerLuck = (AttackerLuck + PositiveModifier),
+ NewDefenderLuck = (DefenderLuck + NegativeModifier),
+
+ case IsSuccessful of
+ true ->
+ Result =
+ effect_of_attack
+ (
+ second,
+ Attacker,
+ Defender,
+ CanParry,
+ NewAttackerLuck,
+ NewDefenderLuck
+ ),
+
+ Result#attack
+ {
+ attacker_luck_mod =
+ (Result#attack.attacker_luck_mod + PositiveModifier),
+ defender_luck_mod =
+ (Result#attack.defender_luck_mod + NegativeModifier)
+ };
+
+ _ -> {nothing, PositiveModifier, NegativeModifier}
+ end;
+get_description_of
+(
+ {counter, CanParry},
+ Attacker,
+ Defender,
+ AttackerLuck,
+ DefenderLuck
+) ->
+ effect_of_attack
+ (
+ counter,
+ Defender,
+ Attacker,
+ CanParry,
+ DefenderLuck,
+ AttackerLuck
+ ).
+
+-spec apply_to_healths_and_lucks
+ (
+ maybe_type(),
+ non_neg_integer(),
+ integer(),
+ non_neg_integer(),
+ integer()
+ )
+ ->
+ {
+ maybe_type(),
+ non_neg_integer(),
+ integer(),
+ non_neg_integer(),
+ integer()
+ }.
+apply_to_healths_and_lucks
+(
+ _Attack,
+ AttackerHealth,
+ AttackerLuck,
+ DefenderHealth,
+ DefenderLuck
+)
+when
+(
+ (AttackerHealth =< 0)
+ or (DefenderHealth =< 0)
+) ->
+ {
+ {nothing, 0, 0},
+ AttackerHealth,
+ AttackerLuck,
+ DefenderHealth,
+ DefenderLuck
+ };
+apply_to_healths_and_lucks
+(
+ {nothing, AttackerLuckMod, DefenderLuckMod},
+ AttackerHealth,
+ AttackerLuck,
+ DefenderHealth,
+ DefenderLuck
+) ->
+ {
+ {nothing, AttackerLuckMod, DefenderLuckMod},
+ AttackerHealth,
+ (AttackerLuck + AttackerLuckMod),
+ DefenderHealth,
+ (DefenderLuck + DefenderLuckMod)
+ };
+apply_to_healths_and_lucks
+(
+ Attack,
+ AttackerHealth,
+ AttackerLuck,
+ DefenderHealth,
+ DefenderLuck
+)
+when
+(
+ (
+ (not Attack#attack.is_parry)
+ and ((Attack#attack.order == first) or (Attack#attack.order == second))
+ )
+ or
+ (
+ Attack#attack.is_parry
+ and (Attack#attack.order == counter)
+ )
+) ->
+ Damage = Attack#attack.damage,
+
+ {
+ Attack,
+ AttackerHealth,
+ (AttackerLuck + Attack#attack.attacker_luck_mod),
+ (DefenderHealth - Damage),
+ (DefenderLuck + Attack#attack.defender_luck_mod)
+ };
+apply_to_healths_and_lucks
+(
+ Attack,
+ AttackerHealth,
+ AttackerLuck,
+ DefenderHealth,
+ DefenderLuck
+)
+when
+(
+ (
+ (not Attack#attack.is_parry)
+ and (Attack#attack.order == counter)
+ )
+ or
+ (
+ Attack#attack.is_parry
+ and ((Attack#attack.order == first) or (Attack#attack.order == second))
+ )
+) ->
+ Damage = Attack#attack.damage,
+
+ {
+ Attack,
+ (AttackerHealth - Damage),
+ (AttackerLuck + Attack#attack.attacker_luck_mod),
+ DefenderHealth,
+ (DefenderLuck + Attack#attack.defender_luck_mod)
+ }.
+
+-spec get_sequence
+ (
+ non_neg_integer(),
+ shr_weapon:type(),
+ shr_weapon:type()
+ )
+ -> list(step()).
+get_sequence (AttackRange, AttackerWeapon, DefenderWeapon) ->
+ AttackerDefenseRange = shr_weapon:get_minimum_range(AttackerWeapon),
+ AttackerAttackRange = shr_weapon:get_maximum_range(AttackerWeapon),
+ DefenderDefenseRange = shr_weapon:get_minimum_range(DefenderWeapon),
+ DefenderAttackRange = shr_weapon:get_maximum_range(DefenderWeapon),
+
+ AttackerCanAttack = (AttackRange =< AttackerAttackRange),
+ AttackerCanDefend =
+ (AttackerCanAttack and (AttackRange > AttackerDefenseRange)),
+
+ true = (AttackerCanAttack == true),
+
+ DefenderCanAttack = (AttackRange =< DefenderAttackRange),
+ DefenderCanDefend =
+ (DefenderCanAttack and (AttackRange > DefenderDefenseRange)),
+
+ First = {first, DefenderCanDefend},
+ Second = {second, DefenderCanDefend},
+ Counter = {counter, AttackerCanDefend},
+
+ case DefenderCanDefend of
+ true -> [First, Counter, Second];
+ _ -> [First, Second]
+ end.
+
+-spec standard
+ (
+ non_neg_integer(),
+ btl_character:type(),
+ btl_player:type(),
+ btl_character:type()
+ btl_player:type()
+ )
+ ->
+ {
+ % Attack Descriptions,
+ % Updated Attacker
+ % Attacker Ataxia Update
+ % Updated Defender
+ % Defender Ataxia Update
+ }
+
+-spec attack_of_opportunity
+ (
+ btl_character:type(),
+ btl_player:type(),
+ btl_character:type()
+ btl_player:type(),
+ )
+ ->
+ {
+ % Attack Descriptions,
+ % Updated Attacker
+ % Attacker Ataxia Update
+ % Updated Attacking Player
+ % Attacking Player Ataxia Update
+ % Updated Defender
+ % Defender Ataxia Update
+ % Updated Defending Player
+ % Attacking Player Ataxia Update
+ }
+
+attack_of_opportunity () ->
+ [
+ {first, false},
+ {second, false}
+ ].
diff --git a/src/battle/mechanic/btl_turn_actions_management.erl b/src/battle/mechanic/btl_turn_actions_management.erl
index eefe812..0981ab4 100644
--- a/src/battle/mechanic/btl_turn_actions_management.erl
+++ b/src/battle/mechanic/btl_turn_actions_management.erl
@@ -37,15 +37,6 @@ deactivate_character (Update) ->
S1Update.
--spec main_character_is_alive
- (
- btl_character_turn_update:type()
- )
- -> {boolean(), btl_character_turn_update:type()}.
-main_character_is_alive (Update) ->
- {S0Update, MainCharacter} = btl_character_turn_update:get_character(Update),
- {btl_character:get_is_alive(MainCharacter), S0Update}.
-
-spec handle_actions
(
list(btl_action:type()),
@@ -54,8 +45,45 @@ main_character_is_alive (Update) ->
-> btl_character_turn_update:type().
handle_actions ([], Update) -> Update;
handle_actions ([BattleAction|FutureBattleActions], Update) ->
- {MainCharacterIsAlive, S0Update} = main_character_is_alive(Update),
-
+ case btl_action:get_actor_index(BattleAction) of
+ -1 -> handle_actions(FutureBattleActions, S0Update);
+ CharacterIX ->
+ S0Battle = btl_character_turn_update:get_battle(S0Update),
+ {Character, S1Battle} =
+ btl_battle:get_resolved_character(CharacterIX, S0Battle),
+
+ S1Update = btl_character_turn_update:set_battle(S1Battle, S0Update),
+
+ case btl_character:is_alive(Character) of
+ false -> handle_actions(FutureBattleActions, S1Update);
+ true ->
+ ActionResult =
+ case btl_action:get_category(BattleAction) of
+ move ->
+ btl_event_move:handle
+ (
+ BattleAction,
+ Character,
+ S1Update
+ );
+
+ attack ->
+ case
+ btl_event_attack:handle
+ (
+ BattleAction,
+ Character,
+ S1Update
+ );
+
+ attack_of_opportunity ->
+ btl_event_attack_of_opportunity:handle
+ (
+ BattleAction,
+ Character,
+ S1Update
+ );
+ end.
ActionResult =
case {MainCharacterIsAlive, btl_action:get_category(BattleAction)} of
{false, _} -> {ok, S0Update};
diff --git a/src/battle/reply/btl_add_char.erl b/src/battle/reply/btl_add_char.erl
index d2fe255..556975c 100644
--- a/src/battle/reply/btl_add_char.erl
+++ b/src/battle/reply/btl_add_char.erl
@@ -26,7 +26,7 @@ rank_to_string (Rank) ->
-spec generate
(
non_neg_integer(),
- btl_character:type(),
+ btl_character:either(),
non_neg_integer()
)
-> {list(any())}.
diff --git a/src/battle/struct/btl_action.erl b/src/battle/struct/btl_action.erl
index 52f41d8..174a063 100644
--- a/src/battle/struct/btl_action.erl
+++ b/src/battle/struct/btl_action.erl
@@ -7,15 +7,8 @@
(
move,
{
+ actor_ix :: non_neg_integer(),
path :: list(shr_direction:enum())
- }
-).
-
--record
-(
- interrupted_move,
- {
- path :: list(shr_direction:enum()),
movement_points :: non_neg_integer()
}
).
@@ -24,6 +17,7 @@
(
switch_weapon,
{
+ actor_ix :: non_neg_integer()
}
).
@@ -31,35 +25,25 @@
(
attack,
{
- target_ix :: non_neg_integer()
- }
-).
-
--record
-(
- defend,
- {
- target_ix :: non_neg_integer()
+ actor_ix :: non_neg_integer(),
+ target_ix :: non_neg_integer(),
+ is_opportunistic :: boolean()
}
).
-
-type category() ::
(
'move'
- | 'interrupted_move'
| 'switch_weapon'
| 'attack'
- | 'defend'
| 'nothing'
).
-opaque type() ::
(
#move{}
- | #interrupted_move{}
| #switch_weapon{}
| #attack{}
- | #defend{}
+ | #attack_of_opportunity{}
).
-export_type([category/0, type/0]).
@@ -71,9 +55,9 @@
(
[
from_map_marker/2,
- maybe_decode_move/1,
- maybe_decode_weapon_switch/1,
- maybe_decode_attack/1,
+ maybe_decode_move/2,
+ maybe_decode_weapon_switch/2,
+ maybe_decode_attack/2,
can_follow/2
]
).
@@ -90,7 +74,8 @@
[
get_path/1,
get_movement_points/1,
- get_target_ix/1,
+ get_target_index/1,
+ get_actor_index/1,
get_category/1
]
).
@@ -102,20 +87,37 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec maybe_decode_move (list(shr_direction:type())) -> list(type()).
-maybe_decode_move ([]) -> [];
-maybe_decode_move (PathInBinary) ->
+-spec maybe_decode_move
+ (
+ non_neg_integer(),
+ list(shr_direction:type())
+ )
+ -> list(type()).
+maybe_decode_move (_CharacterIX, []) -> [];
+maybe_decode_move (CharacterIX, PathInBinary) ->
Path = lists:map(fun shr_direction:decode/1, PathInBinary),
- [#move{ path = Path }].
+ [#move{ actor_ix = CharacterIX, path = Path }].
--spec maybe_decode_attack (integer()) -> list(type()).
-maybe_decode_attack (TargetIX) when (TargetIX < 0) -> [];
-maybe_decode_attack (TargetIX) -> [#attack{ target_ix = TargetIX }].
+-spec maybe_decode_attack
+ (
+ non_neg_integer(),
+ integer()
+ )
+ -> list(type()).
+maybe_decode_attack (_CharacterIX, TargetIX) when (TargetIX < 0) -> [];
+maybe_decode_attack (CharacterIX, TargetIX) ->
+ [#attack{ actor_ix = CharacterIX, target_ix = TargetIX }].
--spec maybe_decode_weapon_switch (boolean()) -> list(type()).
-maybe_decode_weapon_switch (false) -> [];
-maybe_decode_weapon_switch (true) -> [#switch_weapon{}].
+-spec maybe_decode_weapon_switch
+ (
+ non_neg_integer(),
+ boolean()
+ )
+ -> list(type()).
+maybe_decode_weapon_switch (_CharacterIX, false) -> [];
+maybe_decode_weapon_switch (CharacterIX, true) ->
+ [#switch_weapon{ actor_ix = CharacterIX }].
-spec can_follow (category(), category()) -> boolean().
can_follow (nothing, attack) -> true;
@@ -138,14 +140,26 @@ get_movement_points (Action) when is_record(Action, interrupted_move) ->
Action#interrupted_move.movement_points;
get_movement_points (_) -> 0.
--spec get_target_ix (type()) -> non_neg_integer().
-get_target_ix (Action) when is_record(Action, attack) ->
+-spec get_target_index (type()) -> non_neg_integer().
+get_target_index (Action) when is_record(Action, attack) ->
Action#attack.target_ix;
-get_target_ix (Action) when is_record(Action, defend) ->
- Action#defend.target_ix;
-get_target_ix (_) ->
+get_target_index (Action) when is_record(Action, attack_of_opportunity) ->
+ Action#attack_of_opportunity.target_ix;
+get_target_index (_) ->
0.
+-spec get_actor_index (type()) -> (non_neg_integer() | -1).
+get_actor_index (Action) when is_record(Action, attack) ->
+ Action#attack.actor_ix;
+get_actor_index (Action) when is_record(Action, attack_of_opportunity) ->
+ Action#attack_of_opportunity.actor_ix;
+get_actor_index (Action) when is_record(Action, move) ->
+ Action#move.actor_ix;
+get_actor_index (Action) when is_record(Action, switch_weapon) ->
+ Action#switch_weapon.actor_ix;
+get_actor_index (_) ->
+ -1.
+
-spec new_interrupted_move
(
list(shr_direction:type()),
@@ -161,8 +175,8 @@ get_category (Action) when is_record(Action, move) -> move;
get_category (Action) when is_record(Action, switch_weapon) -> switch_weapon;
get_category (Action) when is_record(Action, interrupted_move) ->
interrupted_move;
-get_category (Action) when is_record(Action, defend) ->
- defend.
+get_category (Action) when is_record(Action, attack_of_opportunity) ->
+ attack_of_opportunity.
-spec from_map_marker
(
@@ -174,7 +188,7 @@ from_map_marker (_Character, Marker) ->
case shr_map_marker:get_category(Marker) of
matk ->
[
- #defend
+ #attack_of_opportunity
{
target_ix = shr_map_marker:get_character_index(Marker)
}
diff --git a/src/battle/struct/btl_attack.erl b/src/battle/struct/btl_attack.erl
index 6d7f32e..baaa5a7 100644
--- a/src/battle/struct/btl_attack.erl
+++ b/src/battle/struct/btl_attack.erl
@@ -5,7 +5,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--type order() :: ('first' | 'second' | 'counter' | 'opportunity').
+-type order() :: ('first' | 'second' | 'counter').
-type precision() :: ('misses' | 'grazes' | 'hits').
-record
@@ -411,26 +411,8 @@ get_description_of
CanParry,
DefenderLuck,
AttackerLuck
- );
-get_description_of
-(
- opportunity,
- Attacker,
- Defender,
- AttackerLuck,
- DefenderLuck
-) ->
- effect_of_attack
- (
- opportunity,
- Attacker,
- Defender,
- false,
- AttackerLuck,
- DefenderLuck
).
-
-spec apply_to_healths_and_lucks
(
maybe_type(),
@@ -573,8 +555,12 @@ get_sequence (AttackRange, AttackerWeapon, DefenderWeapon) ->
_ -> [First, Second]
end.
--spec attack_of_opportunity () -> opportunity.
-attack_of_opportunity () -> opportunity.
+-spec attack_of_opportunity () -> list(step()).
+attack_of_opportunity () ->
+ [
+ {first, false},
+ {second, false}
+ ].
-spec encode (type()) -> {list(any())}.
encode (Attack) ->
diff --git a/src/battle/struct/btl_battle.erl b/src/battle/struct/btl_battle.erl
index c1f4d68..435a99b 100644
--- a/src/battle/struct/btl_battle.erl
+++ b/src/battle/struct/btl_battle.erl
@@ -12,8 +12,7 @@
related_inventory :: shr_inventory:type(),
related_tile_ids :: ordsets:ordset(shr_tile:id()),
map :: shr_map:type(),
- characters ::
- orddict:orddict(non_neg_integer(), btl_character:unresolved()),
+ characters :: orddict:orddict(non_neg_integer(), btl_character:either()),
players :: orddict:orddict(non_neg_integer(), btl_player:type()),
current_player_turn :: btl_player_turn:type()
}
@@ -35,6 +34,7 @@
get_map/1,
get_characters/1,
get_character/2,
+ get_resolved_character/2,
get_players/1,
get_player/2,
get_current_player_turn/1,
@@ -130,12 +130,35 @@ get_map (Battle) -> Battle#battle.map.
(
type()
)
- -> orddict:orddict(non_neg_integer(), btl_character:unresolved()).
+ -> orddict:orddict(non_neg_integer(), btl_character:either()).
get_characters (Battle) -> Battle#battle.characters.
--spec get_character (non_neg_integer(), type()) -> btl_character:unresolved().
-get_character (IX, Battle) ->
- orddict:fetch(IX, Battle#battle.characters).
+-spec get_character (non_neg_integer(), type()) -> btl_character:either().
+get_character (IX, Battle) -> orddict:fetch(IX, Battle#battle.characters).
+
+-spec get_resolved_character
+ (
+ non_neg_integer(),
+ type()
+ )
+ -> {btl_character:type(), type()}.
+get_resolved_character (IX, Battle) ->
+ Character = orddict:fetch(IX, Battle#battle.characters),
+
+ case btl_character:is_unresolved(Character) of
+ true ->
+ ResolvedCharacter = resolve_character(Character, Battle),
+ {
+ ResolvedCharacter,
+ Battle#battle
+ {
+ characters =
+ orddict:set(IX, ResolvedCharacter, Battle#battle.characters)
+ }
+ };
+
+ false -> {Character, Battle}
+ end.
-spec get_players
(
@@ -207,7 +230,7 @@ ataxia_set_map (Map, MapUpdate, Battle) ->
-spec set_characters
(
- orddict:orddict(non_neg_integer(), btl_character:unresolved()),
+ orddict:orddict(non_neg_integer(), btl_character:either()),
type()
)
-> type().
@@ -219,16 +242,30 @@ set_characters (Characters, Battle) ->
-spec ataxia_set_characters
(
- orddict:orddict(non_neg_integer(), btl_character:unresolved()),
+ orddict:orddict(non_neg_integer(), btl_character:either()),
type()
)
-> {type(), ataxic:basic()}.
ataxia_set_characters (Characters, Battle) ->
- ataxia_set_characters(Characters, ataxic:constant(Characters), Battle).
+ UnresolvedCharacters =
+ orddict:map
+ (
+ fun (_Key, Character) ->
+ btl_character:to_unresolved(Character)
+ end,
+ Characters
+ ),
+
+ ataxia_set_characters
+ (
+ Characters,
+ ataxic:constant(UnresolvedCharacters),
+ Battle
+ ).
-spec ataxia_set_characters
(
- orddict:orddict(non_neg_integer(), btl_character:unresolved()),
+ orddict:orddict(non_neg_integer(), btl_character:either()),
ataxic:basic(),
type()
)
@@ -246,7 +283,7 @@ ataxia_set_characters (Characters, CharactersUpdate, Battle) ->
-spec set_character
(
non_neg_integer(),
- btl_character:unresolved(),
+ btl_character:either(),
type()
)
-> type().
@@ -258,7 +295,7 @@ set_character (IX, Character, Battle) ->
-spec add_character
(
- btl_character:unresolved(),
+ btl_character:either(),
type()
)
-> {non_neg_integer(), type()}.
@@ -268,7 +305,7 @@ add_character (Character, Battle) ->
-spec ataxia_add_character
(
- btl_character:unresolved(),
+ btl_character:either(),
type()
)
-> {non_neg_integer(), type(), ataxic:basic()}.
@@ -280,17 +317,23 @@ ataxia_add_character (Character, Battle) ->
-spec ataxia_set_character
(
non_neg_integer(),
- btl_character:unresolved(),
+ btl_character:either(),
type()
)
-> {type(), ataxic:basic()}.
ataxia_set_character (IX, Character, Battle) ->
- ataxia_set_character(IX, Character, ataxic:constant(Character), Battle).
+ ataxia_set_character
+ (
+ IX,
+ Character,
+ ataxic:constant(btl_character:to_unresolved(Character)),
+ Battle
+ ).
-spec ataxia_set_character
(
non_neg_integer(),
- btl_character:unresolved(),
+ btl_character:either(),
ataxic:basic(),
type()
)
@@ -477,29 +520,34 @@ new (Map) ->
-spec resolve_character
(
- btl_character:unresolved(),
+ btl_character:either(),
type()
)
-> btl_character:type().
-resolve_character (CharacterRef, Battle) ->
- btl_character:resolve
- (
- shr_tile:get_omnimods
- (
- shr_tile:from_id
+resolve_character (Character, Battle) ->
+ case btl_character:is_unresolved(Character) of
+ true ->
+ btl_character:resolve
(
- shr_tile_instance:get_tile_id
+ shr_tile:get_omnimods
(
- shr_map:get_tile_instance
+ shr_tile:from_id
(
- btl_character:get_location(CharacterRef),
- Battle#battle.map
+ shr_tile_instance:get_tile_id
+ (
+ shr_map:get_tile_instance
+ (
+ btl_character:get_location(Character),
+ Battle#battle.map
+ )
+ )
)
- )
- )
- ),
- CharacterRef
- ).
+ ),
+ Character
+ );
+
+ false -> Character
+ end.
-spec get_characters_field () -> non_neg_integer().
get_characters_field () -> #battle.characters.
diff --git a/src/battle/struct/btl_character.erl b/src/battle/struct/btl_character.erl
index cca53b3..790c809 100644
--- a/src/battle/struct/btl_character.erl
+++ b/src/battle/struct/btl_character.erl
@@ -92,6 +92,7 @@
[
new/4,
resolve/2,
+ is_unresolved/1,
to_unresolved/1,
decode/1,
encode/1
@@ -149,7 +150,7 @@ get_location (#btl_char_ref{ location = R }) -> R.
get_current_health (#btl_char{ current_health = R }) -> R;
get_current_health (#btl_char_ref{ current_health = R }) -> R.
--spec get_is_alive (type()) -> boolean().
+-spec get_is_alive (either()) -> boolean().
get_is_alive (#btl_char{ current_health = H, is_defeated = D }) ->
((not D) and (H > 0));
get_is_alive (#btl_char_ref{ current_health = H, is_defeated = D }) ->
@@ -439,8 +440,8 @@ new
base = Base
}.
--spec resolve (shr_omnimods:type(), unresolved()) -> type().
-resolve (LocalOmnimods, CharRef) ->
+-spec resolve (shr_omnimods:type(), either()) -> type().
+resolve (LocalOmnimods, CharRef) when is_record(CharRef, btl_char_ref) ->
#btl_char
{
player_ix = CharRef#btl_char_ref.player_ix,
@@ -450,10 +451,11 @@ resolve (LocalOmnimods, CharRef) ->
is_active = CharRef#btl_char_ref.is_active,
is_defeated = CharRef#btl_char_ref.is_defeated,
base = shr_character:resolve(LocalOmnimods, CharRef#btl_char_ref.base)
- }.
+ };
+resolve (_LocalOmnimods, Char) when is_record(Char, btl_char) -> Char.
--spec to_unresolved (type()) -> unresolved().
-to_unresolved (Char) ->
+-spec to_unresolved (either()) -> unresolved().
+to_unresolved (Char) when is_record(Char, btl_char) ->
#btl_char_ref
{
player_ix = Char#btl_char.player_ix,
@@ -463,7 +465,11 @@ to_unresolved (Char) ->
is_active = Char#btl_char.is_active,
is_defeated = Char#btl_char.is_defeated,
base = shr_character:to_unresolved(Char#btl_char.base)
- }.
+ };
+to_unresolved (CharRef) when is_record(CharRef, btl_char_ref) -> CharRef.
+
+-spec is_unresolved (either()) -> boolean().
+is_unresolved (Char) -> is_record(Char, btl_char_ref).
-spec get_rank_field() -> non_neg_integer().
get_rank_field () -> #btl_char_ref.rank.
diff --git a/src/battle/struct/btl_character_turn_request.erl b/src/battle/struct/btl_character_turn_request.erl
index 7246ca7..7d53bcd 100644
--- a/src/battle/struct/btl_character_turn_request.erl
+++ b/src/battle/struct/btl_character_turn_request.erl
@@ -52,12 +52,16 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec decode_actions (map()) -> list(btl_action:type()).
-decode_actions (Act) ->
+-spec decode_actions (non_neg_integer(), map()) -> list(btl_action:type()).
+decode_actions (CharacterIX, Act) ->
S0Result = [],
S1Result =
case
- btl_action:maybe_decode_move(maps:get(?ACTIONS_MOVE_FIELD, Act))
+ btl_action:maybe_decode_move
+ (
+ CharacterIX,
+ maps:get(?ACTIONS_MOVE_FIELD, Act)
+ )
of
[] -> S0Result;
[Move] -> [Move|S0Result]
@@ -67,6 +71,7 @@ decode_actions (Act) ->
case
btl_action:maybe_decode_attack
(
+ CharacterIX,
maps:get(?ACTIONS_ATTACK_FIELD, Act)
)
of
@@ -78,6 +83,7 @@ decode_actions (Act) ->
case
btl_action:maybe_decode_weapon_switch
(
+ CharacterIX,
maps:get(?ACTIONS_WEAPON_SWITCH_FIELD, Act)
)
of
@@ -94,7 +100,7 @@ decode_actions (Act) ->
decode (Map) ->
CharacterIX = maps:get(?CHAR_IX_FIELD, Map),
EncodedActions = maps:get(?ACTIONS_FIELD, Map),
- Actions = decode_actions(EncodedActions),
+ Actions = decode_actions(CharacterIX, EncodedActions),
#type
{
diff --git a/src/battle/struct/btl_character_turn_update.erl b/src/battle/struct/btl_character_turn_update.erl
index 9f2c30a..f5f2d05 100644
--- a/src/battle/struct/btl_character_turn_update.erl
+++ b/src/battle/struct/btl_character_turn_update.erl
@@ -7,17 +7,9 @@
(
type,
{
- battle_is_outdated :: boolean(),
- character_is_outdated :: boolean(),
-
battle :: btl_battle:type(),
- reversed_battle_updates :: list(ataxic:basic()),
-
- character :: btl_character:type(),
- reversed_character_updates :: list(ataxic:basic()),
-
character_ix :: non_neg_integer(),
-
+ reversed_battle_updates :: list(ataxic:basic()),
timeline :: list(any())
}
).
@@ -35,14 +27,12 @@
new/2,
get_battle/1,
- get_character/1,
get_character_ix/1,
get_battle_update/1,
get_timeline/1,
set_battle/3,
- set_character/2,
ataxia_set_battle/4,
ataxia_set_character/3,
diff --git a/src/shared/struct/shr_character.erl b/src/shared/struct/shr_character.erl
index 68e6cb6..87a9be8 100644
--- a/src/shared/struct/shr_character.erl
+++ b/src/shared/struct/shr_character.erl
@@ -397,14 +397,15 @@ resolve (LocalOmnimods, CharRef) ->
extra_omnimods = LocalOmnimods
}.
--spec to_unresolved (type()) -> unresolved().
-to_unresolved (Char) ->
+-spec to_unresolved (either()) -> unresolved().
+to_unresolved (Char) when is_record(Char, shr_char)->
#shr_char_ref
{
name = Char#shr_char.name,
equipment = shr_equipment:to_unresolved(Char#shr_char.equipment),
is_using_secondary = Char#shr_char.is_using_secondary
- }.
+ };
+to_unresolved (CharRef) when is_record(CharRef, shr_char_ref) -> CharRef.
-spec decode (map()) -> unresolved().
decode (Map) ->