summaryrefslogtreecommitdiff |
diff options
author | nsensfel <SpamShield0@noot-noot.org> | 2019-06-05 11:24:52 +0200 |
---|---|---|
committer | nsensfel <SpamShield0@noot-noot.org> | 2019-06-05 11:24:52 +0200 |
commit | 1afb69a11b0e291c7bfd6c24bdd8e55742e61889 (patch) | |
tree | 21c09b15ddcc3272bbb8fa8d41676ffa56ca3130 | |
parent | 1aec9784102855c4bf2e5d2ad9a945166aed2051 (diff) |
[Broken] Changing how actions are handled...
-rw-r--r-- | src/battle/mechanic/btl_attack.erl | 554 | ||||
-rw-r--r-- | src/battle/mechanic/btl_turn_actions_management.erl | 50 | ||||
-rw-r--r-- | src/battle/reply/btl_add_char.erl | 2 | ||||
-rw-r--r-- | src/battle/struct/btl_action.erl | 102 | ||||
-rw-r--r-- | src/battle/struct/btl_attack.erl | 28 | ||||
-rw-r--r-- | src/battle/struct/btl_battle.erl | 112 | ||||
-rw-r--r-- | src/battle/struct/btl_character.erl | 20 | ||||
-rw-r--r-- | src/battle/struct/btl_character_turn_request.erl | 14 | ||||
-rw-r--r-- | src/battle/struct/btl_character_turn_update.erl | 12 | ||||
-rw-r--r-- | src/shared/struct/shr_character.erl | 7 |
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) -> |