summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/battle/mechanic/action/btl_action_attack.erl655
-rw-r--r--src/battle/mechanic/action/btl_action_move.erl (renamed from src/battle/mechanic/turn_action/btl_turn_actions_move.erl)93
-rw-r--r--src/battle/mechanic/action/btl_action_switch_weapon.erl (renamed from src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl)25
-rw-r--r--src/battle/mechanic/action/btl_turn_actions_opportunity_attack.erl (renamed from src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl)0
-rw-r--r--src/battle/mechanic/btl_attack.erl109
-rw-r--r--src/battle/mechanic/btl_turn_actions_management.erl82
-rw-r--r--src/battle/mechanic/turn_action/btl_turn_actions_attack.erl339
-rw-r--r--src/battle/struct/btl_action.erl85
8 files changed, 809 insertions, 579 deletions
diff --git a/src/battle/mechanic/action/btl_action_attack.erl b/src/battle/mechanic/action/btl_action_attack.erl
new file mode 100644
index 0000000..1241735
--- /dev/null
+++ b/src/battle/mechanic/action/btl_action_attack.erl
@@ -0,0 +1,655 @@
+-module(btl_turn_actions_attack).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-export
+(
+ [
+ handle/3
+ ]
+).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec roll_precision_modifier
+ (
+ shr_statistics:type(),
+ shr_statistics:type(),
+ integer()
+ )
+ -> {float(), integer(), integer()}.
+roll_precision_modifier (Statistics, TargetStatistics, TargetLuck) ->
+ TargetDodges = shr_statistics:get_dodges(TargetStatistics),
+ Accuracy = shr_statistics:get_accuracy(Statistics),
+ MissChance = max(0, (TargetDodges - Accuracy)),
+
+ {Roll, _IsSuccess, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(MissChance, TargetLuck),
+
+ {
+ case Roll of
+ X when (X =< MissChance) -> 0.0;
+ X when (X =< (MissChance * 2)) -> 0.5;
+ _ -> 1.0
+ end,
+ PositiveModifier,
+ NegativeModifier
+ }.
+
+-spec roll_critical_hit_modifier
+ (
+ shr_statistics:type(),
+ integer()
+ )
+ -> {boolean(), integer(), integer()}.
+roll_critical_hit_modifier (Statistics, Luck) ->
+ CriticalHitChance = shr_statistics:get_critical_hits(Statistics),
+ {_Roll, IsSuccess, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(CriticalHitChance, Luck),
+
+ {
+ case IsSuccess of
+ true -> 2.0; % [TODO][FUTURE]: variable critical multiplier?
+ false -> 1.0
+ end,
+ 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 get_character_abilities
+ (
+ btl_action:type(),
+ btl_character:type(),
+ btl_character:type()
+ )
+ -> {boolean(), boolean(), boolean()}.
+get_character_abilities (Action, Character, TargetCharacter) ->
+ CharacterWeapon =
+ shr_character:get_active_weapon
+ (
+ btl_character:get_base_character(Character)
+ ),
+
+ TargetCharacterWeapon =
+ shr_character:get_active_weapon
+ (
+ btl_character:get_base_character(TargetCharacter)
+ ),
+
+ DefenseRange = shr_weapon:get_minimum_range(CharacterWeapon),
+ AttackRange = shr_weapon:get_maximum_range(CharacterWeapon),
+ TargetDefenseRange = shr_weapon:get_minimum_range(TargetCharacterWeapon),
+ TargetAttackRange = shr_weapon:get_maximum_range(TargetCharacterWeapon),
+
+ IsNotOpportunistic = btl_action:get_is_opportunistic(Action),
+
+ AttackRange =
+ shr_location:dist
+ (
+ btl_character:get_location(Character),
+ btl_character:get_location(TargetCharacter)
+ ),
+
+ {
+ (DefenseRange == 0),
+ (
+ IsNotOpportunistic
+ and (TargetDefenseRange == 0)
+ and (TargetAttackRange =< AttackRange)
+ ),
+ (
+ IsNotOpportunistic
+ and (TargetAttackRange =< AttackRange)
+ )
+ }.
+
+-spec effect_of_attack
+ (
+ btl_attack:category(),
+ non_neg_integer(),
+ non_neg_integer(),
+ btl_character:type(),
+ btl_character:type(),
+ integer(),
+ integer(),
+ boolean(),
+ btl_character_turn_update:type()
+ )
+ ->
+ {
+ btl_character:type(),
+ btl_character:type(),
+ integer(),
+ integer(),
+ btl_character_turn_update:type(),
+ btl_attack:type()
+ }.
+effect_of_attack
+(
+ Category,
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S0Luck,
+ S0TargetLuck,
+ TargetCanParry,
+ S0Update
+) ->
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%% Roll parry to see if the roles have to be swapped. %%%%%%%%%%%%%%%%%%%%%
+
+ {ParryIsSuccessful, ParryPositiveLuckMod, ParryNegativeLuckMod} =
+ case TargetCanParry of
+ true ->
+ TargetStatistics =
+ shr_character:get_statistics
+ (
+ btl_character:get_base_character(TargetCharacter)
+ ),
+ roll_parry(TargetStatistics, S0TargetLuck);
+
+ false -> {false, 0, 0}
+ end,
+
+ { AttackerIX, DefenderIX, Attacker, Defender, AttackerLuck, DefenderLuck } =
+ case ParryIsSuccessful of
+ true ->
+ {
+ TargetCharacterIX,
+ CharacterIX,
+ TargetCharacter,
+ Character,
+ TargetLuck,
+ Luck
+ };
+
+ false ->
+ {
+ CharacterIX,
+ TargetCharacterIX,
+ Character,
+ TargetCharacter,
+ Luck,
+ TargetLuck
+ }
+ end,
+
+ AttackerStatistics =
+
+-spec handle_attack_sequence
+ (
+ list({btl_attack:category(), boolean()}),
+ non_neg_integer(),
+ non_neg_integer(),
+ btl_character:type(),
+ btl_character:type(),
+ integer(),
+ integer(),
+ list(btl_attack:type()),
+ btl_character_turn_update:type()
+ )
+ ->
+ {
+ btl_character:type(),
+ btl_character:type(),
+ integer(),
+ integer(),
+ list(btl_attack:type()),
+ btl_character_turn_update:type()
+ }.
+handle_attack_sequence
+(
+ [],
+ _CharacterIX,
+ _TargetCharacterIX,
+ Character,
+ TargetCharacter,
+ PlayerLuck,
+ TargetPlayerLuck,
+ Results,
+ Update
+)
+->
+ {
+ Character,
+ TargetCharacter,
+ PlayerLuck,
+ TargetPlayerLuck,
+ lists:reverse(Results),
+ Update
+ };
+handle_attack_sequence
+(
+ [{first, TargetCanParry}|NextAttacks],
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S0PlayerLuck,
+ S0TargetPlayerLuck,
+ Results,
+ S0Update
+)
+->
+ {
+ S1Character,
+ S1TargetCharacter,
+ S1PlayerLuck,
+ S1TargetPlayerLuck,
+ S1Update,
+ Result
+ } =
+ effect_of_attack
+ (
+ first,
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S0PlayerLuck,
+ S0TargetPlayerLuck,
+ TargetCanParry,
+ S0Update
+ ),
+
+ handle_attack_sequence
+ (
+ NextAttacks,
+ CharacterIX,
+ TargetCharacterIX,
+ S1Character,
+ S1TargetCharacter,
+ S1PlayerLuck,
+ S1TargetPlayerLuck,
+ [Result|Results],
+ S1Update
+ );
+handle_attack_sequence
+(
+ [{counter, CanParry}|NextAttacks],
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S0PlayerLuck,
+ S0TargetPlayerLuck,
+ Results,
+ S0Update
+)
+->
+ {
+ S1TargetCharacter,
+ S1Character,
+ S2TargetPlayerLuck,
+ S2PlayerLuck,
+ S1Update,
+ Result
+ } =
+ effect_of_attack
+ (
+ counter,
+ TargetCharacterIX,
+ CharacterIX,
+ S0TargetCharacter,
+ S0Character,
+ S1TargetPlayerLuck,
+ S1PlayerLuck,
+ CanParry,
+ S0Update
+ ),
+
+ handle_attack_sequence
+ (
+ NextAttacks,
+ CharacterIX,
+ TargetCharacterIX,
+ S1Character,
+ S1TargetCharacter,
+ S2PlayerLuck,
+ S2TargetPlayerLuck,
+ [Result|Results],
+ S1Update
+ );
+handle_attack_sequence
+(
+ [{second, TargetCanParry}|NextAttacks],
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S0PlayerLuck,
+ S0TargetPlayerLuck,
+ Results,
+ S0Update
+)
+->
+ Statistics = shr_character:get_statistics(S0Character),
+ DoubleAttackChance = shr_statistics:get_double_hits(Statistics),
+ {_Roll, IsSuccessful, PositiveModifier, NegativeModifier} =
+ shr_roll:percentage_with_luck(DoubleAttackChance, S0PlayerLuck),
+
+ S1PlayerLuck = (S0PlayerLuck + PositiveModifier),
+ S1TargetPlayerLuck = (S0TargetPlayerLuck + NegativeModifier),
+
+ case IsSuccessful of
+ false ->
+ handle_attack_sequence
+ (
+ NextAttacks,
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S1PlayerLuck,
+ S1TargetPlayerLuck,
+ Results,
+ S0Update
+ );
+
+ true ->
+ {
+ S1Character,
+ S1TargetCharacter,
+ S2PlayerLuck,
+ S2TargetPlayerLuck,
+ S1Update,
+ Result
+ } =
+ effect_of_attack
+ (
+ second,
+ CharacterIX,
+ TargetCharacterIX,
+ S0Character,
+ S0TargetCharacter,
+ S1PlayerLuck,
+ S1TargetPlayerLuck,
+ TargetCanParry,
+ S0Update
+ ),
+
+ handle_attack_sequence
+ (
+ CharacterIX,
+ TargetCharacterIX,
+ NextAttacks,
+ S1Character,
+ S1TargetCharacter,
+ S2PlayerLuck,
+ S2TargetPlayerLuck,
+ [Result|Results],
+ S1Update
+ )
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec handle
+ (
+ btl_action:type(),
+ btl_character:type(),
+ btl_character_turn_update:type()
+ )
+ -> {ok, btl_character_turn_update:type()}.
+handle (Action, S0Character, S0Update) ->
+ S0Battle = btl_character_turn_update:get_battle(S0Update),
+ CharacterIX = btl_action:get_actor_index(Action),
+
+ PlayerIX = btl_character:get_player_index(S0Character),
+ Player = btl_battle:get_player(PlayerIX, S0Battle),
+ S0PlayerLuck = btl_player:get_luck(Player),
+
+ TargetCharacterIX = btl_action:get_target_index(Action),
+ {S0TargetCharacter, S1Battle} =
+ btl_battle:get_resolved_character(TargetCharacterIX, S0Battle),
+
+ TargetPlayerIX = btl_character:get_player_index(TargetCharacter),
+ TargetPlayer = btl_battle:get_player(TargetPlayerIX, S1Battle),
+ TargetPlayerLuck = btl_player:get_luck(TargetPlayer),
+
+ {CanParry, TargetCanParry, TargetCanCounter} =
+ get_character_abilities(Action, S0Character, S0TargetCharacter),
+
+ {
+ S1Character,
+ S1TargetCharacter,
+ S1PlayerLuck,
+ S1TargetPlayerLuck,
+ Results,
+ S1Update
+ } =
+ handle_attack_sequence
+ (
+ case TargetCanCounter of
+ true ->
+ [
+ {first, TargetCanParry},
+ {counter, CanParry},
+ {second, TargetCanParry}
+ ];
+
+ false ->
+ [
+ {first, TargetCanParry},
+ {second, TargetCanParry}
+ ]
+ end,
+ S1Character,
+ S1TargetCharacter,
+ S1PlayerLuck,
+ S1TargetPlayerLuck,
+ Results,
+ S1Update
+ ),
+
+ {
+ AttackEffects,
+ RemainingAttackerHealth,
+ RemainingDefenderHealth,
+ NewAttackerLuck,
+ NewDefenderLuck
+ } =
+ handle_attack_sequence
+ (
+ Character,
+ btl_character:get_current_health(Character),
+ TargetCharacter,
+ btl_character:get_current_health(TargetCharacter),
+ PlayerLuck,
+ TargetPlayerLuck,
+ AttackSequence,
+ []
+ ),
+
+ S0NewAttackerLuck =
+ case {(NewAttackerLuck =< -2), (NewAttackerLuck >= 2)} of
+ {true, _} -> (NewAttackerLuck + 2);
+ {_, true} -> (NewAttackerLuck - 2);
+ _ -> 0
+ end,
+
+ S0NewDefenderLuck =
+ case {(NewDefenderLuck =< -2), (NewDefenderLuck >= 2)} of
+ {true, _} -> (NewDefenderLuck + 2);
+ {_, true} -> (NewDefenderLuck - 2);
+ _ -> 0
+ end,
+
+ {UpdatedAttackingPlayer, AttackingPlayerAtaxiaUpdate} =
+ btl_player:ataxia_set_luck(S0NewAttackerLuck, AttackingPlayer),
+
+ {UpdatedDefendingPlayer, DefendingPlayerAtaxiaUpdate} =
+ btl_player:ataxia_set_luck(S0NewDefenderLuck, DefendingPlayer),
+
+ {UpdatedCharacter, CharacterAtaxiaUpdate} =
+ btl_character:ataxia_set_current_health
+ (
+ RemainingAttackerHealth,
+ Character
+ ),
+
+ {UpdatedTargetCharacterRef, TargetCharacterRefAtaxiaUpdate} =
+ btl_character:ataxia_set_current_health
+ (
+ RemainingDefenderHealth,
+ TargetCharacterRef
+ ),
+
+ {S0Battle, BattleAtaxiaUpdate0} =
+ btl_battle:ataxia_set_player
+ (
+ AttackingPlayerIX,
+ UpdatedAttackingPlayer,
+ AttackingPlayerAtaxiaUpdate,
+ Battle
+ ),
+
+ {S1Battle, BattleAtaxiaUpdate1} =
+ btl_battle:ataxia_set_player
+ (
+ DefendingPlayerIX,
+ UpdatedDefendingPlayer,
+ DefendingPlayerAtaxiaUpdate,
+ S0Battle
+ ),
+
+ {S2Battle, BattleAtaxiaUpdate2} =
+ btl_battle:ataxia_set_character
+ (
+ TargetIX,
+ UpdatedTargetCharacterRef,
+ TargetCharacterRefAtaxiaUpdate,
+ S1Battle
+ ),
+
+ % Potential danger ahead: we're going to update both the 'character' and
+ % 'battle' members of a btl_character_turn_update.
+ % 'S1Update' is sure to have both up to date (as it's the result of 'get'
+ % requests for both) and there is no risk of the 'battle' update influencing
+ % 'character', making what follows safe.
+
+ S2Update =
+ btl_character_turn_update:ataxia_set_battle
+ (
+ S2Battle,
+ false,
+ ataxic:optimize
+ (
+ ataxic:sequence
+ (
+ [
+ BattleAtaxiaUpdate0,
+ BattleAtaxiaUpdate1,
+ BattleAtaxiaUpdate2
+ ]
+ )
+ ),
+ S1Update
+ ),
+
+ S3Update =
+ btl_character_turn_update:ataxia_set_character
+ (
+ UpdatedCharacter,
+ CharacterAtaxiaUpdate,
+ S2Update
+ ),
+
+ TimelineItem =
+ btl_turn_result:new_character_attacked
+ (
+ btl_character_turn_update:get_character_ix(S3Update),
+ TargetIX,
+ AttackEffects,
+ S0NewAttackerLuck,
+ S0NewDefenderLuck
+ ),
+
+ S4Update = btl_character_turn_update:add_to_timeline(TimelineItem, S3Update),
+
+ S5Update =
+ case (RemainingAttackerHealth > 0) of
+ true -> S4Update;
+ false ->
+ btl_victory_progression:handle_character_loss(Character, S4Update)
+ end,
+
+ S6Update =
+ case (RemainingDefenderHealth > 0) of
+ true -> S5Update;
+ false ->
+ btl_victory_progression:handle_character_loss
+ (
+ TargetCharacterRef,
+ S5Update
+ )
+ end,
+
+ {ok, S6Update}.
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_move.erl b/src/battle/mechanic/action/btl_action_move.erl
index 70b42c9..a32a40f 100644
--- a/src/battle/mechanic/turn_action/btl_turn_actions_move.erl
+++ b/src/battle/mechanic/action/btl_action_move.erl
@@ -1,4 +1,4 @@
--module(btl_turn_actions_move).
+-module(btl_action_move).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -9,7 +9,7 @@
-export
(
[
- handle/2
+ handle/3
]
).
@@ -107,6 +107,8 @@ cross (PlayerIX, Map, ForbiddenLocations, Path, Location) ->
-spec get_path_cost_and_destination
(
+ non_neg_integer(),
+ btl_character:type(),
btl_character_turn_update:type(),
list(shr_direction:type())
)
@@ -115,16 +117,14 @@ cross (PlayerIX, Map, ForbiddenLocations, Path, Location) ->
non_neg_integer(),
shr_location:type(),
list(shr_direction:type()),
- list(shr_map_marker:type()),
- btl_character_turn_update:type()
+ list(shr_map_marker:type())
}.
-get_path_cost_and_destination (Update, Path) ->
- {S0Update, Character} = btl_character_turn_update:get_character(Update),
- {S1Update, Battle} = btl_character_turn_update:get_battle(S0Update),
- CharacterIX = btl_character_turn_update:get_character_ix(S1Update),
+get_path_cost_and_destination (CharacterIX, Character, Update, Path) ->
+ Battle = btl_character_turn_update:get_battle(Update),
Map = btl_battle:get_map(Battle),
- % FIXME: This is recalculated at every move action, despite there be no need
+ % [TODO][OPTIMIZATION] Redundant calculations.
+ % This is recalculated at every move action, despite there be no need
% to: The client will not allow the character to go somewhere that would
% only be freed because of an event.
ForbiddenLocations =
@@ -153,7 +153,7 @@ get_path_cost_and_destination (Update, Path) ->
btl_character:get_location(Character)
),
- {Cost, NewLocation, RemainingPath, Interruptions, S1Update}.
+ {Cost, NewLocation, RemainingPath, Interruptions}.
-spec get_movement_points
(
@@ -161,30 +161,34 @@ get_path_cost_and_destination (Update, Path) ->
btl_character:type()
)
-> non_neg_integer().
-get_movement_points (Action, Char) ->
- case btl_action:get_category(Action) of
- interrupted_move -> btl_action:get_movement_points(Action);
- _ ->
+get_movement_points (Action, Character) ->
+ case btl_action:get_movement_points(Action) of
+ -1 ->
shr_statistics:get_movement_points
(
shr_character:get_statistics
(
- btl_character:get_base_character(Char)
+ btl_character:get_base_character(Character)
)
- )
+ );
+
+ Other -> Other
end.
-spec commit_move
(
+ non_neg_integer(),
btl_character:type(),
btl_character_turn_update:type(),
list(shr_direction:type()),
shr_location:type()
)
-> btl_character_turn_update:type().
-commit_move (Character, Update, Path, NewLocation) ->
- {S0Update, Battle} = btl_character_turn_update:get_battle(Update),
- Map = btl_battle:get_map(Battle),
+commit_move (CharacterIX, Character, S0Update, Path, NewLocation) ->
+ S0Battle = btl_character_turn_update:get_battle(S0Update),
+
+ Map = btl_battle:get_map(S0Battle),
+
TileOmnimods =
shr_tile:get_omnimods
(
@@ -200,24 +204,27 @@ commit_move (Character, Update, Path, NewLocation) ->
{UpdatedCharacter, CharacterAtaxiaUpdate} =
btl_character:ataxia_set_location(NewLocation, TileOmnimods, Character),
- S1Update =
- btl_character_turn_update:ataxia_set_character
+ {UpdatedBattle, BattleAtaxiaUpdate} =
+ btl_battle:ataxia_set_character
(
+ CharacterIX,
UpdatedCharacter,
CharacterAtaxiaUpdate,
- S0Update
+ S0Battle
),
TimelineItem =
- btl_turn_result:new_character_moved
+ btl_turn_result:new_character_moved(CharacterIX, Path, NewLocation),
+
+ S1Update = btl_character_turn_update:add_to_timeline(TimelineItem, S0Update),
+ S2Update =
+ btl_character_turn_update:ataxia_set_battle
(
- btl_character_turn_update:get_character_ix(S1Update),
- Path,
- NewLocation
+ UpdatedBattle,
+ BattleAtaxiaUpdate,
+ S1Update
),
- S2Update = btl_character_turn_update:add_to_timeline(TimelineItem, S1Update),
-
S2Update.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -226,6 +233,7 @@ commit_move (Character, Update, Path, NewLocation) ->
-spec handle
(
btl_action:type(),
+ btl_character:type(),
btl_character_turn_update:type()
)
->
@@ -233,22 +241,21 @@ commit_move (Character, Update, Path, NewLocation) ->
{'ok', btl_character_turn_update:type()}
| {'events', list(btl_action:type()), btl_character_turn_update:type()}
).
-handle (BattleAction, Update) ->
- {S0Update, Character} = btl_character_turn_update:get_character(Update),
-
- Path = btl_action:get_path(BattleAction),
+handle (Action, Character, S0Update) ->
+ Path = btl_action:get_path(Action),
+ CharacterIX = btl_action:get_actor_index(Action),
- {PathCost, NewLocation, RemainingPath, Interruptions, S1Update} =
- get_path_cost_and_destination(S0Update, Path),
+ {PathCost, NewLocation, RemainingPath, Interruptions} =
+ get_path_cost_and_destination(CharacterIX, Character, S0Update, Path),
- MovementPoints = get_movement_points(BattleAction, Character),
+ MovementPoints = get_movement_points(Action, Character),
true = (MovementPoints >= PathCost),
- S2Update = commit_move(Character, S1Update, Path, NewLocation),
+ S1Update = commit_move(CharacterIX, Character, S0Update, Path, NewLocation),
case RemainingPath of
- [] -> {ok, S2Update};
+ [] -> {ok, S1Update};
_ ->
{events,
(
@@ -256,7 +263,12 @@ handle (BattleAction, Update) ->
(
fun (Marker, CurrentActions) ->
(
- btl_action:from_map_marker(Character, Marker)
+ btl_action:from_map_marker
+ (
+ CharacterIX,
+ Character,
+ Marker
+ )
++
CurrentActions
)
@@ -266,13 +278,14 @@ handle (BattleAction, Update) ->
)
++
[
- btl_action:new_interrupted_move
+ btl_action:new_move
(
+ CharacterIX,
RemainingPath,
(MovementPoints - PathCost)
)
]
),
- S2Update
+ S1Update
}
end.
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl b/src/battle/mechanic/action/btl_action_switch_weapon.erl
index 8e4aeab..cf1a31a 100644
--- a/src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl
+++ b/src/battle/mechanic/action/btl_action_switch_weapon.erl
@@ -9,7 +9,7 @@
-export
(
[
- handle/1
+ handle/3
]
).
@@ -22,12 +22,14 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec handle
(
+ btl_action:type(),
+ btl_character:type(),
btl_character_turn_update:type()
)
-> {'ok', btl_character_turn_update:type()}.
-handle (Update) ->
- {S0Update, Character} = btl_character_turn_update:get_character(Update),
- CharacterIX = btl_character_turn_update:get_character_ix(S0Update),
+handle (Action, Character, S0Update) ->
+ CharacterIX = btl_action:get_actor_index(Action),
+
BaseCharacter = btl_character:get_base_character(Character),
{UpdatedBaseCharacter, BaseCharacterAtaxiaUpdate} =
@@ -41,14 +43,23 @@ handle (Update) ->
Character
),
+ {UpdatedBattle, BattleAtaxiaUpdate} =
+ btl_battle:ataxia_set_character
+ (
+ CharacterIX,
+ UpdatedCharacter,
+ CharacterAtaxiaUpdate,
+ btl_character_turn_update:get_battle(S0Update)
+ ),
+
TimelineItem = btl_turn_result:new_character_switched_weapons(CharacterIX),
S1Update = btl_character_turn_update:add_to_timeline(TimelineItem, S0Update),
S2Update =
- btl_character_turn_update:ataxia_set_character
+ btl_character_turn_update:ataxia_set_battle
(
- UpdatedCharacter,
- CharacterAtaxiaUpdate,
+ UpdatedBattle,
+ BattleAtaxiaUpdate,
S1Update
),
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl b/src/battle/mechanic/action/btl_turn_actions_opportunity_attack.erl
index c1dbbdd..c1dbbdd 100644
--- a/src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl
+++ b/src/battle/mechanic/action/btl_turn_actions_opportunity_attack.erl
diff --git a/src/battle/mechanic/btl_attack.erl b/src/battle/mechanic/btl_attack.erl
index cbc1baa..8a10cc6 100644
--- a/src/battle/mechanic/btl_attack.erl
+++ b/src/battle/mechanic/btl_attack.erl
@@ -16,109 +16,6 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 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(),
@@ -512,11 +409,7 @@ get_sequence (AttackRange, AttackerWeapon, DefenderWeapon) ->
-spec standard
(
- non_neg_integer(),
- btl_character:type(),
- btl_player:type(),
- btl_character:type()
- btl_player:type()
+
)
->
{
diff --git a/src/battle/mechanic/btl_turn_actions_management.erl b/src/battle/mechanic/btl_turn_actions_management.erl
index 0981ab4..7ee173a 100644
--- a/src/battle/mechanic/btl_turn_actions_management.erl
+++ b/src/battle/mechanic/btl_turn_actions_management.erl
@@ -37,6 +37,25 @@ deactivate_character (Update) ->
S1Update.
+-spec perform_action
+ (
+ btl_action:type(),
+ btl_character:type(),
+ btl_character_turn_update:type()
+ )
+ ->
+ (
+ {ok, btl_character_turn_update:type()}
+ | {events, list(btl_action:type()), btl_character_turn_update:type()}
+ ).
+perform_action (Action, Character, Update) ->
+ case btl_action:get_category(Action) of
+ move -> btl_action_move:handle(Action, Character, Update);
+ attack -> btl_action_attack:handle(Action, Character, Update);
+ switch_weapon ->
+ btl_action_switch_weapon:handle(Action, Character, Update)
+ end.
+
-spec handle_actions
(
list(btl_action:type()),
@@ -44,7 +63,7 @@ deactivate_character (Update) ->
)
-> btl_character_turn_update:type().
handle_actions ([], Update) -> Update;
-handle_actions ([BattleAction|FutureBattleActions], Update) ->
+handle_actions ([BattleAction|FutureBattleActions], S0Update) ->
case btl_action:get_actor_index(BattleAction) of
-1 -> handle_actions(FutureBattleActions, S0Update);
CharacterIX ->
@@ -57,56 +76,17 @@ handle_actions ([BattleAction|FutureBattleActions], Update) ->
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};
- {true, move} -> btl_turn_actions_move:handle(BattleAction, S0Update);
- {true, switch_weapon} ->
- btl_turn_actions_switch_weapon:handle(S0Update);
- {true, attack} ->
- btl_turn_actions_attack:handle(BattleAction, S0Update);
- {true, interrupted_move} ->
- btl_turn_actions_move:handle(BattleAction, S0Update);
- {true, defend} ->
- % TODO: Attack of Opportunity
- Update
- end,
-
- case ActionResult of
- {ok, NewUpdate} -> handle_actions(FutureBattleActions, NewUpdate);
- {events, NewEvents, NewUpdate} ->
- handle_actions
- (
- (NewEvents ++ FutureBattleActions),
- NewUpdate
- )
+ case perform_action(BattleAction, Character, S1Update) of
+ {ok, S2Update} ->
+ handle_actions(FutureBattleActions, S2Update);
+ {events, NewEvents, S2Update} ->
+ handle_actions
+ (
+ (NewEvents ++ FutureBattleActions),
+ S2Update
+ )
+ end
+ end
end.
-spec update_timeline
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl b/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl
deleted file mode 100644
index 2b032a0..0000000
--- a/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl
+++ /dev/null
@@ -1,339 +0,0 @@
--module(btl_turn_actions_attack).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export
-(
- [
- handle/2
- ]
-).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--spec handle_attack_sequence
- (
- btl_character:type(),
- non_neg_integer(),
- btl_character:type(),
- non_neg_integer(),
- integer(),
- integer(),
- list(btl_attack:step()),
- list(btl_attack:type())
- )
- ->
- {
- list(btl_attack:type()),
- non_neg_integer(),
- non_neg_integer(),
- integer(),
- integer()
- }.
-handle_attack_sequence
-(
- _Character,
- CharacterCurrentHealth,
- _TargetCharacter,
- TargetCurrentHealth,
- AttackerLuck,
- DefenderLuck,
- AttackSequence,
- Result
-)
-when
-(
- (CharacterCurrentHealth == 0)
- or (TargetCurrentHealth == 0)
- or (AttackSequence == [])
-) ->
- {
- lists:reverse(Result),
- CharacterCurrentHealth,
- TargetCurrentHealth,
- AttackerLuck,
- DefenderLuck
- };
-handle_attack_sequence
-(
- Character,
- AttackerHealth,
- TargetCharacter,
- DefenderHealth,
- AttackerLuck,
- DefenderLuck,
- [NextAttack | AttackSequence],
- Result
-) ->
- AttackEffect =
- btl_attack:get_description_of
- (
- NextAttack,
- btl_character:get_base_character(Character),
- btl_character:get_base_character(TargetCharacter),
- AttackerLuck,
- DefenderLuck
- ),
-
- {
- AttackResult,
- NewAttackerHealth,
- NewAttackerLuck,
- NewDefenderHealth,
- NewDefenderLuck
- } =
- btl_attack:apply_to_healths_and_lucks
- (
- AttackEffect,
- AttackerHealth,
- AttackerLuck,
- DefenderHealth,
- DefenderLuck
- ),
-
- NextResult =
- case AttackResult of
- {nothing, _, _} -> Result;
- _ -> [AttackResult|Result]
- end,
-
- handle_attack_sequence
- (
- Character,
- NewAttackerHealth,
- TargetCharacter,
- NewDefenderHealth,
- NewAttackerLuck,
- NewDefenderLuck,
- AttackSequence,
- NextResult
- ).
-
--spec get_attack_sequence
- (
- btl_character:type(),
- btl_character:type()
- )
- -> list(btl_attack:step()).
-get_attack_sequence (Character, TargetCharacter) ->
- Range =
- shr_location:dist
- (
- btl_character:get_location(Character),
- btl_character:get_location(TargetCharacter)
- ),
-
- AttackingWeapon =
- shr_character:get_active_weapon
- (
- btl_character:get_base_character(Character)
- ),
-
- DefendingWeapon =
- shr_character:get_active_weapon
- (
- btl_character:get_base_character(TargetCharacter)
- ),
-
- btl_attack:get_sequence(Range, AttackingWeapon, DefendingWeapon).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--spec handle
- (
- btl_action:type(),
- btl_character_turn_update:type()
- )
- -> {ok, btl_character_turn_update:type()}.
-handle (BattleAction, Update) ->
- {S0Update, Battle} = btl_character_turn_update:get_battle(Update),
- {S1Update, Character} = btl_character_turn_update:get_character(S0Update),
-
- AttackingPlayerIX = btl_character:get_player_index(Character),
- AttackingPlayer = btl_battle:get_player(AttackingPlayerIX, Battle),
- AttackingPlayerLuck = btl_player:get_luck(AttackingPlayer),
-
- TargetIX = btl_action:get_target_ix(BattleAction),
- Map = btl_battle:get_map(Battle),
- TargetCharacterRef = btl_battle:get_character(TargetIX, Battle),
- TargetCharacter =
- btl_character:resolve
- (
- shr_tile:get_omnimods
- (
- shr_tile:from_id
- (
- shr_tile_instance:get_tile_id
- (
- shr_map:get_tile_instance
- (
- btl_character:get_location(TargetCharacterRef),
- Map
- )
- )
- )
- ),
- TargetCharacterRef
- ),
-
- DefendingPlayerIX = btl_character:get_player_index(TargetCharacter),
- DefendingPlayer = btl_battle:get_player(DefendingPlayerIX, Battle),
- DefendingPlayerLuck = btl_player:get_luck(DefendingPlayer),
-
-
- true = btl_character:get_is_alive(TargetCharacter),
-
-
- AttackSequence = get_attack_sequence(Character, TargetCharacter),
-
- {
- AttackEffects,
- RemainingAttackerHealth,
- RemainingDefenderHealth,
- NewAttackerLuck,
- NewDefenderLuck
- } =
- handle_attack_sequence
- (
- Character,
- btl_character:get_current_health(Character),
- TargetCharacter,
- btl_character:get_current_health(TargetCharacter),
- AttackingPlayerLuck,
- DefendingPlayerLuck,
- AttackSequence,
- []
- ),
-
- S0NewAttackerLuck =
- case {(NewAttackerLuck =< -2), (NewAttackerLuck >= 2)} of
- {true, _} -> (NewAttackerLuck + 2);
- {_, true} -> (NewAttackerLuck - 2);
- _ -> 0
- end,
-
- S0NewDefenderLuck =
- case {(NewDefenderLuck =< -2), (NewDefenderLuck >= 2)} of
- {true, _} -> (NewDefenderLuck + 2);
- {_, true} -> (NewDefenderLuck - 2);
- _ -> 0
- end,
-
- {UpdatedAttackingPlayer, AttackingPlayerAtaxiaUpdate} =
- btl_player:ataxia_set_luck(S0NewAttackerLuck, AttackingPlayer),
-
- {UpdatedDefendingPlayer, DefendingPlayerAtaxiaUpdate} =
- btl_player:ataxia_set_luck(S0NewDefenderLuck, DefendingPlayer),
-
- {UpdatedCharacter, CharacterAtaxiaUpdate} =
- btl_character:ataxia_set_current_health
- (
- RemainingAttackerHealth,
- Character
- ),
-
- {UpdatedTargetCharacterRef, TargetCharacterRefAtaxiaUpdate} =
- btl_character:ataxia_set_current_health
- (
- RemainingDefenderHealth,
- TargetCharacterRef
- ),
-
- {S0Battle, BattleAtaxiaUpdate0} =
- btl_battle:ataxia_set_player
- (
- AttackingPlayerIX,
- UpdatedAttackingPlayer,
- AttackingPlayerAtaxiaUpdate,
- Battle
- ),
-
- {S1Battle, BattleAtaxiaUpdate1} =
- btl_battle:ataxia_set_player
- (
- DefendingPlayerIX,
- UpdatedDefendingPlayer,
- DefendingPlayerAtaxiaUpdate,
- S0Battle
- ),
-
- {S2Battle, BattleAtaxiaUpdate2} =
- btl_battle:ataxia_set_character
- (
- TargetIX,
- UpdatedTargetCharacterRef,
- TargetCharacterRefAtaxiaUpdate,
- S1Battle
- ),
-
- % Potential danger ahead: we're going to update both the 'character' and
- % 'battle' members of a btl_character_turn_update.
- % 'S1Update' is sure to have both up to date (as it's the result of 'get'
- % requests for both) and there is no risk of the 'battle' update influencing
- % 'character', making what follows safe.
-
- S2Update =
- btl_character_turn_update:ataxia_set_battle
- (
- S2Battle,
- false,
- ataxic:optimize
- (
- ataxic:sequence
- (
- [
- BattleAtaxiaUpdate0,
- BattleAtaxiaUpdate1,
- BattleAtaxiaUpdate2
- ]
- )
- ),
- S1Update
- ),
-
- S3Update =
- btl_character_turn_update:ataxia_set_character
- (
- UpdatedCharacter,
- CharacterAtaxiaUpdate,
- S2Update
- ),
-
- TimelineItem =
- btl_turn_result:new_character_attacked
- (
- btl_character_turn_update:get_character_ix(S3Update),
- TargetIX,
- AttackEffects,
- S0NewAttackerLuck,
- S0NewDefenderLuck
- ),
-
- S4Update = btl_character_turn_update:add_to_timeline(TimelineItem, S3Update),
-
- S5Update =
- case (RemainingAttackerHealth > 0) of
- true -> S4Update;
- false ->
- btl_victory_progression:handle_character_loss(Character, S4Update)
- end,
-
- S6Update =
- case (RemainingDefenderHealth > 0) of
- true -> S5Update;
- false ->
- btl_victory_progression:handle_character_loss
- (
- TargetCharacterRef,
- S5Update
- )
- end,
-
- {ok, S6Update}.
diff --git a/src/battle/struct/btl_action.erl b/src/battle/struct/btl_action.erl
index 174a063..50606ac 100644
--- a/src/battle/struct/btl_action.erl
+++ b/src/battle/struct/btl_action.erl
@@ -8,8 +8,8 @@
move,
{
actor_ix :: non_neg_integer(),
- path :: list(shr_direction:enum())
- movement_points :: non_neg_integer()
+ path :: list(shr_direction:enum()),
+ movement_points :: (non_neg_integer() | -1)
}
).
@@ -38,12 +38,12 @@
| 'attack'
| 'nothing'
).
+
-opaque type() ::
(
#move{}
| #switch_weapon{}
| #attack{}
- | #attack_of_opportunity{}
).
-export_type([category/0, type/0]).
@@ -54,7 +54,7 @@
-export
(
[
- from_map_marker/2,
+ from_map_marker/3,
maybe_decode_move/2,
maybe_decode_weapon_switch/2,
maybe_decode_attack/2,
@@ -65,13 +65,14 @@
-export
(
[
- new_interrupted_move/2
+ new_move/3
]
).
-export
(
[
+ get_is_opportunistic/1,
get_path/1,
get_movement_points/1,
get_target_index/1,
@@ -97,7 +98,14 @@ maybe_decode_move (_CharacterIX, []) -> [];
maybe_decode_move (CharacterIX, PathInBinary) ->
Path = lists:map(fun shr_direction:decode/1, PathInBinary),
- [#move{ actor_ix = CharacterIX, path = Path }].
+ [
+ #move
+ {
+ actor_ix = CharacterIX,
+ path = Path,
+ movement_points = -1
+ }
+ ].
-spec maybe_decode_attack
(
@@ -107,7 +115,14 @@ maybe_decode_move (CharacterIX, PathInBinary) ->
-> list(type()).
maybe_decode_attack (_CharacterIX, TargetIX) when (TargetIX < 0) -> [];
maybe_decode_attack (CharacterIX, TargetIX) ->
- [#attack{ actor_ix = CharacterIX, target_ix = TargetIX }].
+ [
+ #attack
+ {
+ actor_ix = CharacterIX,
+ target_ix = TargetIX,
+ is_opportunistic = false
+ }
+ ].
-spec maybe_decode_weapon_switch
(
@@ -128,31 +143,23 @@ can_follow (move, attack) -> true;
can_follow (_, _) -> false.
-spec get_path (type()) -> list(shr_direction:type()).
-get_path (Action) when is_record(Action, move) ->
- Action#move.path;
-get_path (Action) when is_record(Action, interrupted_move) ->
- Action#interrupted_move.path;
+get_path (Action) when is_record(Action, move) -> Action#move.path;
get_path (_) ->
[].
--spec get_movement_points (type()) -> non_neg_integer().
-get_movement_points (Action) when is_record(Action, interrupted_move) ->
- Action#interrupted_move.movement_points;
-get_movement_points (_) -> 0.
+-spec get_movement_points (type()) -> (non_neg_integer() | -1).
+get_movement_points (Action) when is_record(Action, move) ->
+ Action#move.movement_points;
+get_movement_points (_) -> -1.
--spec get_target_index (type()) -> non_neg_integer().
+-spec get_target_index (type()) -> (non_neg_integer() | -1).
get_target_index (Action) when is_record(Action, attack) ->
Action#attack.target_ix;
-get_target_index (Action) when is_record(Action, attack_of_opportunity) ->
- Action#attack_of_opportunity.target_ix;
-get_target_index (_) ->
- 0.
+get_target_index (_) -> -1.
-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) ->
@@ -160,37 +167,47 @@ get_actor_index (Action) when is_record(Action, switch_weapon) ->
get_actor_index (_) ->
-1.
--spec new_interrupted_move
+-spec get_is_opportunistic (type()) -> boolean().
+get_is_opportunistic (Action) when is_record(Action, attack) ->
+ Action#attack.is_opportunistic;
+get_is_opportunistic (_) -> false.
+
+-spec new_move
(
+ non_neg_integer(),
list(shr_direction:type()),
- non_neg_integer()
+ (non_neg_integer() | -1)
)
-> type().
-new_interrupted_move (Path, MovementPoints) ->
- #interrupted_move{ path = Path, movement_points = MovementPoints }.
+new_move (ActorIX, Path, MovementPoints) ->
+ #move
+ {
+ actor_ix = ActorIX,
+ path = Path,
+ movement_points = MovementPoints
+ }.
-spec get_category (type()) -> category().
get_category (Action) when is_record(Action, attack) -> attack;
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, attack_of_opportunity) ->
- attack_of_opportunity.
+get_category (Action) when is_record(Action, switch_weapon) -> switch_weapon.
-spec from_map_marker
(
+ non_neg_integer(),
btl_character:type(),
shr_map_marker:type()
)
-> list(type()).
-from_map_marker (_Character, Marker) ->
+from_map_marker (CharacterIX, _Character, Marker) ->
case shr_map_marker:get_category(Marker) of
matk ->
[
- #attack_of_opportunity
+ #attack
{
- target_ix = shr_map_marker:get_character_index(Marker)
+ target_ix = CharacterIX,
+ actor_ix = shr_map_marker:get_character_index(Marker),
+ is_opportunistic = true
}
];