summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl308
-rw-r--r--src/battle/struct/btl_attack.erl5
2 files changed, 311 insertions, 2 deletions
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl b/src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl
new file mode 100644
index 0000000..7d6a1c5
--- /dev/null
+++ b/src/battle/mechanic/turn_action/btl_turn_actions_opportunity_attack.erl
@@ -0,0 +1,308 @@
+-module(btl_turn_actions_opportunity_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
+ ).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 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),
+
+ DefendingPlayerIX = btl_character:get_player_index(Character),
+ DefendingPlayer = btl_battle:get_player(DefendingPlayerIX, Battle),
+ DefendingPlayerLuck = btl_player:get_luck(DefendingPlayer),
+
+ ActorIX = btl_action:get_target_ix(BattleAction),
+ Map = btl_battle:get_map(Battle),
+ ActorCharacterRef = btl_battle:get_character(ActorIX, Battle),
+ ActorCharacter =
+ 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(ActorCharacterRef),
+ Map
+ )
+ )
+ )
+ ),
+ ActorCharacterRef
+ ),
+
+ AttackingPlayerIX = btl_character:get_player_index(ActorCharacter),
+ AttackingPlayer = btl_battle:get_player(AttackingPlayerIX, Battle),
+ AttackingPlayerLuck = btl_player:get_luck(AttackingPlayer),
+
+ AttackSequence = btl_attack:attack_of_opportunity(),
+
+ {
+ AttackEffects,
+ RemainingAttackerHealth,
+ RemainingDefenderHealth,
+ NewAttackerLuck,
+ NewDefenderLuck
+ } =
+ handle_attack_sequence
+ (
+ Character,
+ btl_character:get_current_health(Character),
+ ActorCharacter,
+ btl_character:get_current_health(ActorCharacter),
+ 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 (RemainingAttackerHealth > 0) of
+ true -> S5Update;
+ false ->
+ btl_victory_progression:handle_character_loss
+ (
+ TargetCharacterRef,
+ S5Update
+ )
+ end,
+
+ {ok, S6Update}.
diff --git a/src/battle/struct/btl_attack.erl b/src/battle/struct/btl_attack.erl
index 481e07f..189cb0e 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').
+-type order() :: ('first' | 'second' | 'counter' | 'opportunity').
-type precision() :: ('misses' | 'grazes' | 'hits').
-record
@@ -35,7 +35,8 @@
[
get_sequence/3,
get_description_of/5,
- apply_to_healths_and_lucks/5
+ apply_to_healths_and_lucks/5,
+ new_opportunity/2,
]
).