From 668e1ab70b66a44e40922a29225d2835b03190fa Mon Sep 17 00:00:00 2001 From: nsensfel Date: Mon, 2 Jul 2018 18:06:08 +0200 Subject: Working on player defeats... --- src/battlemap/bm_shim.erl | 14 +-- src/battlemap/game-logic/bm_next_turn.erl | 4 +- src/battlemap/game-logic/bm_turn_actions.erl | 163 ++++++++++++++++++++++++++- src/battlemap/query/bm_character_turn.erl | 8 +- src/battlemap/query/bm_load_state.erl | 15 ++- src/battlemap/reply/bm_add_char.erl | 11 +- src/battlemap/struct/bm_character.erl | 25 ++-- src/shared/util/sh_array_util.erl | 47 ++++++++ 8 files changed, 261 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/battlemap/bm_shim.erl b/src/battlemap/bm_shim.erl index 1ff8ac3..67e82bf 100644 --- a/src/battlemap/bm_shim.erl +++ b/src/battlemap/bm_shim.erl @@ -7,7 +7,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --export([generate_random_battle/0 ]). +-export([generate_random_battle/0]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -37,7 +37,7 @@ generate_random_characters Result; generate_random_characters ( - MaxPlayerID, + MaxPlayerIX, 0, CharactersPerPlayer, TotalCharacterCount, @@ -47,7 +47,7 @@ generate_random_characters ) -> generate_random_characters ( - (MaxPlayerID - 1), + (MaxPlayerIX - 1), CharactersPerPlayer, CharactersPerPlayer, TotalCharacterCount, @@ -57,7 +57,7 @@ generate_random_characters ); generate_random_characters ( - MaxPlayerID, + MaxPlayerIX, PlayerCharacterCount, CharactersPerPlayer, TotalCharacterCount, @@ -69,20 +69,20 @@ generate_random_characters bm_character:random ( TotalCharacterCount, - list_to_binary(integer_to_list(MaxPlayerID)), + MaxPlayerIX, bm_battlemap:get_width(Battlemap), bm_battlemap:get_height(Battlemap), ForbiddenLocations ), Character = - case MaxPlayerID of + case MaxPlayerIX of 0 -> bm_character:set_is_active(true, NewCharacter); _ -> NewCharacter end, generate_random_characters ( - MaxPlayerID, + MaxPlayerIX, (PlayerCharacterCount - 1), CharactersPerPlayer, (TotalCharacterCount + 1), diff --git a/src/battlemap/game-logic/bm_next_turn.erl b/src/battlemap/game-logic/bm_next_turn.erl index 3cd63b4..56e7f7e 100644 --- a/src/battlemap/game-logic/bm_next_turn.erl +++ b/src/battlemap/game-logic/bm_next_turn.erl @@ -60,14 +60,14 @@ reset_next_player_timeline (Battle) -> -spec activate_next_players_characters (bm_battle:type(), bm_player:type()) -> {bm_battle:type(), list(sh_db_query:op())}. activate_next_players_characters (Battle, NextPlayer) -> - NextPlayerID = bm_player:get_id(NextPlayer), + NextPlayerIX = bm_player:get_index(NextPlayer), Characters = bm_battle:get_characters(Battle), {UpdatedCharacters, ModifiedIXs} = sh_array_util:mapiff ( fun (Character) -> - (bm_character:get_owner_id(Character) == NextPlayerID) + (bm_character:get_player_index(Character) == NextPlayerIX) end, fun (Character) -> bm_character:set_is_active(true, Character) diff --git a/src/battlemap/game-logic/bm_turn_actions.erl b/src/battlemap/game-logic/bm_turn_actions.erl index 87e14aa..2dfcf63 100644 --- a/src/battlemap/game-logic/bm_turn_actions.erl +++ b/src/battlemap/game-logic/bm_turn_actions.erl @@ -16,6 +16,149 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec handle_player_defeat + ( + non_neg_integer(), + bm_character_turn_update:type() + ) + -> bm_character_turn_update:type(). +handle_player_defeat (PlayerIX, Update) -> + Data = bm_character_turn_update:get_data(Update), + Battle = bm_character_turn_data:get_battle(Data), + Characters = bm_battle:get_characters(Battle), + + %% FIXME: The controlled character might slip through. + {UpdatedCharacters, ModifiedIXs} = + sh_array_util:mapiff + ( + fun (Character) -> + (bm_character:get_player_index(Character) == PlayerIX) + end, + fun (Character) -> + bm_character:set_rank(defeated, Character) + end, + Characters + ), + + S1Update = + lists:foldl + ( + fun (NextUpdate, IX) -> + bm_character_turn_update:add_to_db + ( + sh_db_query:update_indexed + ( + bm_battle:get_characters_field(), + IX, + [ + sh_db_query:set_field + ( + bm_character:get_rank_field(), + defeated + ) + ] + ), + NextUpdate + ) + end, + Update, + ModifiedIXs + ), + + %% TODO: Battle.player[PlayerIX].is_active <- false + + UpdatedBattle = bm_battle:set_characters(UpdatedCharacters, Battle), + UpdatedData = bm_character_turn_data:set_battle(UpdatedBattle, Data), + S2Update = bm_character_turn_update:set_data(UpdatedData, S1Update), + + DBQuery = + sh_db_query:update_indexed + ( + bm_battle:get_players_field(), + PlayerIX, + [ + sh_db_query:set_field + ( + bm_character:get_is_active_field(), + false + ) + ] + ), + + S3Update = + bm_character_turn_update:add_to_timeline + ( + bm_turn_result:new_player_lost(PlayerIX), + DBQuery, + S2Update + ), + + S3Update. + +-spec handle_victory_condition + ( + non_neg_integer(), + integer(), + bm_character_turn_update:type() + ) + -> bm_character_turn_update:type(). +handle_victory_condition (_, Health, Update) when (Health > 0) -> Update; +handle_victory_condition (CharIX, _Health, Update) -> + Data = bm_character_turn_update:get_data(Update), + Battle = bm_character_turn_data:get_battle(Data), + Character = bm_battle:get_character(CharIX, Battle), + Characters = bm_battle:get_characters(Battle), + CharacterPlayerIX = bm_character:get_player_index(Character), + + case bm_character:get_rank(Character) of + optional -> + %% Let's not assume there is a commander + StillHasAliveChar = + sh_array_util:any_indexed + ( + fun (IX, Char) -> + ( + (CharacterPlayerIX == bm_character:get_player_index(Char)) + and (IX /= CharIX) + and bm_character:get_is_alive(Char) + ) + end, + %% FIXME: Potential issue if it's the controlled player and Data + %% is dirty. + Characters + ), + + case StillHasAliveChar of + true -> Update; + _ -> handle_player_defeat(CharacterPlayerIX, Update) + end; + + commander -> handle_player_defeat(CharacterPlayerIX, Update); + + target -> + StillHasAliveChar = + sh_array_util:any_indexed + ( + fun (IX, Char) -> + ( + (CharacterPlayerIX == bm_character:get_player_index(Char)) + and (IX /= CharIX) + and bm_character:get_is_alive(Char) + and (bm_character:get_rank(Char) == target) + ) + end, + %% FIXME: Potential issue if it's the controlled player and Data + %% is dirty. + Characters + ), + + case StillHasAliveChar of + true -> Update; + _ -> handle_player_defeat(CharacterPlayerIX, Update) + end; + + defeated -> Update + end. %%%% SWITCHING WEAPON %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -spec handle_switch_weapon @@ -353,7 +496,25 @@ handle_attack (BattleAction, Update) -> S0Update ), - bm_character_turn_update:set_data(S1Data, S1Update). + S2Update = bm_character_turn_update:set_data(S1Data, S1Update), + + S3Update = + handle_victory_condition + ( + CharacterIX, + RemainingAttackerHealth, + S2Update + ), + + S4Update = + handle_victory_condition + ( + TargetIX, + RemainingDefenderHealth, + S3Update + ), + + S4Update. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/battlemap/query/bm_character_turn.erl b/src/battlemap/query/bm_character_turn.erl index 74def12..7a7476c 100644 --- a/src/battlemap/query/bm_character_turn.erl +++ b/src/battlemap/query/bm_character_turn.erl @@ -73,10 +73,14 @@ assert_user_is_current_player (Data, Request) -> ) -> 'ok'. assert_user_owns_played_character (Data, Request) -> PlayerID = bm_character_turn_request:get_player_id(Request), + Battle = bm_character_turn_data:get_battle(Data), + Players = bm_battle:get_players(Battle), Character = bm_character_turn_data:get_character(Data), - CharacterOwnerID = bm_character:get_owner_id(Character), + CharacterPlayerIX = bm_character:get_player_index(Character), + CharacterPlayer = array:get(CharacterPlayerIX, Players), + CharacterPlayerID = bm_player:get_id(CharacterPlayer), - true = (PlayerID == CharacterOwnerID), + true = (PlayerID == CharacterPlayerID), ok. diff --git a/src/battlemap/query/bm_load_state.erl b/src/battlemap/query/bm_load_state.erl index 4b5b3ab..505ec3b 100644 --- a/src/battlemap/query/bm_load_state.erl +++ b/src/battlemap/query/bm_load_state.erl @@ -64,6 +64,19 @@ fetch_data (Input) -> generate_reply (QueryState, Input) -> PlayerID = Input#input.player_id, Battle = QueryState#query_state.battle, + Players = bm_battle:get_players(Battle), + + PlayerIX = + sh_array_util:first + ( + fun (Player) -> + (bm_player:get_id(Player) == PlayerID) + end, + Players + ), + + true = (PlayerIX >= 0), + SetTimeline = bm_set_timeline:generate ( @@ -78,7 +91,7 @@ generate_reply (QueryState, Input) -> array:map ( fun (IX, Character) -> - bm_add_char:generate(IX, Character, PlayerID) + bm_add_char:generate(IX, Character, PlayerIX) end, bm_battle:get_characters(Battle) ) diff --git a/src/battlemap/reply/bm_add_char.erl b/src/battlemap/reply/bm_add_char.erl index 0fbaf82..d37c06e 100644 --- a/src/battlemap/reply/bm_add_char.erl +++ b/src/battlemap/reply/bm_add_char.erl @@ -44,13 +44,13 @@ attributes_as_json (Attributes) -> ( non_neg_integer(), bm_character:type(), - bm_player:id() + non_neg_integer() ) -> {list(any())}. -generate (IX, Character, PlayerID) -> +generate (IX, Character, PlayerIX) -> Attributes = bm_character:get_attributes(Character), {ActiveWeapon, SecondaryWeapon} = bm_character:get_weapon_ids(Character), - OwnerID = bm_character:get_owner_id(Character), + CharacterPlayerIX = bm_character:get_player_index(Character), Location = bm_character:get_location(Character), { @@ -66,13 +66,12 @@ generate (IX, Character, PlayerID) -> bm_character:get_current_health(Character) }, {<<"lc">>, bm_location:encode(Location)}, - {<<"pla">>, OwnerID}, + {<<"pla">>, CharacterPlayerIX}, { <<"ena">>, ( bm_character:get_is_active(Character) - and - (OwnerID == PlayerID) + and (CharacterPlayerIX == PlayerIX) ) }, {<<"att">>, attributes_as_json(Attributes)}, diff --git a/src/battlemap/struct/bm_character.erl b/src/battlemap/struct/bm_character.erl index 45b2361..7dec927 100644 --- a/src/battlemap/struct/bm_character.erl +++ b/src/battlemap/struct/bm_character.erl @@ -11,7 +11,7 @@ character, { id :: id(), - owner_id :: bm_player:id(), + player_ix :: non_neg_integer(), name :: binary(), rank :: rank(), icon :: binary(), @@ -37,7 +37,7 @@ ( [ get_id/1, - get_owner_id/1, + get_player_index/1, get_name/1, get_rank/1, get_icon/1, @@ -51,6 +51,7 @@ get_is_alive/1, get_is_active/1, + set_rank/2, set_weapon_ids/2, set_armor_id/2, set_statistics/2, @@ -58,6 +59,7 @@ set_current_health/2, set_is_active/2, + get_rank_field/0, get_statistics_field/0, get_weapons_field/0, get_location_field/0, @@ -108,8 +110,8 @@ find_random_location (BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> -spec get_id (type()) -> id(). get_id (Char) -> Char#character.id. --spec get_owner_id (type()) -> bm_player:id(). -get_owner_id (Char) -> Char#character.owner_id. +-spec get_player_index (type()) -> non_neg_integer(). +get_player_index (Char) -> Char#character.player_ix. -spec get_name (type()) -> binary(). get_name (Char) -> Char#character.name. @@ -153,6 +155,13 @@ get_is_active (Char) -> and get_is_alive(Char) ). +-spec set_rank (rank(), type()) -> type(). +set_rank (Rank, Char) -> + Char#character + { + rank = Rank + }. + -spec set_location ( {non_neg_integer(), non_neg_integer()}, @@ -209,13 +218,13 @@ set_statistics (Stats, Char) -> -spec random ( non_neg_integer(), - bm_player:id(), + non_neg_integer(), non_neg_integer(), non_neg_integer(), list({non_neg_integer(), non_neg_integer()}) ) -> type(). -random (ID, OwnerID, BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> +random (ID, PlayerIX, BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> Location = find_random_location(BattlemapWidth, BattlemapHeight, ForbiddenLocations), WeaponIDs = {sh_weapon:random_id(), sh_weapon:random_id()}, @@ -228,7 +237,7 @@ random (ID, OwnerID, BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> #character { id = ID, - owner_id = OwnerID, + player_ix = PlayerIX, name = list_to_binary("Char" ++ IDAsListString), rank = if @@ -246,6 +255,8 @@ random (ID, OwnerID, BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> is_active = false }. +-spec get_rank_field() -> non_neg_integer(). +get_rank_field () -> #character.rank. -spec get_statistics_field() -> non_neg_integer(). get_statistics_field () -> #character.statistics. -spec get_weapons_field() -> non_neg_integer(). diff --git a/src/shared/util/sh_array_util.erl b/src/shared/util/sh_array_util.erl index 5f58b36..6d976bc 100644 --- a/src/shared/util/sh_array_util.erl +++ b/src/shared/util/sh_array_util.erl @@ -10,9 +10,12 @@ ( [ any/2, + any_indexed/2, none/2, all/2, + first/2, + mapiff/3 ] ). @@ -35,6 +38,38 @@ any_internals (Fun, Array, PrevIX) -> _ -> any_internals(Fun, Array, IX) end. +-spec first_internals + ( + fun((any()) -> boolean()), + array:array(any()), + non_neg_integer() + ) + -> integer(). +first_internals (_, _, 0) -> + -1; +first_internals (Fun, Array, PrevIX) -> + IX = (PrevIX - 1), + case Fun(array:get(IX, Array)) of + true -> IX; + _ -> first_internals(Fun, Array, IX) + end. + +-spec any_indexed_internals + ( + fun((non_neg_integer(), any()) -> boolean()), + array:array(any()), + non_neg_integer() + ) + -> boolean(). +any_indexed_internals (_, _, 0) -> + false; +any_indexed_internals (Fun, Array, PrevIX) -> + IX = (PrevIX - 1), + case Fun(IX, array:get(IX, Array)) of + true -> true; + _ -> any_indexed_internals(Fun, Array, IX) + end. + -spec all_internals ( fun((any()) -> boolean()), @@ -86,6 +121,18 @@ mapiff_internals (Cond, Map, Array, IXList, PrevIX) -> any (Fun, Array) -> any_internals(Fun, Array, array:size(Array)). +-spec first (fun((any()) -> boolean()), array:array(any())) -> integer(). +first (Fun, Array) -> + first_internals(Fun, Array, array:size(Array)). + +-spec any_indexed + ( + fun((non_neg_integer(), any()) -> boolean()), + array:array(any()) + ) -> boolean(). +any_indexed (Fun, Array) -> + any_indexed_internals(Fun, Array, array:size(Array)). + -spec all (fun((any()) -> boolean()), array:array(any())) -> boolean(). all (Fun, Array) -> all_internals(Fun, Array, array:size(Array)). -- cgit v1.2.3-70-g09d2