Skip to content

Commit 1baa972

Browse files
committed
Players can have items and see what those items are.
Also a test screen framework for testing without randomness. :D They can also use the items they have.
1 parent 0ab4fd7 commit 1baa972

38 files changed

+331
-132
lines changed

Diff for: apps/gald/lib/gald/controller.ex

+8-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ defmodule Gald.Controller do
1010
# TODO(Havvy): Change to a :gen_fsm?
1111
use GenServer
1212
use Gald.Race
13-
import ShortMaps
13+
import Destructure
1414
alias Gald.Race
1515
alias Gald.Config
1616
alias Gald.Players
@@ -23,15 +23,15 @@ defmodule Gald.Controller do
2323
@spec start_link(Race.t, %Config{}) :: {:ok, pid}
2424
@spec start_link(Race.t, %Config{}, GenServer.opts) :: {:ok, pid}
2525
def start_link(race, config, opts \\ []) do
26-
GenServer.start_link(__MODULE__, ~m{race config}a, opts)
26+
GenServer.start_link(__MODULE__, d(%{race, config}), opts)
2727
end
2828

29-
def init(~m{race config}a) do
29+
def init(d%{race, config}) do
3030
status = :lobby
31-
{:ok, ~m{race config status}a}
31+
{:ok, d%{race, config, status}}
3232
end
3333

34-
def handle_call({:new_player, name}, _from, state = ~m{race status}a) do
34+
def handle_call({:new_player, name}, _from, state = d%{race, status}) do
3535
reply = if status == :lobby do
3636
case Players.new_player(players(race), name) do
3737
{:ok, player} ->
@@ -52,7 +52,7 @@ defmodule Gald.Controller do
5252

5353
def handle_call(:config, _from, state), do: {:reply, state.config, state}
5454

55-
def handle_cast(:begin, state = ~m{race config}a) do
55+
def handle_cast(:begin, state = d%{race, config}) do
5656
require Logger
5757
state = %{state | status: :play}
5858
# Determine turn order
@@ -72,7 +72,7 @@ defmodule Gald.Controller do
7272
{:ok, _map} = Race.start_map(race, map_config)
7373

7474
# Start the event choosing process.
75-
event_manager_config = ~m{config}a
75+
event_manager_config = d%{config}
7676
{:ok, _event_manager} = Race.start_event_manager(race, event_manager_config)
7777

7878
snapshot = Snapshot.new(%{state | status: :beginning})
@@ -88,7 +88,7 @@ defmodule Gald.Controller do
8888
{:noreply, state}
8989
end
9090

91-
def handle_cast(:finish, state = ~m{race}a) do
91+
def handle_cast(:finish, state = d%{race}) do
9292
state = %{state | status: :over}
9393
snapshot = Snapshot.new(state)
9494
GenEvent.notify(out(race), {:finish, snapshot.data})

