summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2019-05-21 16:39:12 +0200
committerNathanael Sensfelder <SpamShield0@MultiAgentSystems.org>2019-05-21 16:39:12 +0200
commit0157365585c1201c53aa29cac84cd977de7434a1 (patch)
tree44c301187f2809be974dbe8afcbc1032002ec1e8 /src/battle
parentfb4159dbfb49f71d23c2616e7b8c9be453953883 (diff)
Working on Attacks of Opportunity.
Diffstat (limited to 'src/battle')
-rw-r--r--src/battle/mechanic/btl_turn_actions_management.erl55
-rw-r--r--src/battle/mechanic/turn_action/btl_turn_actions_attack.erl4
-rw-r--r--src/battle/mechanic/turn_action/btl_turn_actions_move.erl154
-rw-r--r--src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl4
-rw-r--r--src/battle/struct/btl_action.erl92
5 files changed, 252 insertions, 57 deletions
diff --git a/src/battle/mechanic/btl_turn_actions_management.erl b/src/battle/mechanic/btl_turn_actions_management.erl
index d33fbad..eefe812 100644
--- a/src/battle/mechanic/btl_turn_actions_management.erl
+++ b/src/battle/mechanic/btl_turn_actions_management.erl
@@ -37,17 +37,48 @@ deactivate_character (Update) ->
S1Update.
--spec handle_action
-(
- btl_action:type(),
- btl_character_turn_update:type()
-)
--> btl_character_turn_update:type().
-handle_action (BattleAction, Update) ->
- case btl_action:get_category(BattleAction) of
- move -> btl_turn_actions_move:handle(BattleAction, Update);
- switch_weapon -> btl_turn_actions_switch_weapon:handle(Update);
- attack -> btl_turn_actions_attack:handle(BattleAction, Update)
+-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()),
+ btl_character_turn_update:type()
+ )
+ -> btl_character_turn_update:type().
+handle_actions ([], Update) -> Update;
+handle_actions ([BattleAction|FutureBattleActions], Update) ->
+ {MainCharacterIsAlive, S0Update} = main_character_is_alive(Update),
+
+ 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
+ )
end.
-spec update_timeline
@@ -98,7 +129,7 @@ update_timeline (Update) ->
handle (Update, Request) ->
Actions = btl_character_turn_request:get_actions(Request),
- S0Update = lists:foldl(fun handle_action/2, Update, Actions),
+ S0Update = handle_actions(Actions, Update),
S1Update = deactivate_character(S0Update),
S2Update = update_timeline(S1Update),
S3Update = btl_turn_progression:handle(S2Update),
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl b/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl
index e36c7e3..af4c53b 100644
--- a/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl
+++ b/src/battle/mechanic/turn_action/btl_turn_actions_attack.erl
@@ -151,7 +151,7 @@ get_attack_sequence (Character, TargetCharacter) ->
btl_action:type(),
btl_character_turn_update: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),
@@ -336,4 +336,4 @@ handle (BattleAction, Update) ->
)
end,
- S6Update.
+ {ok, S6Update}.
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_move.erl b/src/battle/mechanic/turn_action/btl_turn_actions_move.erl
index a0cd138..70b42c9 100644
--- a/src/battle/mechanic/turn_action/btl_turn_actions_move.erl
+++ b/src/battle/mechanic/turn_action/btl_turn_actions_move.erl
@@ -18,16 +18,23 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec cross
(
+ non_neg_integer(),
shr_map:type(),
list(shr_location:type()),
list(shr_direction:enum()),
non_neg_integer(),
shr_location:type()
)
- -> {shr_location:type(), non_neg_integer()}.
-cross (_Map, _ForbiddenLocations, [], Cost, Location) ->
- {Location, Cost};
-cross (Map, ForbiddenLocations, [Step|NextSteps], Cost, Location) ->
+ ->
+ {
+ shr_location:type(),
+ list(shr_direction:type()),
+ non_neg_integer(),
+ list(shr_map_marker:type())
+ }.
+cross (_PlayerIX, _Map, _ForbiddenLocations, [], Cost, Location) ->
+ {Location, [], Cost, []};
+cross (PlayerIX, Map, ForbiddenLocations, [Step|NextSteps], Cost, Location) ->
NextLocation = shr_location:apply_direction(Step, Location),
NextTileInstance = shr_map:get_tile_instance(NextLocation, Map),
NextTileClassID = shr_tile_instance:get_tile_id(NextTileInstance),
@@ -43,20 +50,60 @@ cross (Map, ForbiddenLocations, [Step|NextSteps], Cost, Location) ->
ForbiddenLocations
),
- IsForbidden = false,
+ false = IsForbidden,
+
+ Interruptions =
+ list:foldl
+ (
+ fun (MarkerName, CurrentInterruptions) ->
+ case shr_map:get_marker(MarkerName, Map) of
+ {ok, Marker} ->
+ case shr_map_marker:interrupts_movement(PlayerIX, Marker) of
+ true -> [Marker|CurrentInterruptions];
+ _ -> CurrentInterruptions
+ end;
+
+ error ->
+ %% TODO: Error.
+ CurrentInterruptions
+ end
+ end,
+ [],
+ shr_tile_instance:get_triggers(NextTileInstance)
+ ),
+
+ case Interruptions of
+ [] ->
+ cross
+ (
+ PlayerIX,
+ Map,
+ ForbiddenLocations,
+ NextSteps,
+ NextCost,
+ NextLocation
+ );
- cross(Map, ForbiddenLocations, NextSteps, NextCost, NextLocation).
+ _ -> {NextLocation, NextSteps, NextCost, Interruptions}
+ end.
-spec cross
(
+ non_neg_integer(),
shr_map:type(),
list(shr_location:type()),
list(shr_direction:enum()),
shr_location:type()
)
- -> {shr_location:type(), non_neg_integer()}.
-cross (Map, ForbiddenLocations, Path, Location) ->
- cross(Map, ForbiddenLocations, Path, 0, Location).
+ ->
+ {
+ shr_location:type(),
+ list(shr_direction:type()),
+ non_neg_integer(),
+ list(shr_map_marker:type())
+ }.
+cross (PlayerIX, Map, ForbiddenLocations, Path, Location) ->
+ cross(PlayerIX, Map, ForbiddenLocations, Path, 0, Location).
-spec get_path_cost_and_destination
(
@@ -67,6 +114,8 @@ cross (Map, ForbiddenLocations, Path, Location) ->
{
non_neg_integer(),
shr_location:type(),
+ list(shr_direction:type()),
+ list(shr_map_marker:type()),
btl_character_turn_update:type()
}.
get_path_cost_and_destination (Update, Path) ->
@@ -75,6 +124,9 @@ get_path_cost_and_destination (Update, Path) ->
CharacterIX = btl_character_turn_update:get_character_ix(S1Update),
Map = btl_battle:get_map(Battle),
+ % FIXME: 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 =
orddict:fold
(
@@ -91,42 +143,35 @@ get_path_cost_and_destination (Update, Path) ->
btl_battle:get_characters(Battle)
),
- {NewLocation, Cost} =
+ {NewLocation, RemainingPath, Cost, Interruptions} =
cross
(
+ btl_character:get_player_index(Character),
Map,
ForbiddenLocations,
Path,
btl_character:get_location(Character)
),
- {Cost, NewLocation, S1Update}.
+ {Cost, NewLocation, RemainingPath, Interruptions, S1Update}.
--spec assert_character_can_move
+-spec get_movement_points
(
- btl_character:type(),
- non_neg_integer()
+ btl_action:type(),
+ btl_character:type()
)
- -> ('ok' | 'error').
-assert_character_can_move (Char, Cost) ->
- CharacterMovementPoints =
- shr_statistics:get_movement_points
- (
- shr_character:get_statistics
+ -> non_neg_integer().
+get_movement_points (Action, Char) ->
+ case btl_action:get_category(Action) of
+ interrupted_move -> btl_action:get_movement_points(Action);
+ _ ->
+ shr_statistics:get_movement_points
(
- btl_character:get_base_character(Char)
+ shr_character:get_statistics
+ (
+ btl_character:get_base_character(Char)
+ )
)
- ),
-
- case (Cost =< CharacterMovementPoints) of
- true -> ok;
- false ->
- io:format
- (
- "~n[E] Character trying to move ~p dist with ~p points.~n",
- [Cost, CharacterMovementPoints]
- ),
- error
end.
-spec commit_move
@@ -183,14 +228,51 @@ commit_move (Character, Update, Path, NewLocation) ->
btl_action:type(),
btl_character_turn_update:type()
)
- -> btl_character_turn_update:type().
+ ->
+ (
+ {'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),
- {PathCost, NewLocation, S1Update} =
+ {PathCost, NewLocation, RemainingPath, Interruptions, S1Update} =
get_path_cost_and_destination(S0Update, Path),
- ok = assert_character_can_move(Character, PathCost),
+ MovementPoints = get_movement_points(BattleAction, Character),
+
+ true = (MovementPoints >= PathCost),
+
+ S2Update = commit_move(Character, S1Update, Path, NewLocation),
- commit_move(Character, S1Update, Path, NewLocation).
+ case RemainingPath of
+ [] -> {ok, S2Update};
+ _ ->
+ {events,
+ (
+ lists:foldl
+ (
+ fun (Marker, CurrentActions) ->
+ (
+ btl_action:from_map_marker(Character, Marker)
+ ++
+ CurrentActions
+ )
+ end,
+ [],
+ Interruptions
+ )
+ ++
+ [
+ btl_action:new_interrupted_move
+ (
+ RemainingPath,
+ (MovementPoints - PathCost)
+ )
+ ]
+ ),
+ S2Update
+ }
+ end.
diff --git a/src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl b/src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl
index 24b361a..8e4aeab 100644
--- a/src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl
+++ b/src/battle/mechanic/turn_action/btl_turn_actions_switch_weapon.erl
@@ -24,7 +24,7 @@
(
btl_character_turn_update: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),
@@ -52,4 +52,4 @@ handle (Update) ->
S1Update
),
- S2Update.
+ {ok, S2Update}.
diff --git a/src/battle/struct/btl_action.erl b/src/battle/struct/btl_action.erl
index 34dd46e..52f41d8 100644
--- a/src/battle/struct/btl_action.erl
+++ b/src/battle/struct/btl_action.erl
@@ -13,6 +13,15 @@
-record
(
+ interrupted_move,
+ {
+ path :: list(shr_direction:enum()),
+ movement_points :: non_neg_integer()
+ }
+).
+
+-record
+(
switch_weapon,
{
}
@@ -26,8 +35,32 @@
}
).
--type category() :: ('move' | 'switch_weapon' | 'attack' | 'nothing').
--opaque type() :: (#move{} | #switch_weapon{} | #attack{}).
+-record
+(
+ defend,
+ {
+ target_ix :: non_neg_integer()
+ }
+).
+
+
+-type category() ::
+ (
+ 'move'
+ | 'interrupted_move'
+ | 'switch_weapon'
+ | 'attack'
+ | 'defend'
+ | 'nothing'
+ ).
+-opaque type() ::
+ (
+ #move{}
+ | #interrupted_move{}
+ | #switch_weapon{}
+ | #attack{}
+ | #defend{}
+ ).
-export_type([category/0, type/0]).
@@ -37,6 +70,7 @@
-export
(
[
+ from_map_marker/2,
maybe_decode_move/1,
maybe_decode_weapon_switch/1,
maybe_decode_attack/1,
@@ -47,7 +81,15 @@
-export
(
[
+ new_interrupted_move/2
+ ]
+).
+
+-export
+(
+ [
get_path/1,
+ get_movement_points/1,
get_target_ix/1,
get_category/1
]
@@ -86,17 +128,57 @@ 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 (_) ->
[].
+-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_target_ix (type()) -> non_neg_integer().
get_target_ix (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 (_) ->
- [].
+ 0.
+
+-spec new_interrupted_move
+ (
+ list(shr_direction:type()),
+ non_neg_integer()
+ )
+ -> type().
+new_interrupted_move (Path, MovementPoints) ->
+ #interrupted_move{ 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, switch_weapon) -> switch_weapon;
+get_category (Action) when is_record(Action, interrupted_move) ->
+ interrupted_move;
+get_category (Action) when is_record(Action, defend) ->
+ defend.
+
+-spec from_map_marker
+ (
+ btl_character:type(),
+ shr_map_marker:type()
+ )
+ -> list(type()).
+from_map_marker (_Character, Marker) ->
+ case shr_map_marker:get_category(Marker) of
+ matk ->
+ [
+ #defend
+ {
+ target_ix = shr_map_marker:get_character_index(Marker)
+ }
+ ];
+
+ _ -> []
+ end.