aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornsensfel <SpamShield0@noot-noot.org>2018-03-01 14:30:24 +0100
committernsensfel <SpamShield0@noot-noot.org>2018-03-01 14:30:24 +0100
commit21a949eb40407ab61e5dac956303ec1618bdfe1e (patch)
treed88a20219e70cf2aa0db64261c4232caa02d3707
parent55c32019f5b82fd488c4ceed8c80e1b7a0fa114f (diff)
downloadtacticians-server-21a949eb40407ab61e5dac956303ec1618bdfe1e.zip
tacticians-server-21a949eb40407ab61e5dac956303ec1618bdfe1e.tar.bz2
...
-rw-r--r--src/query/character_turn.erl550
1 files changed, 110 insertions, 440 deletions
diff --git a/src/query/character_turn.erl b/src/query/character_turn.erl
index cb4e8ea..adfc542 100644
--- a/src/query/character_turn.erl
+++ b/src/query/character_turn.erl
@@ -12,19 +12,18 @@
{
player_id :: player:id(),
session_token :: binary(),
- battlemap_instance_id :: binary(),
+ battle_id :: binary(),
character_instance_ix :: non_neg_integer(),
- path :: list(binary()),
- target_ix :: (-1 | non_neg_integer())
+ actions :: list(battle_action:struct())
}
).
-record
(
- query_state,
+ relevant_data,
{
- battlemap_instance :: battlemap_instance:struct(),
- character_instance :: character_instance:struct()
+ battle :: battle:struct(),
+ played_character_instance :: character_instance:struct()
}
).
@@ -34,401 +33,99 @@
{
is_new_turn :: boolean(),
updated_character_instance_ixs :: list(non_neg_integer()),
- updated_battlemap_instance :: battlemap_instance:struct()
+ updated_battle :: battle:struct()
}
).
-type input() :: #input{}.
--type query_state() :: #query_state{}.
-type query_result() :: #query_result{}.
+
+-type relevant_data() :: #relevant_data{}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([out/1]).
+-export_type([relevant_data/0]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-decode_action (EncodedAction) ->
- JSONActionMap = jiffy:decode(EncodedAction, [return_maps]),
-spec parse_input (binary()) -> input().
parse_input (Req) ->
JSONReqMap = jiffy:decode(Req, [return_maps]),
CharacterInstanceIX = binary_to_integer(maps:get(<<"cix">>, JSONReqMap)),
- TargetIX = binary_to_integer(maps:get(<<"tix">>, JSONReqMap)),
EncodedActions = maps:get(<<"act">>, JSONReqMap),
- Actions = decode_action_sequence(EncodedActions),
+ Actions = lists:map(fun battle_action:decode/1, EncodedActions),
+
#input
{
player_id = maps:get(<<"pid">>, JSONReqMap),
session_token = maps:get(<<"stk">>, JSONReqMap),
battle_id = maps:get(<<"bid">>, JSONReqMap),
character_instance_ix = CharacterInstanceIX,
- path = maps:get(<<"p">>, JSONReqMap),
- target_ix = TargetIX
+ actions = Actions
}.
--spec fetch_data (input()) -> query_state().
-fetch_data (Input) ->
+-spec fetch_relevant_data (input()) -> battle:struct().
+fetch_relevant_data (Input) ->
PlayerID = Input#input.player_id,
- BattlemapInstanceID = Input#input.battlemap_instance_id,
+ BattleID = Input#input.battle_id,
CharacterInstanceIX = Input#input.character_instance_ix,
- BattlemapInstance =
- timed_cache:fetch
- (
- battlemap_instance_db,
- PlayerID,
- BattlemapInstanceID
- ),
+ Battle = timed_cache:fetch(battle_db, PlayerID, BattleID),
CharacterInstance =
- array:get
- (
- CharacterInstanceIX,
- battlemap_instance:get_character_instances(BattlemapInstance)
- ),
+ battle:get_character_instance(CharacterInstanceIX, Battle),
- #query_state
+ #relevant_data
{
- battlemap_instance = BattlemapInstance,
- character_instance = CharacterInstance
+ battle = Battle,
+ played_character_instance = CharacterInstance
}.
-spec assert_character_instance_can_be_played
(
- query_state(),
+ relevant_data(),
input()
)
- -> 'ok'.
-assert_character_instance_can_be_played (QueryState, Input) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
+ -> true.
+assert_character_instance_can_be_played (RData, Input) ->
PlayerID = Input#input.player_id,
- ControlledCharacterInstance = QueryState#query_state.character_instance,
-
- PlayerID =
- array:get
- (
- player_turn:get_player_ix
- (
- battlemap_instance:get_current_player_turn(BattlemapInstance)
- ),
- battlemap_instance:get_player_ids(BattlemapInstance)
- ),
- PlayerID =
- character:get_owner_id
- (
- character_instance:get_character(ControlledCharacterInstance)
- ),
- true = character_instance:get_is_active(ControlledCharacterInstance),
-
- ok.
-
--spec handle_character_instance_moving
- (
- query_state(),
- input()
- )
- -> {list(any()), query_state()}.
-handle_character_instance_moving (QueryState, Input) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
- ControlledCharacterInstance = QueryState#query_state.character_instance,
- ControlledCharacter =
- character_instance:get_character(ControlledCharacterInstance),
- ControlledCharacterIX = Input#input.character_instance_ix,
-
- Path = Input#input.path,
- Battlemap = battlemap_instance:get_battlemap(BattlemapInstance),
- ControlledCharacterStatistics =
- character:get_statistics(ControlledCharacter),
- ControlledCharacterMovementPoints =
- statistics:get_movement_points(ControlledCharacterStatistics),
-
- % FIXME: The controlled character's old location should not be considered to
- % be a forbidden location.
- ForbiddenLocations =
- array:map
- (
- fun (_IX, CharacterInstance) ->
- character_instance:get_location(CharacterInstance)
- end,
- battlemap_instance:get_character_instances(BattlemapInstance)
- ),
- {NewLocation, Cost} =
- movement:cross
- (
- Battlemap,
- ForbiddenLocations,
- Path,
- character_instance:get_location(ControlledCharacterInstance)
- ),
-
- io:format
- (
- "~nMoving from ~p to ~p (cost ~p) with ~p movement points.~n",
- [
- character_instance:get_location(ControlledCharacterInstance),
- NewLocation,
- Cost,
- ControlledCharacterMovementPoints
- ]
- ),
-
- true = (Cost =< ControlledCharacterMovementPoints),
-
- UpdatedQueryState =
- QueryState#query_state
- {
- character_instance =
- character_instance:set_location
- (
- NewLocation,
- ControlledCharacterInstance
- )
- },
- {
- [{move, ControlledCharacterIX, NewLocation}],
- UpdatedQueryState
- }.
-
--spec handle_character_instance_switching_weapons
- (
- query_state(),
- input()
- )
- -> {list(any()), query_state()}.
-handle_character_instance_switching_weapons (QueryState, Input) ->
- ControlledCharacterInstance = QueryState#query_state.character_instance,
- ControlledCharacter =
- character_instance:get_character(ControlledCharacterInstance),
- ControlledCharacterAttributes =
- character:get_attributes(ControlledCharacter),
- {PrimaryWeapon, SecondaryWeapon} =
- character:get_weapon_ids(ControlledCharacter),
- ControlledCharacterIX = Input#input.character_instance_ix,
-
- UpdatedWeapons = {SecondaryWeapon, PrimaryWeapon},
- UpdatedControlledCharacterStatistics =
- statistics:new
- (
- ControlledCharacterAttributes,
- UpdatedWeapons
- ),
- UpdatedControlledCharacter =
- character:set_statistics
- (
- UpdatedControlledCharacterStatistics,
- character:set_weapon_ids
- (
- UpdatedWeapons,
- ControlledCharacter
- )
- ),
- UpdatedControlledCharacterInstance =
- character_instance:set_character
- (
- UpdatedControlledCharacter,
- ControlledCharacterInstance
- ),
- UpdatedQueryState =
- QueryState#query_state
- {
- character_instance = UpdatedControlledCharacterInstance
- },
-
- {
- [{switch_weapons, ControlledCharacterIX}],
- UpdatedQueryState
- }.
-
--spec set_new_healths_in_query_state
- (
- non_neg_integer(),
- non_neg_integer(),
- query_state(),
- input()
- )
- -> query_state().
-set_new_healths_in_query_state
-(
- RemainingAttackerHealth,
- RemainingDefenderHealth,
- QueryState,
- Input
-) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
- ControlledCharacterInstance = QueryState#query_state.character_instance,
- CharacterInstances =
- battlemap_instance:get_character_instances(BattlemapInstance),
- TargettedCharacterInstanceIX = Input#input.target_ix,
- TargettedCharacterInstance =
- array:get
- (
- TargettedCharacterInstanceIX,
- CharacterInstances
- ),
-
- QueryState#query_state
- {
- battlemap_instance =
- battlemap_instance:set_character_instances
- (
- array:set
- (
- TargettedCharacterInstanceIX,
- character_instance:set_current_health
- (
- RemainingDefenderHealth,
- TargettedCharacterInstance
- ),
- CharacterInstances
- ),
- BattlemapInstance
- ),
- character_instance =
- character_instance:set_current_health
- (
- RemainingAttackerHealth,
- ControlledCharacterInstance
- )
- }.
-
--spec handle_character_instance_attacking
- (
- query_state(),
- input()
- )
- -> {list(attack:attack_desc()), query_state()}.
-handle_character_instance_attacking (QueryState, Input) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
- ControlledCharacterInstance = QueryState#query_state.character_instance,
- ControlledCharacter =
- character_instance:get_character(ControlledCharacterInstance),
- ControlledCharacterStatistics =
- character:get_statistics(ControlledCharacter),
- TargettedCharacterInstance =
- array:get
- (
- Input#input.target_ix,
- battlemap_instance:get_character_instances(BattlemapInstance)
- ),
- TargettedCharacter =
- character_instance:get_character(TargettedCharacterInstance),
- TargettedCharacterStatistics = character:get_statistics(TargettedCharacter),
- RequiredRange =
- movement:steps_between
- (
- character_instance:get_location(ControlledCharacterInstance),
- character_instance:get_location(TargettedCharacterInstance)
- ),
- {AttackingWeaponID, _} = character:get_weapon_ids(ControlledCharacter),
- AttackingWeapon = weapon:from_id(AttackingWeaponID),
- {DefendingWeaponID, _} = character:get_weapon_ids(TargettedCharacter),
- DefendingWeapon = weapon:from_id(DefendingWeaponID),
- BaseAttackerHealth =
- character_instance:get_current_health(ControlledCharacterInstance),
- BaseDefenderHealth =
- character_instance:get_current_health(TargettedCharacterInstance),
-
- AttackSequence =
- attack:get_sequence(RequiredRange, AttackingWeapon, DefendingWeapon),
-
- AttackEffects =
- lists:map
- (
- fun (AttackOrder) ->
- attack:get_description_of
- (
- AttackOrder,
- ControlledCharacterStatistics,
- TargettedCharacterStatistics
- )
- end,
- AttackSequence
- ),
-
- {AttackSummary, RemainingAttackerHealth, RemainingDefenderHealth} =
- lists:foldl
+ CharacterInstance = RData#relevant_data.played_character_instance,
+ Battle = RData#relevant_data.battle,
+ Character = character_instance:get_character(CharacterInstance),
+ CurrentPlayerIX =
+ player_turn:get_player_ix
(
- fun
- (
- AttackEffect,
- {
- CurrentAttackEffects,
- CurrentAttackerHealth,
- CurrentDefenderHealth
- }
- ) ->
- {AttackTrueEffect, NewAttackerHealth, NewDefenderHealth} =
- attack:apply_to_healths
- (
- AttackEffect,
- CurrentAttackerHealth,
- CurrentDefenderHealth
- ),
- {
- [AttackTrueEffect|CurrentAttackEffects],
- NewAttackerHealth,
- NewDefenderHealth
- }
- end,
- {[], BaseAttackerHealth, BaseDefenderHealth},
- AttackEffects
+ battle:get_current_player_turn(Battle)
),
+ CurrentPlayer = battle:get_player_id(CurrentPlayerIX, Battle),
+ CharacterOwner = character:get_owner_id(Character),
- {
- AttackSummary,
- set_new_healths_in_query_state
- (
- RemainingAttackerHealth,
- RemainingDefenderHealth,
- QueryState,
- Input
- )
- }.
+ PlayerID = CurrentPlayer,
+ PlayerID = CharacterOwner,
--spec get_type_of_turn (input()) -> list(atom()).
-get_type_of_turn (Input) ->
- case {Input#input.path, Input#input.target_ix} of
- {[], -1} -> [nothing, nothing];
- {[], _} -> [nothing, attack];
- {[<<"S">>], -1} -> [switch, nothing];
- {[<<"S">>], _} -> [switch, attack];
- {_, -1} -> [move, nothing];
- {_, _} -> [move, attack]
- end.
+ true = character_instance:get_is_active(CharacterInstance).
--spec finalize_character_instance
+-spec finalize_and_fuse_relevant_data
(
- query_state(),
+ relevant_data(),
input()
)
- -> query_state().
-finalize_character_instance (QueryState, Input) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
+ -> battle:struct().
+finalize_and_fuse_relevant_data (RData, Input) ->
+ Battle = RData#relevant_data.battle,
+ CharacterInstance = RData#relevant_data.played_character_instance,
FinalizedCharacterInstance =
- character_instance:set_is_active
- (
- false,
- QueryState#query_state.character_instance
- ),
+ character_instance:set_is_active(false, CharacterInstance),
- QueryState#query_state
- {
- battlemap_instance =
- battlemap_instance:set_character_instances
- (
- array:set
- (
- Input#input.character_instance_ix,
- FinalizedCharacterInstance,
- battlemap_instance:get_character_instances(BattlemapInstance)
- ),
- BattlemapInstance
- ),
- character_instance = FinalizedCharacterInstance
- }.
+ battle:set_character_instance
+ (
+ Input#input.character_instance_ix,
+ FinalizedCharacterInstance,
+ Battle
+ ).
-spec activate_relevant_character_instances
(
@@ -472,15 +169,14 @@ activate_relevant_character_instances (IXs, CharacterInstances, Owner, IX) ->
(
query_state()
)
- -> {list(non_neg_integer()), battlemap_instance:struct()}.
+ -> {list(non_neg_integer()), battle:struct()}.
start_next_players_turn (QueryState) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
- PlayerIDs = battlemap_instance:get_player_ids(BattlemapInstance),
- PlayerTurn = battlemap_instance:get_current_player_turn(BattlemapInstance),
+ Battle = QueryState#query_state.battle,
+ PlayerIDs = battle:get_player_ids(Battle),
+ PlayerTurn = battle:get_current_player_turn(Battle),
CurrentPlayerIX = player_turn:get_player_ix(PlayerTurn),
CurrentTurnNumber = player_turn:get_number(PlayerTurn),
- CharacterInstances =
- battlemap_instance:get_character_instances(BattlemapInstance),
+ CharacterInstances = battle:get_character_instances(Battle),
NextPlayerIX = ((CurrentPlayerIX + 1) rem (array:size(PlayerIDs))),
NextPlayerTurn =
@@ -501,23 +197,23 @@ start_next_players_turn (QueryState) ->
array:get(NextPlayerIX, PlayerIDs),
(array:size(CharacterInstances) - 1)
),
- UpdatedBattlemapInstance =
- battlemap_instance:set_character_instances
+ UpdatedBattle =
+ battle:set_character_instances
(
UpdatedCharacterInstances,
- battlemap_instance:set_current_player_turn
+ battle:set_current_player_turn
(
NextPlayerTurn,
- BattlemapInstance
+ Battle
)
),
- {ActivatedCharacterInstanceIXs, UpdatedBattlemapInstance}.
+ {ActivatedCharacterInstanceIXs, UpdatedBattle}.
-spec finalize_character_turn (query_state()) -> query_result().
finalize_character_turn (QueryState) ->
- BattlemapInstance = QueryState#query_state.battlemap_instance,
+ Battle = QueryState#query_state.battle,
CharacterInstances =
- battlemap_instance:get_character_instances(BattlemapInstance),
+ battle:get_character_instances(Battle),
AnActiveCharacterInstanceRemains =
array:foldl
@@ -536,108 +232,62 @@ finalize_character_turn (QueryState) ->
{
is_new_turn = false,
updated_character_instance_ixs = [],
- updated_battlemap_instance = BattlemapInstance
+ updated_battle = Battle
};
false ->
io:format("~nThere are no more active characters.~n"),
- {UpdatedCharacterInstanceIXs, UpdatedBattlemapInstance} =
+ {UpdatedCharacterInstanceIXs, UpdatedBattle} =
start_next_players_turn(QueryState),
#query_result
{
is_new_turn = true,
updated_character_instance_ixs = UpdatedCharacterInstanceIXs,
- updated_battlemap_instance = UpdatedBattlemapInstance
+ updated_battle = UpdatedBattle
}
end.
--spec play
- (
- list(any()),
- query_state(),
- list(atom()),
- input()
- )
- -> {list(any()), query_state()}.
-play (DiffUpdate, QueryState, [], _Input) ->
- {DiffUpdate, QueryState};
-play (DiffUpdate, QueryState, [nothing|Next], Input) ->
- play(DiffUpdate, QueryState, Next, Input);
-play (DiffUpdate, QueryState, [move|Next], Input) ->
- {AddedDiffContent, NewQueryState} =
- handle_character_instance_moving(QueryState, Input),
- play
- (
- (AddedDiffContent ++ DiffUpdate),
- NewQueryState,
- Next,
- Input
- );
-play (DiffUpdate, QueryState, [switch|Next], Input) ->
- {AddedDiffContent, NewQueryState} =
- handle_character_instance_switching_weapons(QueryState, Input),
- play
- (
- (AddedDiffContent ++ DiffUpdate),
- NewQueryState,
- Next,
- Input
- );
-play (DiffUpdate, QueryState, [attack|Next], Input) ->
- {AddedDiffContent, NewQueryState} =
- handle_character_instance_attacking(QueryState, Input),
- play
- (
- (AddedDiffContent ++ DiffUpdate),
- NewQueryState,
- Next,
- Input
- ).
-
--spec send_to_database (query_result(), any(), input()) -> 'ok'.
-send_to_database (QueryResult, _TurnType, Input) ->
+%-spec send_to_database (list(database_diff:struct()), input()) -> 'ok'.
+-spec send_to_database (battle:struct(), input()) -> 'ok'.
+send_to_database (FinalizedBattle, Input) ->
PlayerID = Input#input.player_id,
- BattlemapInstanceID = Input#input.battlemap_instance_id,
- BattlemapInstance = QueryResult#query_result.updated_battlemap_instance,
+ BattleID = Input#input.battle_id,
%% TODO: differential commit
database_shim:commit
(
- battlemap_instance_db,
+ battle_db,
PlayerID,
- BattlemapInstanceID,
- BattlemapInstance
+ BattleID,
+ FinalizedBattle
).
-spec update_cache (query_result(), input()) -> 'ok'.
update_cache (QueryResult, Input) ->
PlayerID = Input#input.player_id,
- BattlemapInstanceID = Input#input.battlemap_instance_id,
- BattlemapInstance = QueryResult#query_result.updated_battlemap_instance,
+ BattleID = Input#input.battle_id,
+ Battle = QueryResult#query_result.updated_battle,
timed_cache:update
(
- battlemap_instance_db,
+ battle_db,
PlayerID,
- BattlemapInstanceID,
- BattlemapInstance
+ BattleID,
+ Battle
).
-spec generate_reply
(
- query_result(),
- list(any()),
- any(),
- input()
+ list(turn_result:struct())
)
-> binary().
-generate_reply (_QueryResult, DiffUpdate, _TurnType, _Input) ->
+generate_reply (ClientUpdate) ->
%% TODO
jiffy:encode
(
[
[
<<"raw">>,
- list_to_binary(io_lib:format("~p", [DiffUpdate]))
+ list_to_binary(io_lib:format("~p", [ClientUpdate]))
]
]
).
@@ -645,22 +295,42 @@ generate_reply (_QueryResult, DiffUpdate, _TurnType, _Input) ->
-spec handle (binary()) -> binary().
handle (Req) ->
Input = parse_input(Req),
- security:assert_identity(Input#input.player_id, Input#input.session_token),
- security:lock_queries(Input#input.player_id),
- QueryState = fetch_data(Input),
- assert_character_instance_can_be_played(QueryState, Input),
- TurnType = get_type_of_turn(Input),
- {DiffUpdate, UpdatedQueryState} = play([], QueryState, TurnType, Input),
- QueryResult =
- finalize_character_turn
+ PlayerID = Input#input.player_id,
+ PlayerSessionToken = Input#input.session_token,
+ Actions = Input#input.actions,
+
+ security:assert_identity(PlayerID, PlayerSessionToken),
+ security:lock_queries(PlayerID),
+
+ RData = fetch_relevant_data(Input),
+
+ assert_character_instance_can_be_played(RData, Input),
+
+ {ActionsDiffUpdate, ClientUpdate, UpdatedRData} =
+ lists:foldl
(
- finalize_character_instance(UpdatedQueryState, Input)
+ fun (Action, Prev) ->
+ battle_action:handle(Action, Prev)
+ end,
+ {[], [], RData},
+ Actions
),
- send_to_database(QueryResult, TurnType, Input),
- update_cache(QueryResult, Input),
+
+ UpdatedBattle = finalize_and_fuse_relevant_data(UpdatedRData, Input),
+
+ {TurnDiffUpdate, FinalizedBattle} = end_of_turn:apply_to(UpdatedBattle),
+
+ DiffUpdate = (TurnDiffUpdate ++ ActionsDiffUpdate),
+
+ %send_to_database(DiffUpdate, Input),
+ send_to_database(FinalizedBattle, Input),
+ update_cache(FinalizedBattle, Input),
+
io:format("~nCharacter turn result:~n~p~n", [DiffUpdate]),
- security:unlock_queries(Input#input.player_id),
- generate_reply(QueryResult, DiffUpdate, TurnType, Input).
+
+ security:unlock_queries(PlayerID),
+
+ generate_reply(ClientUpdate).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%