Diff for: apps/gald/lib/gald/monsters.ex

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ defmodule Gald.Monsters do
66
"""
77

88
use Supervisor
9-
import ShortMaps
9+
import Destructure
1010
alias Gald.Monster
1111

1212
# Client
1313
def start_link(init_map, otp_opts \\ []) do
1414
Supervisor.start_link(__MODULE__, init_map, otp_opts)
1515
end
1616

17-
def start_monster(monsters, ~m{monster_module}a) do
18-
Supervisor.start_child(monsters, [~m{monster_module}a])
17+
def start_monster(monsters, d%{monster_module}) do
18+
Supervisor.start_child(monsters, [d%{monster_module}])
1919
end
2020

2121
# Server

Diff for: apps/gald/lib/gald/player/controller.ex

+15
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ defmodule Gald.Player.Controller do
4949
{:noreply, state}
5050
end
5151

52+
def handle_cast({:update_health, updater}, state = d%{player}) do
53+
Stats.update_health(Player.stats(player), updater)
54+
{:noreply, state}
55+
end
56+
57+
def handle_cast({:unborrow_usable, use_result}, state=d%{player}) do
58+
Player.Inventory.unborrow_usable(Player.inventory(player), use_result)
59+
{:noreply, state}
60+
end
61+
62+
def handle_call({:borrow_usable, usable_name}, _from, state = d%{player}) do
63+
reply = Player.Inventory.borrow_usable(Player.inventory(player), usable_name)
64+
{:reply, reply, state}
65+
end
66+
5267
def handle_call(:name, _from, state) do
5368
{:reply, state.name, state}
5469
end

Diff for: apps/gald/lib/gald/player/input.ex

+38-7
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,59 @@
1+
# TODO(Havvy): Rename to Gald.PlayerInput
2+
# Because it connects the player to the game, it's
3+
# not actually actually a component to being a player,
4+
# but rather an interface in the game predicated on
5+
# what the player has access to.
6+
# This is a prestep for removing the Race dependency
7+
# on Player.
18
defmodule Gald.Player.Input do
29
use GenServer
3-
import ShortMaps
4-
alias Gald.Race
5-
alias Gald.Turn
10+
import Destructure
11+
alias Gald.{Race, Turn, Player, Usable}
612
require Logger
713

14+
@type player_option_result :: Turn.player_option_result
15+
@type player_usable_result :: :ok | {:error, :no_such_item}
16+
817
# Client
918
def start_link(init_arg, opts \\ []) do
1019
GenServer.start_link(__MODULE__, init_arg, opts)
1120
end
1221

22+
@spec select_option(GenServer.server, String.t) :: player_option_result
1323
def select_option(player_in, option) do
1424
GenServer.call(player_in, {:option, option})
1525
end
1626

27+
@spec use_usable(GenServer.server, String.t) :: player_usable_result
28+
def use_usable(player_in, usable) do
29+
GenServer.call(player_in, {:usable, usable})
30+
end
31+
1732
# Server
18-
def init(~m{race player}a) do
19-
{:ok, ~m{race player}a}
33+
def init(d%{race, player}) do
34+
{:ok, d%{race, player}}
2035
end
2136

22-
def handle_call({:option, option}, _from, state = ~m{player race}a) do
23-
player_name = Gald.Player.name(player)
37+
def handle_call({:option, option}, _from, state = d%{player, race}) do
38+
player_name = Player.name(player)
2439
Logger.debug("Player #{player_name} selects #{option}.")
2540
reply = Turn.player_option(Race.turn(race), player_name, option)
2641
{:reply, reply, state}
2742
end
43+
44+
def handle_call({:usable, usable_name}, _from, state = d%{player}) do
45+
player_name = Player.name(player)
46+
Logger.debug("Player #{player_name} using #{usable_name}.")
47+
reply = do_use_usable(usable_name, player)
48+
{:reply, reply, state}
49+
end
50+
51+
defp do_use_usable(usable_name, player) do
52+
with {:ok, usable} <- Player.borrow_usable(player, usable_name),
53+
usable_result <- Usable.use(usable, player) do
54+
Player.unborrow_usable(player, usable_result)
55+
Player.emit_stats(player)
56+
:ok
57+
end
58+
end
2859
end

Diff for: apps/gald/lib/gald/player/inventory.ex

+36-11
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,60 @@
11
defmodule Gald.Player.Inventory do
2-
@moduledoc false
2+
@moduledoc """
3+
Player's inventory. Responsible for storing usables and firing off their usables affects.
4+
"""
35

46
use GenServer
7+
alias Gald.{Usable}
8+
alias Gald.Usable.List, as: Inventory
9+
10+
@type use_usable_result :: :ok | {:error, :no_such_usable}
11+
@type inventory :: [Usable.t]
512

613
def start_link(state, opts) do
714
GenServer.start_link(__MODULE__, state, opts)
815
end
916

17+
@spec display_info(GenServer.server) :: [String.t]
18+
def display_info(inventory) do
19+
GenServer.call(inventory, :display_info)
20+
end
21+
1022
@spec put_usable(GenServer.server, Gald.Usable.t) :: :ok
1123
def put_usable(inventory, usable) do
1224
GenServer.cast(inventory, {:put_usable, usable})
1325
end
1426

15-
@spec display_info(GenServer.info) :: [String.t]
16-
def display_info(inventory) do
17-
GenServer.call(inventory, :display_info)
27+
@spec borrow_usable(GenServer.server, String.t) :: {:ok, Usable.t} | {:error, :no_such_usable}
28+
def borrow_usable(inventory, usable_name) do
29+
GenServer.call(inventory, {:borrow_usable, usable_name})
1830
end
1931

32+
@spec unborrow_usable(GenServer.server, Usable.use_result) :: :ok
33+
def unborrow_usable(inventory, use_result) do
34+
GenServer.cast(inventory, {:unborrow_usable, use_result})
35+
end
36+
37+
@spec can_use(Usable.t) :: :ok | {:error, :cannot_use_when_dead}
38+
def can_use(_usable), do: :ok
39+
2040
def init(_opts) do
2141
{:ok, []}
2242
end
2343

24-
def handle_call(:display_info, _from, inventory) do
25-
reply = inventory
26-
|> Enum.map(&Gald.Usable.name/1)
27-
|> Enum.reverse()
44+
def handle_cast({:put_usable, usable}, inventory) do
45+
{:noreply, Inventory.put_usable(inventory, usable)}
46+
end
2847

29-
{:reply, reply, inventory}
48+
def handle_cast({:unborrow_usable, use_result}, inventory) do
49+
{:noreply, Inventory.unborrow_usable(inventory, use_result)}
3050
end
3151

32-
def handle_cast({:put_usable, usable}, inventory) do
33-
{:noreply, [usable | inventory]}
52+
def handle_call(:display_info, _from, inventory) do
53+
{:reply, Inventory.display_info(inventory), inventory}
54+
end
55+
56+
def handle_call({:borrow_usable, usable_name}, _from, inventory) do
57+
{reply, inventory} = Inventory.borrow_usable(inventory, usable_name)
58+
{:reply, reply, inventory}
3459
end
3560
end

Diff for: apps/gald/lib/gald/player/mod.ex

+21-6
Original file line numberDiff line numberDiff line change
@@ -104,21 +104,36 @@ defmodule Gald.Player do
104104
GenServer.call(controller(player), :on_turn_start)
105105
end
106106

107+
def update_health(player, updater) when is_pid(player) do
108+
GenServer.cast(controller(player), {:update_health, updater})
109+
end
110+
107111
@spec put_usable(Supervisor.supervisor, Gald.Usable.t) :: :ok
108112
def put_usable(player, usable) when is_pid(player) do
109113
GenServer.cast(controller(player), {:put_usable, usable})
110114
end
111115

116+
# TODO(Havvy): Return a ref with the usable for the spot the usable was at.
117+
@spec borrow_usable(Supervisor.supervisor, String.t) :: {:ok, Usable.t} | {:error, :no_such_item}
118+
def borrow_usable(player, usable_name) do
119+
GenServer.call(controller(player), {:borrow_usable, usable_name})
120+
end
121+
122+
@spec unborrow_usable(Supervisor.supervisor, Usable.use_result) :: :ok
123+
def unborrow_usable(player, usable_result) do
124+
GenServer.cast(controller(player), {:unborrow_usable, usable_result})
125+
end
126+
112127
# Server
113128
def init(d%{race, name}) do
114-
base_args = d%{race, player: self}
129+
base_args = d%{race, player: self()}
115130
controller_args = Map.put(base_args, :name, name)
116131
children = [
117-
worker(Controller, [controller_args, [name: controller(self)]]),
118-
worker(Input, [base_args, [name: input(self)]]),
119-
worker(GenEvent, [[name: output(self)]]),
120-
worker(Stats, [base_args, [name: stats(self)]]),
121-
worker(Inventory, [base_args, [name: inventory(self)]])
132+
worker(Controller, [controller_args, [name: controller(self())]]),
133+
worker(Input, [base_args, [name: input(self())]]),
134+
worker(GenEvent, [[name: output(self())]]),
135+
worker(Stats, [base_args, [name: stats(self())]]),
136+
worker(Inventory, [base_args, [name: inventory(self())]])
122137
]
123138

124139
supervise(children, [strategy: :one_for_all, max_restarts: 0])

Diff for: apps/gald/lib/gald/player/stats.ex

+9-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ defmodule Gald.Player.Stats do
1818
import Destructure
1919
alias Gald.Status
2020
alias Gald.Status.List, as: StatusEffects
21+
alias Gald.Status.Respawning
2122

2223
@type life :: :alive | Gald.Death.t
2324
@type health :: non_neg_integer
@@ -155,7 +156,7 @@ defmodule Gald.Player.Stats do
155156
Agent.update(stats, &%Gald.Player.Stats{ &1 |
156157
life: %Gald.Death{},
157158
health: 0,
158-
status_effects: StatusEffects.filter_category(&1.status_effects, :soulbound)
159+
status_effects: &1.status_effects |> StatusEffects.filter_category(:soulbound) |> StatusEffects.put(%Respawning{})
159160
})
160161
end
161162

@@ -164,9 +165,14 @@ defmodule Gald.Player.Stats do
164165
def respawn_tick(stats) do
165166
Agent.get_and_update(stats, &respawn_tick_impl/1)
166167
end
167-
defp respawn_tick_impl(stats = %Gald.Player.Stats{life: life, max_health: max_health}) do
168+
defp respawn_tick_impl(stats = d%Gald.Player.Stats{life, max_health, status_effects}) do
168169
{new_life, respawned} = Gald.RespawnTick.respawn_tick(life)
169170
health = if respawned do max_health else 0 end
170-
{respawned, %{stats | life: new_life, health: health}}
171+
status_effects = if respawned do
172+
StatusEffects.delete(status_effects, Gald.Status.Respawning)
173+
else
174+
status_effects
175+
end
176+
{respawned, %{stats | life: new_life, health: health, status_effects: status_effects}}
171177
end
172178
end

Diff for: apps/gald/lib/gald/players.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ defmodule Gald.Players do
2525
# Server
2626
def init(race) do
2727
player_spec = Supervisor.Spec.worker(Player, [])
28-
{:ok, sup} = Supervisor.start_link([player_spec], strategy: :simple_one_for_one)
28+
{:ok, sup} = Supervisor.start_link([player_spec], [strategy: :simple_one_for_one, max_restarts: 0])
2929
names_to_pids = %{}
3030
join_ix = 0
3131
{:ok, d%{sup, names_to_pids, join_ix, race}}

Diff for: apps/gald/lib/gald/race.ex

+6-6
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ defmodule Gald.Race do
3737
# Server
3838
def init(config = %Config{}) do
3939
children = [
40-
worker(GenEvent, [[name: out(self)]]),
41-
worker(Gald.Controller, [self, config, [name: controller(self)]]),
42-
worker(Gald.Players, [self, [name: players(self)]]),
43-
worker(Gald.Rng, [%{module: config.rng, config: config.rng_config}, [name: rng(self)]]),
44-
worker(Gald.Display, [%{race: self}, [name: display(self)]]),
45-
worker(Gald.Monsters, [nil, [name: monsters(self)]]),
40+
worker(GenEvent, [[name: out(self())]]),
41+
worker(Gald.Controller, [self(), config, [name: controller(self())]]),
42+
worker(Gald.Players, [self(), [name: players(self())]]),
43+
worker(Gald.Rng, [%{module: config.rng, config: config.rng_config}, [name: rng(self())]]),
44+
worker(Gald.Display, [%{race: self()}, [name: display(self())]]),
45+
worker(Gald.Monsters, [nil, [name: monsters(self())]]),
4646
# Other children started dynamically.
4747
]
4848

Diff for: apps/gald/lib/gald/round.ex

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ defmodule Gald.Round do
2020

2121
# Server
2222
def init(d%{turn_order, race}) do
23-
GenServer.cast(self, :next)
23+
GenServer.cast(self(), :next)
2424

2525
{:ok, %{
2626
new_turn_order: turn_order,
@@ -56,7 +56,7 @@ defmodule Gald.Round do
5656
Gald.Race.delete_turn(race)
5757

5858
if !Gald.Victory.check(victory(race)) do
59-
GenServer.cast(self, :next)
59+
GenServer.cast(self(), :next)
6060
end
6161

6262
{:noreply, %{state | turn: nil, turn_player: nil}}

0 commit comments

Comments
 (0)