| summaryrefslogtreecommitdiff | 
diff options
| author | nsensfel <SpamShield0@noot-noot.org> | 2019-06-05 17:52:58 +0200 | 
|---|---|---|
| committer | nsensfel <SpamShield0@noot-noot.org> | 2019-06-05 17:52:58 +0200 | 
| commit | 9e7dcabc164eacb7024387e060623993b48c60b4 (patch) | |
| tree | 50df2a6143eb2eca18b2588383630c81bb11c1b6 /src/battle | |
| parent | 1afb69a11b0e291c7bfd6c24bdd8e55742e61889 (diff) | |
[Broken] ...
Diffstat (limited to 'src/battle')
| -rw-r--r-- | src/battle/mechanic/action/btl_action_attack.erl | 655 | ||||
| -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.erl | 109 | ||||
| -rw-r--r-- | src/battle/mechanic/btl_turn_actions_management.erl | 82 | ||||
| -rw-r--r-- | src/battle/mechanic/turn_action/btl_turn_actions_attack.erl | 339 | ||||
| -rw-r--r-- | src/battle/struct/btl_action.erl | 85 | 
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              }           ]; | 


