| summaryrefslogtreecommitdiff | 
diff options
| author | nsensfel <SpamShield0@noot-noot.org> | 2018-06-06 15:54:18 +0200 | 
|---|---|---|
| committer | nsensfel <SpamShield0@noot-noot.org> | 2018-06-06 15:54:18 +0200 | 
| commit | ee9c2ac044cc77b80f30420c8f0788cad4281084 (patch) | |
| tree | 6ce9c45b6c0f0c556839b6f462f84eab06e26594 /src/battlemap/struct | |
| parent | 97f7511e61cebae3676a83aa9c0dc2efb15d8d8c (diff) | |
Figuring out how to organize the src folder(s)...
Diffstat (limited to 'src/battlemap/struct')
| -rw-r--r-- | src/battlemap/struct/bm_attack.erl | 300 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_battle.erl | 197 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_battle_action.erl | 114 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_battlemap.erl | 121 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_character.erl | 239 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_character_turn_data.erl | 102 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_character_turn_request.erl | 84 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_character_turn_update.erl | 73 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_direction.erl | 38 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_location.erl | 90 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_player.erl | 72 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_player_turn.erl | 73 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_tile.erl | 47 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_turn_result.erl | 142 | ||||
| -rw-r--r-- | src/battlemap/struct/bm_weapon.erl | 360 | 
15 files changed, 2052 insertions, 0 deletions
| diff --git a/src/battlemap/struct/bm_attack.erl b/src/battlemap/struct/bm_attack.erl new file mode 100644 index 0000000..fe7d8b8 --- /dev/null +++ b/src/battlemap/struct/bm_attack.erl @@ -0,0 +1,300 @@ +-module(bm_attack). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type order() :: ('first' | 'second' | 'counter'). +-type precision() :: ('misses' | 'grazes' | 'hits'). + +-record +( +   attack, +   { +      order :: order(), +      precision :: precision(), +      is_critical :: boolean(), +      is_parry :: boolean(), +      damage :: non_neg_integer() +   } +). + +-opaque type() :: #attack{}. +-type maybe_type() :: ('nothing' | type()). +-opaque step() :: {order(), boolean()}. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0, maybe_type/0, step/0]). + +-export +( +   [ +      get_sequence/3, +      get_description_of/3, +      apply_to_healths/3 +   ] +). + +-export +( +   [ +      encode/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec roll_precision +   ( +      bm_statistics:type(), +      bm_statistics:type() +   ) +   -> precision(). +roll_precision (AttackerStatistics, DefenderStatistics) -> +   DefenderDodges = bm_statistics:get_dodges(DefenderStatistics), +   AttackerAccuracy = bm_statistics:get_accuracy(AttackerStatistics), +   MissChance = max(0, (DefenderDodges - AttackerAccuracy)), +   case sh_roll:percentage() of +      X when (X =< MissChance) -> misses; +      X when (X =< (MissChance * 2)) -> grazes; +      _ -> hits +   end. + +-spec roll_damage +   ( +      bm_statistics:type(), +      bm_statistics:type() +   ) +   -> {non_neg_integer(), boolean()}. +roll_damage (AttackerStatistics, _DefenderStatistics) -> +   {MinimumDamage, MaximumDamage} = +      bm_statistics:get_damages(AttackerStatistics), +   MaximumRoll = max(1, MaximumDamage - MinimumDamage), +   BaseDamage = MinimumDamage + (rand:uniform(MaximumRoll) - 1), +   CriticalHitChance = bm_statistics:get_critical_hits(AttackerStatistics), +   case sh_roll:percentage() of +      X when (X =< CriticalHitChance) -> {(BaseDamage * 2), true}; +      _ -> {BaseDamage, false} +   end. + +-spec roll_parry (bm_statistics:type()) -> boolean(). +roll_parry (DefenderStatistics) -> +   DefenderParryChance = bm_statistics:get_parries(DefenderStatistics), +   (sh_roll:percentage() =< DefenderParryChance). + +-spec effect_of_attack +   ( +      order(), +      bm_statistics:type(), +      bm_statistics:type(), +      boolean() +   ) +   -> type(). +effect_of_attack (Order, AttackerStatistics, DefenderStatistics, CanParry) -> +   ParryIsSuccessful = (CanParry and roll_parry(DefenderStatistics)), +   {ActualAtkStatistics, ActualDefStatistics} = +      case ParryIsSuccessful of +         true -> {DefenderStatistics, AttackerStatistics}; +         false -> {AttackerStatistics, DefenderStatistics} +      end, + +   Precision = roll_precision(ActualAtkStatistics, ActualDefStatistics), +   {Damage, IsCritical} = roll_damage(ActualAtkStatistics, ActualDefStatistics), +   ActualDamage = +      case Precision of +         misses -> 0; +         grazes -> trunc(Damage / 2); +         hits -> Damage +      end, + +   #attack +   { +      order = Order, +      precision = Precision, +      is_critical = IsCritical, +      is_parry = ParryIsSuccessful, +      damage = ActualDamage +   }. + +-spec encode_order (order()) -> binary(). +encode_order (first) -> <<"f">>; +encode_order (counter) -> <<"c">>; +encode_order (second) -> <<"s">>. + +-spec encode_precision (precision()) -> binary(). +encode_precision (hits) -> <<"h">>; +encode_precision (grazes) -> <<"g">>; +encode_precision (misses) -> <<"m">>. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-spec get_description_of +   ( +      step(), +      bm_statistics:type(), +      bm_statistics:type() +   ) +   -> maybe_type(). +get_description_of +( +   {first, CanParry}, +   AttackerStatistics, +   DefenderStatistics +) -> +   effect_of_attack(first, AttackerStatistics, DefenderStatistics, CanParry); +get_description_of +( +   {second, CanParry}, +   AttackerStatistics, +   DefenderStatistics +) -> +   AttackerDoubleAttackChange = +      bm_statistics:get_double_hits(AttackerStatistics), + +   case sh_roll:percentage() of +      X when (X =< AttackerDoubleAttackChange) -> +         effect_of_attack +         ( +            second, +            AttackerStatistics, +            DefenderStatistics, +            CanParry +         ); + +      _ -> +         nothing +   end; +get_description_of +( +   {counter, CanParry}, +   AttackerStatistics, +   DefenderStatistics +) -> +   effect_of_attack(counter, DefenderStatistics, AttackerStatistics, CanParry). + +-spec apply_to_healths +   ( +      maybe_type(), +      non_neg_integer(), +      non_neg_integer() +   ) +   -> {maybe_type(), non_neg_integer(), non_neg_integer()}. +apply_to_healths +( +   nothing, +   AttackerHealth, +   DefenderHealth +) -> +   {nothing, AttackerHealth, DefenderHealth}; +apply_to_healths +( +   Attack, +   AttackerHealth, +   DefenderHealth +) +when +( +   (Attack#attack.order == first) +   or (Attack#attack.order == second) +   or ((Attack#attack.order == counter) and Attack#attack.is_parry) +) -> +   Damage = Attack#attack.damage, + +   case AttackerHealth of +      0 -> +         {nothing, AttackerHealth, DefenderHealth}; + +      _ -> +         { +            Attack, +            AttackerHealth, +            max(0, (DefenderHealth - Damage)) +         } +   end; +apply_to_healths +( +   Attack, +   AttackerHealth, +   DefenderHealth +) +when +( +   (Attack#attack.order == counter) +   or +   ( +      (Attack#attack.is_parry) +      and ((Attack#attack.order == first) or (Attack#attack.order == second)) +   ) +) -> +   Damage = Attack#attack.damage, + +   case DefenderHealth of +      0 -> +         {nothing, AttackerHealth, DefenderHealth}; + +      _ -> +         { +            Attack, +            max(0, (AttackerHealth - Damage)), +            DefenderHealth +         } +   end. + +-spec get_sequence +   ( +      non_neg_integer(), +      bm_weapon:type(), +      bm_weapon:type() +   ) +   -> list(step()). +get_sequence (AttackRange, AttackerWeapon, DefenderWeapon) -> +   {AttackerDefenseRange, AttackerAttackRange} = +      bm_weapon:get_ranges(AttackerWeapon), +   {DefenderDefenseRange, DefenderAttackRange} = +      bm_weapon:get_ranges(DefenderWeapon), + +   AttackerCanAttack = (AttackRange =< AttackerAttackRange), +   AttackerCanAttack = true, +   AttackerCanDefend = +      (AttackerCanAttack and (AttackRange > AttackerDefenseRange)), +   AttackerCanParry = +      (AttackerCanDefend and weapon:can_parry(AttackerWeapon)), + +   DefenderCanAttack = (AttackRange =< DefenderAttackRange), +   DefenderCanDefend = +      (DefenderCanAttack and (AttackRange > DefenderDefenseRange)), +   DefenderCanParry = +      (DefenderCanDefend and weapon:can_parry(DefenderWeapon)), + +   First = {first, DefenderCanParry}, +   Second = {second, DefenderCanParry}, +   Counter = {counter, AttackerCanParry}, + +   if +      (not DefenderCanDefend) -> +         [First, Second]; + +      true -> +         [First, Counter, Second] +   end. + +-spec encode (type()) -> {list(any())}. +encode (Attack) -> +   Order = Attack#attack.order, +   Precision = Attack#attack.precision, +   IsCritical = Attack#attack.is_critical, +   IsParry = Attack#attack.is_parry, +   Damage = Attack#attack.damage, + +   { +      [ +         {<<"ord">>, encode_order(Order)}, +         {<<"pre">>, encode_precision(Precision)}, +         {<<"cri">>, IsCritical}, +         {<<"par">>, IsParry}, +         {<<"dmg">>, Damage} +      ] +   }. diff --git a/src/battlemap/struct/bm_battle.erl b/src/battlemap/struct/bm_battle.erl new file mode 100644 index 0000000..08c4943 --- /dev/null +++ b/src/battlemap/struct/bm_battle.erl @@ -0,0 +1,197 @@ +-module(bm_battle). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type id() :: binary(). + +-record +( +   battle, +   { +      id :: id(), +      battlemap :: bm_battlemap:type(), +      characters :: array:array(bm_character:type()), +      players :: array:array(bm_player:type()), +      current_player_turn :: bm_player_turn:type() +   } +). + +-opaque type() :: #battle{}. + +-export_type([type/0, id/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-export +( +   [ +      get_id/1, +      get_battlemap/1, +      get_characters/1, +      get_character/2, +      get_players/1, +      get_player/2, +      get_current_player_turn/1, +      get_encoded_last_turns_effects/1, + +      set_battlemap/2, +      set_characters/2, +      set_character/3, +      set_players/2, +      set_player/3, +      set_current_player_turn/2, + +      get_characters_field/0, +      get_players_field/0, +      get_current_player_turn_field/0 +   ] +). + +-export +( +   [ +      new/4 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +get_all_timelines (Result, CurrentIndex, EndPoint, ArraySize, Players) -> +   Player = array:get(CurrentIndex, Players), +   Timeline = bm_player:get_timeline(Player), +   NextIndex = ((CurrentIndex + 1) rem ArraySize), +   NextResult = (Timeline ++ Result), +   case CurrentIndex of +      EndPoint -> +         NextResult; + +      _ -> +         get_all_timelines(NextResult, NextIndex, EndPoint, ArraySize, Players) +   end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-spec get_id (type()) -> id(). +get_id (Battle) -> Battle#battle.id. + +-spec get_battlemap (type()) -> bm_battlemap:type(). +get_battlemap (Battle) -> +   Battle#battle.battlemap. + +-spec get_characters (type()) -> array:array(bm_character:type()). +get_characters (Battle) -> +   Battle#battle.characters. + +-spec get_character (non_neg_integer(), type()) -> bm_character:type(). +get_character (IX, Battle) -> +   array:get(IX, Battle#battle.characters). + +-spec get_players (type()) -> array:array(bm_player:type()). +get_players (Battle) -> +   Battle#battle.players. + +-spec get_player (non_neg_integer(), type()) -> bm_player:type(). +get_player (IX, Battle) -> +   array:get(IX, Battle#battle.players). + +-spec get_current_player_turn (type()) -> bm_player_turn:type(). +get_current_player_turn (Battle) -> +   Battle#battle.current_player_turn. + +-spec get_encoded_last_turns_effects (type()) -> list(any()). +get_encoded_last_turns_effects (Battle) -> +   CurrentPlayerTurn = Battle#battle.current_player_turn, +   Players = Battle#battle.players, +   CurrentPlayerIX = bm_player_turn:get_player_ix(CurrentPlayerTurn), + +   PlayersCount = array:size(Players), +   StartingPoint = ((CurrentPlayerIX + 1) rem PlayersCount), +   get_all_timelines([], StartingPoint, CurrentPlayerIX, PlayersCount, Players). + +-spec set_battlemap (bm_battlemap:type(), type()) -> type(). +set_battlemap (Battlemap, Battle) -> +   Battle#battle +   { +      battlemap = Battlemap +   }. + +-spec set_characters (array:array(bm_character:type()), type()) -> type(). +set_characters (Characters, Battle) -> +   Battle#battle +   { +      characters = Characters +   }. + +-spec set_character (non_neg_integer(), bm_character:type(), type()) -> type(). +set_character (IX, Character, Battle) -> +   Battle#battle +   { +      characters = +         array:set +         ( +            IX, +            Character, +            Battle#battle.characters +         ) +   }. + +-spec set_players (array:array(bm_player:type()), type()) -> type(). +set_players (Players, Battle) -> +   Battle#battle +   { +      players = Players +   }. + +-spec set_player (non_neg_integer(), bm_player:type(), type()) -> type(). +set_player (IX, Player, Battle) -> +   Battle#battle +   { +      players = +         array:set +         ( +            IX, +            Player, +            Battle#battle.players +         ) +   }. + +-spec set_current_player_turn (bm_player_turn:type(), type()) -> type(). +set_current_player_turn (PlayerTurn, Battle) -> +   Battle#battle +   { +      current_player_turn = PlayerTurn +   }. + +-spec new +   ( +      id(), +      list(bm_player:type()), +      bm_battlemap:type(), +      list(bm_character:type()) +   ) +   -> type(). +new (ID, PlayersAsList, Battlemap, CharactersAsList) -> +   #battle +   { +      id = ID, +      battlemap = Battlemap, +      characters = array:from_list(CharactersAsList), +      players = array:from_list(PlayersAsList), +      current_player_turn = bm_player_turn:new(0, 0) +   }. + + +-spec get_characters_field () -> non_neg_integer(). +get_characters_field () -> #battle.characters. + +-spec get_players_field () -> non_neg_integer(). +get_players_field () -> #battle.players. + +-spec get_current_player_turn_field () -> non_neg_integer(). +get_current_player_turn_field () -> #battle.current_player_turn. diff --git a/src/battlemap/struct/bm_battle_action.erl b/src/battlemap/struct/bm_battle_action.erl new file mode 100644 index 0000000..abdc1c6 --- /dev/null +++ b/src/battlemap/struct/bm_battle_action.erl @@ -0,0 +1,114 @@ +-module(bm_battle_action). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   move, +   { +      path :: list(bm_direction:enum()) +   } +). + +-record +( +   switch_weapon, +   { +   } +). + +-record +( +   attack, +   { +      target_ix :: non_neg_integer() +   } +). + +-type category() :: ('move' | 'switch_weapon' | 'attack' | 'nothing'). +-opaque type() :: (#move{} | #switch_weapon{} | #attack{}). + +-export_type([category/0, type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      decode/1, +      can_follow/2 +   ] +). + +-export +( +   [ +      get_path/1, +      get_target_ix/1, +      get_category/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec decode_mov_action (map()) -> type(). +decode_mov_action (JSONMap) -> +   PathInBinary = maps:get(<<"p">>, JSONMap), +   Path = lists:map(fun bm_direction:decode/1, PathInBinary), + +   #move { path = Path }. + +-spec decode_atk_action (map()) -> type(). +decode_atk_action (JSONMap) -> +   TargetIX = binary_to_integer(maps:get(<<"tix">>, JSONMap)), + +   #attack { target_ix = TargetIX }. + +-spec decode_swp_action (map()) -> type(). +decode_swp_action (_JSONMap) -> +   #switch_weapon{}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec decode (map()) -> type(). +decode (EncodedAction) -> +   JSONActionMap = EncodedAction, %jiffy:decode(EncodedAction, [return_maps]), +   ActionType = maps:get(<<"t">>, JSONActionMap), +   case ActionType of +      <<"mov">> -> decode_mov_action(JSONActionMap); +      <<"atk">> -> decode_atk_action(JSONActionMap); +      <<"swp">> -> decode_swp_action(JSONActionMap) +   end. + +-spec can_follow (category(), category()) -> boolean(). +can_follow (nothing, attack) -> true; +can_follow (nothing, switch_weapon) -> true; +can_follow (nothing, move) -> true; +can_follow (switch_weapon, attack) -> true; +can_follow (move, attack) -> true; +can_follow (_, _) -> false. + +-spec get_path (type()) -> list(direction:type()). +get_path (Action) when is_record(Action, move) -> +   Action#move.path; +get_path (_) -> +   []. + +-spec get_target_ix (type()) -> non_neg_integer(). +get_target_ix (Action) when is_record(Action, attack) -> +   Action#attack.target_ix; +get_target_ix (_) -> +   []. + +-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) -> +   io:format("How'd you get there?~p~n", [Action]), +   true = Action. + diff --git a/src/battlemap/struct/bm_battlemap.erl b/src/battlemap/struct/bm_battlemap.erl new file mode 100644 index 0000000..c3eabb0 --- /dev/null +++ b/src/battlemap/struct/bm_battlemap.erl @@ -0,0 +1,121 @@ +-module(bm_battlemap). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type id() :: binary(). + +-record +( +   battlemap, +   { +      id :: id(), +      width :: integer(), +      height :: integer(), +      tile_ids :: array:array(bm_tile:id()) +   } +). + +-opaque type() :: #battlemap{}. + +-export_type([type/0, id/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-export +( +   [ +      get_id/1, +      get_width/1, +      get_height/1, +      get_tile_ids/1, +      get_tile_id/2 +   ] +). + +-export +( +   [ +      random/3 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec generate_random_tile_ids +   ( +      bm_tile:id(), +      list(bm_tile:id()), +      non_neg_integer(), +      non_neg_integer(), +      non_neg_integer() +   ) +   -> list(bm_tile:id()). +generate_random_tile_ids (_PreviousTileID, Result, _X, 0, _Width) -> +   Result; +generate_random_tile_ids (PreviousTileID, Result, 0, Y, Width) -> +   generate_random_tile_ids(PreviousTileID, Result, Width, (Y - 1), Width); +generate_random_tile_ids (PreviousTileID, Result, X, Y, Width) -> +   NewTile = +      case sh_roll:percentage() of +         N when (N >= 10) -> PreviousTileID; +         _ -> bm_tile:random_id() +      end, +   generate_random_tile_ids(NewTile, [NewTile|Result], (X - 1), Y, Width). + +-spec location_to_array_index +   ( +      non_neg_integer(), +      bm_location:type() +   ) +   -> ('error' | non_neg_integer()). +location_to_array_index (ArrayWidth, {X, Y}) -> +   if +      (X < 0) -> error; +      (Y < 0) -> error; +      (X >= ArrayWidth) -> error; +      true -> ((Y * ArrayWidth) + X) +   end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-spec get_id (type()) -> id(). +get_id (Battlemap) -> Battlemap#battlemap.id. + +-spec get_width (type()) -> integer(). +get_width (Battlemap) -> Battlemap#battlemap.width. + +-spec get_height (type()) -> integer(). +get_height (Battlemap) -> Battlemap#battlemap.height. + +-spec get_tile_ids (type()) -> array:array(bm_tile:id()). +get_tile_ids (Battlemap) -> Battlemap#battlemap.tile_ids. + +-spec get_tile_id (bm_location:type(), type()) -> bm_tile:id(). +get_tile_id (Location, Battlemap) -> +   TileIX = location_to_array_index(Battlemap#battlemap.width, Location), +   array:get(TileIX, Battlemap#battlemap.tile_ids). + +-spec random +   ( +      non_neg_integer(), +      non_neg_integer(), +      non_neg_integer() +   ) +   -> type(). +random (ID, Width, Height) -> +   InitialTile = bm_tile:random_id(), +   TileIDs = generate_random_tile_ids(InitialTile, [], Width, Height, Width), + +   #battlemap +   { +      id = list_to_binary(integer_to_list(ID)), +      width = Width, +      height = Height, +      tile_ids = array:from_list(TileIDs) +   }. diff --git a/src/battlemap/struct/bm_character.erl b/src/battlemap/struct/bm_character.erl new file mode 100644 index 0000000..e797b74 --- /dev/null +++ b/src/battlemap/struct/bm_character.erl @@ -0,0 +1,239 @@ +-module(bm_character). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type id() :: non_neg_integer(). + +-record +( +   character, +   { +      id :: id(), +      owner_id :: bm_player:id(), +      name :: binary(), +      icon :: binary(), +      portrait :: binary(), +      attributes :: sh_attributes:type(), +      statistics :: bm_statistics:type(), +      weapon_ids :: {bm_weapon:id(), bm_weapon:id()}, +      location :: {non_neg_integer(), non_neg_integer()}, +      current_health :: non_neg_integer(), +      active :: boolean() +   } +). + +-opaque type() :: #character{}. + +-export_type([type/0, id/0]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-export +( +   [ +      get_id/1, +      get_owner_id/1, +      get_name/1, +      get_icon/1, +      get_portrait/1, +      get_attributes/1, +      get_statistics/1, +      get_weapon_ids/1, +      get_location/1, +      get_current_health/1, +      get_is_alive/1, +      get_is_active/1, + +      set_weapon_ids/2, +      set_statistics/2, +      set_location/2, +      set_current_health/2, +      set_is_active/2, + +      get_statistics_field/0, +      get_weapons_field/0, +      get_location_field/0, +      get_current_health_field/0, +      get_active_field/0 +   ] +). + +-export +( +   [ +      random/5 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec find_random_location +   ( +      non_neg_integer(), +      non_neg_integer(), +      list({non_neg_integer(), non_neg_integer()}) +   ) +   -> {non_neg_integer(), non_neg_integer()}. +find_random_location (BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> +   X = roll:between(0, (BattlemapWidth - 1)), +   Y = roll:between(0, (BattlemapHeight - 1)), + +   IsForbidden = lists:member({X, Y}, ForbiddenLocations), + +   case IsForbidden of +      true -> +         find_random_location +         ( +            BattlemapWidth, +            BattlemapHeight, +            ForbiddenLocations +         ); + +      _ -> {X, Y} +   end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-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_name (type()) -> binary(). +get_name (Char) -> Char#character.name. + +-spec get_icon (type()) -> binary(). +get_icon (Char) -> Char#character.icon. + +-spec get_portrait (type()) -> binary(). +get_portrait (Char) -> Char#character.portrait. + +-spec get_attributes (type()) -> sh_attributes:type(). +get_attributes (Char) -> Char#character.attributes. + +-spec get_weapon_ids (type()) -> {bm_weapon:id(), bm_weapon:id()}. +get_weapon_ids (Char) -> Char#character.weapon_ids. + +-spec get_statistics (type()) -> bm_statistics:type(). +get_statistics (Char) -> Char#character.statistics. + +-spec get_location (type()) -> {non_neg_integer(), non_neg_integer()}. +get_location (Char) -> +   true = get_is_alive(Char), +   Char#character.location. + +-spec get_current_health (type()) -> non_neg_integer(). +get_current_health (Char) -> Char#character.current_health. + +-spec get_is_alive (type()) -> boolean(). +get_is_alive (Char) -> +   (Char#character.current_health > 0). + +-spec get_is_active (type()) -> boolean(). +get_is_active (Char) -> +   ( +      Char#character.active +      and +      get_is_alive(Char) +   ). + +-spec set_location +   ( +      {non_neg_integer(), non_neg_integer()}, +      type() +   ) +   -> type(). +set_location (Location, Char) -> +   Char#character +   { +      location = Location +   }. + +-spec set_current_health (non_neg_integer(), type()) -> type(). +set_current_health (Health, Char) -> +   Char#character +   { +      current_health = max(0, Health) +   }. + +-spec set_is_active (boolean(), type()) -> type(). +set_is_active (Active, Char) -> +   Char#character +   { +      active = Active +   }. + +-spec set_weapon_ids +   ( +      {bm_weapon:id(), bm_weapon:id()}, +      type() +   ) +   -> type(). +set_weapon_ids (WeaponIDs, Char) -> +   Char#character +   { +      weapon_ids = WeaponIDs +   }. + +-spec set_statistics +   ( +      bm_statistics:type(), +      type() +   ) +   -> type(). +set_statistics (Stats, Char) -> +   Char#character +   { +      statistics = Stats +   }. + +%%%% Utils +-spec random +   ( +      non_neg_integer(), +      bm_player:id(), +      non_neg_integer(), +      non_neg_integer(), +      list({non_neg_integer(), non_neg_integer()}) +   ) +   -> type(). +random (ID, OwnerID, BattlemapWidth, BattlemapHeight, ForbiddenLocations) -> +   Location = +      find_random_location(BattlemapWidth, BattlemapHeight, ForbiddenLocations), +   WeaponIDs = {bm_weapon:random_id(), bm_weapon:random_id()}, +   Attributes = sh_attributes:random(), +   Statistics = bm_statistics:new(Attributes, WeaponIDs), +   IDAsListString = integer_to_list(ID), +   IDAsBinaryString = list_to_binary(IDAsListString), + +   #character +   { +      id = ID, +      owner_id = OwnerID, +      name = list_to_binary("Char" ++ IDAsListString), +      icon = IDAsBinaryString, +      portrait = IDAsBinaryString, +      attributes = Attributes, +      weapon_ids = WeaponIDs, +      statistics = Statistics, +      location = Location, +      current_health = bm_statistics:get_health(Statistics), +      active = false +   }. + +-spec get_statistics_field() -> non_neg_integer(). +get_statistics_field () -> #character.statistics. +-spec get_weapons_field() -> non_neg_integer(). +get_weapons_field () -> #character.weapon_ids. +-spec get_location_field() -> non_neg_integer(). +get_location_field () -> #character.location. +-spec get_current_health_field() -> non_neg_integer(). +get_current_health_field () -> #character.current_health. +-spec get_active_field() -> non_neg_integer(). +get_active_field () -> #character.active. diff --git a/src/battlemap/struct/bm_character_turn_data.erl b/src/battlemap/struct/bm_character_turn_data.erl new file mode 100644 index 0000000..aaf7426 --- /dev/null +++ b/src/battlemap/struct/bm_character_turn_data.erl @@ -0,0 +1,102 @@ +-module(bm_character_turn_data). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   type, +   { +      dirty :: boolean(), +      battle :: bm_battle:type(), +      character :: bm_character:type(), +      character_ix :: non_neg_integer() +   } +). + +-opaque type() :: #type{}. + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      new/2, + +      get_battle_is_dirty/1, +      get_battle/1, +      get_character/1, +      get_character_ix/1, + +      set_battle/2, +      set_character/2 +   ] +). + +-export +( +   [ +      clean_battle/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec new (bm_battle:type(), non_neg_integer()) -> type(). +new (Battle, CharacterIX) -> +   Character = bm_battle:get_character(CharacterIX, Battle), + +   #type +   { +      dirty = false, +      battle = Battle, +      character = Character, +      character_ix = CharacterIX +   }. + +-spec get_battle_is_dirty (type()) -> boolean(). +get_battle_is_dirty (Data) -> Data#type.dirty. + +-spec get_battle (type()) -> bm_battle:type(). +get_battle (Data) -> Data#type.battle. + +-spec get_character (type()) -> bm_character:type(). +get_character (Data) -> Data#type.character. + +-spec get_character_ix (type()) -> non_neg_integer(). +get_character_ix (Data) -> Data#type.character_ix. + +-spec set_battle (bm_battle:type(), type()) -> type(). +set_battle (Battle, Data) -> +   Data#type{ battle = Battle }. + +-spec set_character (bm_character:type(), type()) -> type(). +set_character (Character, Data) -> +   Data#type +   { +      dirty = true, +      character = Character +   }. + +-spec clean_battle (type()) -> type(). +clean_battle (Data) -> +   Data#type +   { +      dirty = false, +      battle = +         bm_battle:set_character +         ( +            Data#type.character_ix, +            Data#type.character, +            Data#type.battle +         ) +   }. + diff --git a/src/battlemap/struct/bm_character_turn_request.erl b/src/battlemap/struct/bm_character_turn_request.erl new file mode 100644 index 0000000..d141d7e --- /dev/null +++ b/src/battlemap/struct/bm_character_turn_request.erl @@ -0,0 +1,84 @@ +-module(bm_character_turn_request). + +-define(PLAYER_ID_FIELD, <<"pid">>). +-define(SESSION_TOKEN_FIELD, <<"stk">>). +-define(BATTLE_ID_FIELD, <<"bid">>). +-define(CHAR_IX_FIELD, <<"cix">>). +-define(ACTIONS_FIELD, <<"act">>). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   type, +   { +      player_id :: bm_player:id(), +      session_token :: binary(), +      battle_id :: binary(), +      character_ix :: non_neg_integer(), +      actions :: list(bm_battle_action:type()) +   } +). + +-opaque type() :: #type{}. + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      decode/1 +   ] +). + +-export +( +   [ +      get_player_id/1, +      get_session_token/1, +      get_battle_id/1, +      get_character_ix/1, +      get_actions/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec decode (map()) -> type(). +decode (Map) -> +   CharacterIX = binary_to_integer(maps:get(?CHAR_IX_FIELD, Map)), +   EncodedActions = maps:get(?ACTIONS_FIELD, Map), +   Actions = lists:map(fun bm_battle_action:decode/1, EncodedActions), + +   #type +   { +      player_id = maps:get(?PLAYER_ID_FIELD, Map), +      session_token = maps:get(?SESSION_TOKEN_FIELD, Map), +      battle_id = maps:get(?BATTLE_ID_FIELD, Map), +      character_ix = CharacterIX, +      actions = Actions +   }. + +-spec get_player_id (type()) -> player:id(). +get_player_id (Request) -> Request#type.player_id. + +-spec get_session_token (type()) -> binary(). +get_session_token (Request) -> Request#type.session_token. + +-spec get_battle_id (type()) -> binary(). +get_battle_id (Request) -> Request#type.battle_id. + +-spec get_character_ix (type()) -> non_neg_integer(). +get_character_ix (Request) -> Request#type.character_ix. + +-spec get_actions (type()) -> list(bm_battle_action:type()). +get_actions (Request) -> Request#type.actions. diff --git a/src/battlemap/struct/bm_character_turn_update.erl b/src/battlemap/struct/bm_character_turn_update.erl new file mode 100644 index 0000000..078075c --- /dev/null +++ b/src/battlemap/struct/bm_character_turn_update.erl @@ -0,0 +1,73 @@ +-module(bm_character_turn_update). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   type, +   { +      data :: bm_character_turn_data:type(), +      timeline :: list(any()), +      db :: list(sh_db_query:op()) +   } +). + +-opaque type() :: #type{}. + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      new/1, + +      get_data/1, +      get_timeline/1, +      get_db/1, + +      set_data/2, +      add_to_timeline/2, +      add_to_db/2 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec new (bm_character_turn_data:type()) -> type(). +new (Data) -> +   #type +   { +      data = Data, +      timeline = [], +      db = [] +   }. + +-spec get_data (type()) -> bm_character_turn_data:type(). +get_data (Update) -> Update#type.data. + +-spec get_timeline (type()) -> list(any()). +get_timeline (Update) -> Update#type.timeline. + +-spec get_db (type()) -> list(sh_db_query:op()). +get_db (Update) -> Update#type.db. + +-spec set_data (bm_character_turn_data:type(), type()) -> type(). +set_data (Data, Update) -> +   Update#type{ data = Data}. + +-spec add_to_timeline (bm_turn_result:type(), type()) -> type(). +add_to_timeline (Item, Update) -> +   Update#type{ timeline = [bm_turn_result:encode(Item)|Update#type.timeline] }. + +-spec add_to_db (sh_db_query:op(), type()) -> type(). +add_to_db (Item, Update) -> +   Update#type{ db = [Item|Update#type.db] }. diff --git a/src/battlemap/struct/bm_direction.erl b/src/battlemap/struct/bm_direction.erl new file mode 100644 index 0000000..2da3936 --- /dev/null +++ b/src/battlemap/struct/bm_direction.erl @@ -0,0 +1,38 @@ +-module(bm_direction). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type enum() :: ('up' | 'down' | 'left' | 'right'). +-type type() :: enum(). + +-export_type([enum/0, type/0]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      decode/1, +      encode/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec decode (binary()) -> enum(). +decode (<<"U">>) -> up; +decode (<<"D">>) -> down; +decode (<<"L">>) -> left; +decode (<<"R">>) -> right. + +-spec encode (enum()) -> binary(). +encode (up) -> <<"U">>; +encode (down) -> <<"D">>; +encode (left) -> <<"L">>; +encode (right) -> <<"R">>. diff --git a/src/battlemap/struct/bm_location.erl b/src/battlemap/struct/bm_location.erl new file mode 100644 index 0000000..056d10c --- /dev/null +++ b/src/battlemap/struct/bm_location.erl @@ -0,0 +1,90 @@ +-module(bm_location). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type type() :: ({non_neg_integer(), non_neg_integer()} | 'nowhere'). + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      decode/1, +      encode/1, +      get_nowhere/0 +   ] +). + +-export +( +   [ +      apply_direction/2, +      dist/2 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec validate ({integer(), integer()}) -> type(). +validate ({X, Y}) -> +   if +      (X < 0) -> nowhere; +      (Y < 0) -> nowhere; +      true -> {X, Y} +   end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec get_nowhere () -> type(). +get_nowhere () -> nowhere. + +-spec apply_direction (bm_direction:enum(), type()) -> type(). +apply_direction (left, {X, Y}) -> +   validate({(X - 1), Y}); +apply_direction (right, {X, Y}) -> +   validate({(X + 1), Y}); +apply_direction (up, {X, Y}) -> +   validate({X, (Y - 1)}); +apply_direction (down, {X, Y}) -> +   validate({X, (Y + 1)}); +apply_direction (_, nowhere) -> +   error("Trying to move from 'nowhere'."), +   nowhere. + +-spec dist(type(), type()) -> non_neg_integer(). +dist ({OX, OY}, {DX, DY}) -> +   (abs(DY - OY) + abs(DX - OX)); +dist (_, _) -> +   error("Trying to measure distance to 'nowhere'"), +   999. + +-spec encode (type()) -> {list(any())}. +encode ({X, Y}) -> +   { +      [ +         {<<"x">>, X}, +         {<<"y">>, Y} +      ] +   }; +encode (nowhere) -> +   { +      [ +         {<<"x">>, -1}, +         {<<"y">>, -1} +      ] +   }. + +-spec decode (map()) -> type(). +decode (Map) -> +   X = maps:get(<<"x">>, Map), +   Y = maps:get(<<"y">>, Map), + +   true = (is_integer(X) and is_integer(Y)), + +   validate({X, Y}). diff --git a/src/battlemap/struct/bm_player.erl b/src/battlemap/struct/bm_player.erl new file mode 100644 index 0000000..3f14a6f --- /dev/null +++ b/src/battlemap/struct/bm_player.erl @@ -0,0 +1,72 @@ +-module(bm_player). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-type id() :: binary(). + +-record +( +   player, +   { +      id :: id(), +      timeline :: list(any()) +   } +). + +-opaque type() :: #player{}. + +-export_type([type/0, id/0]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      get_id/1, +      get_timeline/1, +      add_to_timeline/2, +      reset_timeline/1 +   ] +). + +-export +( +   [ +      new/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec get_id (type()) -> id(). +get_id (Player) -> Player#player.id. + +-spec get_timeline (type()) -> list(any()). +get_timeline (Player) -> Player#player.timeline. + +-spec add_to_timeline (list(any()), type()) -> type(). +add_to_timeline (NewEvents, Player) -> +   OldTimeline = Player#player.timeline, + +   Player#player +   { +      timeline = (NewEvents ++ OldTimeline) +   }. + +-spec reset_timeline (type()) -> type(). +reset_timeline (Player) -> Player#player{ timeline = [] }. + +-spec new (id()) -> type(). +new (ID) -> +   #player +   { +      id = ID, +      timeline = [] +   }. + diff --git a/src/battlemap/struct/bm_player_turn.erl b/src/battlemap/struct/bm_player_turn.erl new file mode 100644 index 0000000..5f2c074 --- /dev/null +++ b/src/battlemap/struct/bm_player_turn.erl @@ -0,0 +1,73 @@ +-module(bm_player_turn). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-record +( +   player_turn, +   { +      number :: non_neg_integer(), +      player_ix :: non_neg_integer() +   } +). + +-opaque type() :: #player_turn{}. + +-export_type([type/0]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      new/2, +      next/2 +   ] +). + +%%%% Accessors +-export +( +   [ +      get_number/1, +      get_player_ix/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-spec new (non_neg_integer(), non_neg_integer()) -> type(). +new (Number, PlayerIX) -> +   #player_turn +   { +      number = Number, +      player_ix = PlayerIX +   }. + +-spec get_number (type()) -> non_neg_integer(). +get_number (PlayerTurn) -> PlayerTurn#player_turn.number. + +-spec get_player_ix (type()) -> non_neg_integer(). +get_player_ix (PlayerTurn) -> PlayerTurn#player_turn.player_ix. + +-spec next (non_neg_integer(), type()) -> type(). +next (PlayersCount, CurrentPlayerTurn) -> +   CurrentPlayerIX = CurrentPlayerTurn#player_turn.player_ix, +   CurrentTurnNumber = CurrentPlayerTurn#player_turn.number, + +   NextPlayerIX = ((CurrentPlayerIX + 1) rem PlayersCount), +   NextTurnNumber = +      case NextPlayerIX of +         0 -> (CurrentTurnNumber + 1); +         _ -> CurrentTurnNumber +      end, + +   new(NextTurnNumber, NextPlayerIX). diff --git a/src/battlemap/struct/bm_tile.erl b/src/battlemap/struct/bm_tile.erl new file mode 100644 index 0000000..c1dd448 --- /dev/null +++ b/src/battlemap/struct/bm_tile.erl @@ -0,0 +1,47 @@ +-module(bm_tile). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-opaque id() :: non_neg_integer(). +-opaque type() :: id(). + +-export_type([type/0, id/0]). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export +( +   [ +      get_cost/1, +      cost_when_oob/0 +   ] +). + +-export +( +   [ +      random_id/0 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec cost_when_oob () -> non_neg_integer(). +cost_when_oob () -> 255. + +-spec get_cost (id()) -> non_neg_integer(). +get_cost (N) -> +   if +      (N =< 200) -> (N + 8); +      true -> cost_when_oob() +   end. + +-spec random_id () -> id(). +random_id () -> +   sh_roll:between(0, 15). diff --git a/src/battlemap/struct/bm_turn_result.erl b/src/battlemap/struct/bm_turn_result.erl new file mode 100644 index 0000000..c3440bd --- /dev/null +++ b/src/battlemap/struct/bm_turn_result.erl @@ -0,0 +1,142 @@ +-module(bm_turn_result). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% +-record +( +   switched_weapon, +   { +      character_ix :: bm_character:id() +   } +). + +-record +( +   moved, +   { +      character_ix :: bm_character:id(), +      path :: list(bm_direction:enum()), +      new_location :: bm_location:type() +   } +). + +-record +( +   attacked, +   { +      attacker_ix :: bm_character:id(), +      defender_ix :: bm_character:id(), +      sequence :: list(bm_attack:type()) +   } +). + +-opaque type() :: (#switched_weapon{} | #moved{} | #attacked{}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-export_type([type/0]). + +-export +( +   [ +      new_character_switched_weapons/1, +      new_character_moved/3, +      new_character_attacked/3 +   ] +). + +-export +( +   [ +      encode/1 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec new_character_switched_weapons (bm_character:id()) -> type(). +new_character_switched_weapons (CharacterIX) -> +   #switched_weapon { character_ix = CharacterIX }. + +-spec new_character_moved +   ( +      bm_character:id(), +      list(bm_direction:enum()), +      bm_location:type() +   ) +   -> type(). +new_character_moved (CharacterIX, Path, NewLocation) -> +   #moved +   { +      character_ix = CharacterIX, +      path = Path, +      new_location = NewLocation +   }. + +-spec new_character_attacked +   ( +      bm_character:id(), +      bm_character:id(), +      list(bm_attack:type()) +   ) +   -> type(). +new_character_attacked (AttackerIX, DefenderIX, AttackSequence) -> +   #attacked +   { +      attacker_ix = AttackerIX, +      defender_ix = DefenderIX, +      sequence = AttackSequence +   }. + +-spec encode (type()) -> {list(any())}. +encode (TurnResult) when is_record(TurnResult, switched_weapon) -> +   CharacterIX = TurnResult#switched_weapon.character_ix, + +   { +      [ +         {<<"t">>, <<"swp">>}, +         {<<"ix">>, CharacterIX} +      ] +   }; +encode (TurnResult) when is_record(TurnResult, moved) -> +   CharacterIX = TurnResult#moved.character_ix, +   Path = TurnResult#moved.path, +   NewLocation = TurnResult#moved.new_location, + +   EncodedPath = lists:map(fun bm_direction:encode/1, Path), +   EncodedNewLocation = bm_location:encode(NewLocation), + +   { +      [ +         {<<"t">>, <<"mv">>}, +         {<<"ix">>, CharacterIX}, +         {<<"p">>, EncodedPath}, +         {<<"nlc">>, EncodedNewLocation} +      ] +   }; +encode (TurnResult) when is_record(TurnResult, attacked) -> +   AttackerIX = TurnResult#attacked.attacker_ix, +   DefenderIX = TurnResult#attacked.defender_ix, +   Sequence = TurnResult#attacked.sequence, + +   EncodedSequence = lists:map(fun bm_attack:encode/1, Sequence), + +   { +      [ +         {<<"t">>, <<"atk">>}, +         {<<"aix">>, AttackerIX}, +         {<<"dix">>, DefenderIX}, +         {<<"seq">>, EncodedSequence} +      ] +   }; +encode (Other) -> +   io:format("~n invalid encode param\"~p\"~n", [Other]), +   true = Other. diff --git a/src/battlemap/struct/bm_weapon.erl b/src/battlemap/struct/bm_weapon.erl new file mode 100644 index 0000000..6c05799 --- /dev/null +++ b/src/battlemap/struct/bm_weapon.erl @@ -0,0 +1,360 @@ +-module(bm_weapon). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% TYPES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-opaque id() :: non_neg_integer(). + +-type range_type() :: 'ranged' | 'melee'. +-type range_mod() :: 'long' | 'short'. +-type damage_type() :: 'slash' | 'pierce' | 'blunt'. +-type damage_mod() :: 'heavy' | 'light'. + +-record +( +   weapon, +   { +      id :: id(), +      name :: binary(), +      range_type :: range_type(), +      range_mod :: range_mod(), +      damage_type :: damage_type(), +      damage_mod :: damage_mod() +   } +). + +-opaque type() :: #weapon{}. + +-export_type([type/0, id/0]). +-export_type +( +   [ +      range_type/0, +      range_mod/0, +      damage_type/0, +      damage_mod/0 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-export +( +   [ +      get_id/1, +      get_range_type/1, +      get_ranges/1, +      get_damages/1 +   ] +). + +-export +( +   [ +      random_id/0, +      from_id/1, +      can_parry/1, +      apply_to_attributes/2 +   ] +). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% LOCAL FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-spec ranges_of_type +   ( +      range_type(), +      range_mod() +   ) +   -> {non_neg_integer(), non_neg_integer()}. +ranges_of_type (ranged, long) -> {2, 6}; +ranges_of_type (ranged, short) -> {1, 4}; +ranges_of_type (melee, long) -> {0, 2}; +ranges_of_type (melee, short) -> {0, 1}. + +-spec damages_of_type +   ( +      range_type(), +      damage_mod() +   ) +   -> {non_neg_integer(), non_neg_integer()}. +damages_of_type (ranged, heavy) -> {10, 25}; +damages_of_type (ranged, light) -> {5, 20}; +damages_of_type (melee, heavy) -> {20, 35}; +damages_of_type (melee, light) -> {15, 30}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% EXPORTED FUNCTIONS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%% Accessors +-spec get_id (type()) -> id(). +get_id (Wp) -> Wp#weapon.id. + +-spec get_range_type (type()) -> range_type(). +get_range_type (Wp) -> Wp#weapon.range_type. + +-spec get_ranges (type()) -> {non_neg_integer(), non_neg_integer()}. +get_ranges (Wp) -> +   ranges_of_type(Wp#weapon.range_type, Wp#weapon.range_mod). + +-spec get_damages (type()) -> {non_neg_integer(), non_neg_integer()}. +get_damages (Wp) -> +   damages_of_type(Wp#weapon.range_type, Wp#weapon.damage_mod). + +-spec can_parry (type()) -> boolean(). +can_parry (Wp) -> (Wp#weapon.range_type == melee). + +-spec from_id (id()) -> type(). +from_id (0) -> +   #weapon{ +      id = 0, +      name = <<"None">>, +      range_type = melee, +      range_mod = short, +      damage_type = blunt, +      damage_mod = light +   }; +from_id (1) -> +   #weapon{ +      id = 1, +      name = <<"Dagger">>, +      range_type = melee, +      range_mod = short, +      damage_type = slash, +      damage_mod = light +   }; +from_id (2) -> +   #weapon{ +      id = 2, +      name = <<"Sword">>, +      range_type = melee, +      range_mod = short, +      damage_type = slash, +      damage_mod = heavy +   }; +from_id (3) -> +   #weapon{ +      id = 3, +      name = <<"Claymore">>, +      range_type = melee, +      range_mod = long, +      damage_type = slash, +      damage_mod = light +   }; +from_id (4) -> +   #weapon{ +      id = 4, +      name = <<"Bardiche">>, +      range_type = melee, +      range_mod = long, +      damage_type = slash, +      damage_mod = heavy +   }; +from_id (5) -> +   #weapon{ +      id = 5, +      name = <<"Stiletto">>, +      range_type = melee, +      range_mod = short, +      damage_type = pierce, +      damage_mod = light +   }; +from_id (6) -> +   #weapon{ +      id = 6, +      name = <<"Pickaxe">>, +      range_type = melee, +      range_mod = short, +      damage_type = pierce, +      damage_mod = heavy +   }; +from_id (7) -> +   #weapon{ +      id = 7, +      name = <<"Rapier">>, +      range_type = melee, +      range_mod = long, +      damage_type = pierce, +      damage_mod = light +   }; +from_id (8) -> +   #weapon{ +      id = 8, +      name = <<"Pike">>, +      range_type = melee, +      range_mod = long, +      damage_type = pierce, +      damage_mod = heavy +   }; +from_id (9) -> +   #weapon{ +      id = 9, +      name = <<"Club">>, +      range_type = melee, +      range_mod = short, +      damage_type = blunt, +      damage_mod = light +   }; +from_id (10) -> +   #weapon{ +      id = 10, +      name = <<"Mace">>, +      range_type = melee, +      range_mod = short, +      damage_type = blunt, +      damage_mod = heavy +   }; +from_id (11) -> +   #weapon{ +      id = 11, +      name = <<"Staff">>, +      range_type = melee, +      range_mod = long, +      damage_type = blunt, +      damage_mod = light +   }; +from_id (12) -> +   #weapon{ +      id = 12, +      name = <<"War Hammer">>, +      range_type = melee, +      range_mod = long, +      damage_type = blunt, +      damage_mod = heavy +   }; +from_id (13) -> +   #weapon{ +      id = 13, +      name = <<"Short Bow (Broadhead)">>, +      range_type = ranged, +      range_mod = short, +      damage_type = slash, +      damage_mod = light +   }; +from_id (14) -> +   #weapon{ +      id = 14, +      name = <<"Short Bow (Blunt)">>, +      range_type = ranged, +      range_mod = short, +      damage_type = blunt, +      damage_mod = light +   }; +from_id (15) -> +   #weapon{ +      id = 15, +      name = <<"Short Bow (Bodkin Point)">>, +      range_type = ranged, +      range_mod = short, +      damage_type = pierce, +      damage_mod = light +   }; +from_id (16) -> +   #weapon{ +      id = 16, +      name = <<"Long Bow (Broadhead)">>, +      range_type = ranged, +      range_mod = long, +      damage_type = slash, +      damage_mod = light +   }; +from_id (17) -> +   #weapon{ +      id = 17, +      name = <<"Long Bow (Blunt)">>, +      range_type = ranged, +      range_mod = long, +      damage_type = blunt, +      damage_mod = light +   }; +from_id (18) -> +   #weapon{ +      id = 18, +      name = <<"Long Bow (Bodkin Point)">>, +      range_type = ranged, +      range_mod = long, +      damage_type = pierce, +      damage_mod = light +   }; +from_id (19) -> +   #weapon{ +      id = 19, +      name = <<"Crossbow (Broadhead)">>, +      range_type = ranged, +      range_mod = short, +      damage_type = slash, +      damage_mod = heavy +   }; +from_id (20) -> +   #weapon{ +      id = 20, +      name = <<"Crossbow (Blunt)">>, +      range_type = ranged, +      range_mod = short, +      damage_type = blunt, +      damage_mod = heavy +   }; +from_id (21) -> +   #weapon{ +      id = 21, +      name = <<"Crossbow (Bodkin Point)">>, +      range_type = ranged, +      range_mod = short, +      damage_type = pierce, +      damage_mod = heavy +   }; +from_id (22) -> +   #weapon{ +      id = 22, +      name = <<"Arbalest (Broadhead)">>, +      range_type = ranged, +      range_mod = long, +      damage_type = slash, +      damage_mod = heavy +   }; +from_id (23) -> +   #weapon{ +      id = 23, +      name = <<"Arbalest (Blunt)">>, +      range_type = ranged, +      range_mod = long, +      damage_type = blunt, +      damage_mod = heavy +   }; +from_id (24) -> +   #weapon{ +      id = 24, +      name = <<"Arbalest (Bodkin Point)">>, +      range_type = ranged, +      range_mod = long, +      damage_type = pierce, +      damage_mod = heavy +   }. + +-spec random_id () -> id(). +random_id () -> sh_roll:between(0, 24). + +-spec apply_to_attributes +   ( +      sh_attributes:type(), +      bm_weapon:type() +   ) +   -> attributes:type(). +apply_to_attributes (Attributes, Weapon) -> +   Dexterity = sh_attributes:get_dexterity(Attributes), +   Speed = sh_attributes:get_speed(Attributes), +   RangeModifier = Weapon#weapon.range_mod, +   DamageModifier = Weapon#weapon.damage_mod, +   WithRangeModifier = +      case RangeModifier of +         long -> +            sh_attributes:set_dexterity(max(0, (Dexterity - 20)), Attributes); +         _ -> Attributes +      end, +   case DamageModifier of +      heavy -> sh_attributes:set_speed(max(0, (Speed - 20)), WithRangeModifier); +      _ -> WithRangeModifier +   end. + | 


