Skip to content

Commit 0ab4fd7

Browse files
committed
Players can have items and see what those items are.
Also a test screen framework for testing without randomness. :D
1 parent 5e96052 commit 0ab4fd7

19 files changed

+269
-36
lines changed

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ defmodule Gald.Player.Controller do
33
You should never call the functions on this module directly - instead, use the proper functions on Gald.Player.
44
"""
55

6+
#TODO(Havvy): Remove dependence upon Gald.Race
7+
68
use GenServer
79
import Destructure
810
require Logger
911
alias Gald.{Race, Player}
10-
alias Gald.Player.Stats
12+
alias Gald.Player.{Inventory, Stats}
1113

1214
@typep state :: %{
1315
required(:race) => Race.t,
@@ -28,8 +30,12 @@ defmodule Gald.Player.Controller do
2830
end
2931

3032
def handle_cast(:emit_stats, state = d%{player}) do
31-
Stats.emit(Player.stats(player), Player.output(player))
33+
stats = Stats.display_info(Player.stats(player))
34+
inventory = Inventory.display_info(Player.inventory(player))
35+
36+
display_info = Map.put(stats, :inventory, inventory)
3237

38+
GenEvent.notify(Player.output(player), {:stats, display_info})
3339
{:noreply, state}
3440
end
3541

@@ -38,6 +44,11 @@ defmodule Gald.Player.Controller do
3844
{:noreply, state}
3945
end
4046

47+
def handle_cast({:put_usable, usable}, state = d%{player}) do
48+
Player.Inventory.put_usable(Player.inventory(player), usable)
49+
{:noreply, state}
50+
end
51+
4152
def handle_call(:name, _from, state) do
4253
{:reply, state.name, state}
4354
end

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

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
defmodule Gald.Player.Inventory do
2+
@moduledoc false
3+
4+
use GenServer
5+
6+
def start_link(state, opts) do
7+
GenServer.start_link(__MODULE__, state, opts)
8+
end
9+
10+
@spec put_usable(GenServer.server, Gald.Usable.t) :: :ok
11+
def put_usable(inventory, usable) do
12+
GenServer.cast(inventory, {:put_usable, usable})
13+
end
14+
15+
@spec display_info(GenServer.info) :: [String.t]
16+
def display_info(inventory) do
17+
GenServer.call(inventory, :display_info)
18+
end
19+
20+
def init(_opts) do
21+
{:ok, []}
22+
end
23+
24+
def handle_call(:display_info, _from, inventory) do
25+
reply = inventory
26+
|> Enum.map(&Gald.Usable.name/1)
27+
|> Enum.reverse()
28+
29+
{:reply, reply, inventory}
30+
end
31+
32+
def handle_cast({:put_usable, usable}, inventory) do
33+
{:noreply, [usable | inventory]}
34+
end
35+
end

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

+10-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ defmodule Gald.Player do
55

66
use Supervisor
77
import Destructure
8-
alias Gald.Player.Controller
9-
alias Gald.Player.Input
10-
alias Gald.Player.Stats
8+
alias Gald.Player.{Controller, Input, Stats, Inventory}
119
alias Gald.Race
1210

1311
@type name :: String.t
@@ -26,6 +24,8 @@ defmodule Gald.Player do
2624
def output(race, player) when is_binary(player), do: who(race, player, :output)
2725
def stats(player) when is_pid(player), do: who(player, :stats)
2826
def stats(race, player) when is_binary(player), do: who(race, player, :stats)
27+
def inventory(player) when is_pid(player), do: who(player, :inventory)
28+
def inventory(race, player) when is_binary(player), do: who(race, player, :inventory)
2929

3030
@spec io(Player.t) :: {Input.t, GenEvent.t}
3131
@doc "Returns a tuple of the player input and output."
@@ -104,15 +104,21 @@ defmodule Gald.Player do
104104
GenServer.call(controller(player), :on_turn_start)
105105
end
106106

107+
@spec put_usable(Supervisor.supervisor, Gald.Usable.t) :: :ok
108+
def put_usable(player, usable) when is_pid(player) do
109+
GenServer.cast(controller(player), {:put_usable, usable})
110+
end
111+
107112
# Server
108113
def init(d%{race, name}) do
109-
base_args = %{race: race, player: self}
114+
base_args = d%{race, player: self}
110115
controller_args = Map.put(base_args, :name, name)
111116
children = [
112117
worker(Controller, [controller_args, [name: controller(self)]]),
113118
worker(Input, [base_args, [name: input(self)]]),
114119
worker(GenEvent, [[name: output(self)]]),
115120
worker(Stats, [base_args, [name: stats(self)]]),
121+
worker(Inventory, [base_args, [name: inventory(self)]])
116122
]
117123

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

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

+8-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ defmodule Gald.Player.Stats do
1313
that implement a protocol or behaviour. Probably a protocol...
1414
"""
1515

16+
# TODO(Havvy): Move status effects out?
17+
1618
import Destructure
1719
alias Gald.Status
1820
alias Gald.Status.List, as: StatusEffects
@@ -67,10 +69,12 @@ defmodule Gald.Player.Stats do
6769
Agent.start_link(fn -> %Gald.Player.Stats{} end, otp_opts)
6870
end
6971

70-
@spec emit(Agent.agent, GenEvent.manager) :: :ok
71-
def emit(stats, event_emitter) do
72-
stats = Agent.get(stats, &(&1))
73-
GenEvent.notify(event_emitter, {:stats, stats})
72+
@spec display_info(Agent.agent) :: Map.t
73+
@doc "Returns the info needed to be displayed to the player."
74+
def display_info(stats) do
75+
Agent.get(stats, fn (stats) ->
76+
%{stats | status_effects: Enum.map(stats.status_effects, &Gald.Status.name/1)}
77+
end)
7478
end
7579

7680
@spec battle_card(Agent.agent) :: battle_card

Diff for: apps/gald/lib/gald/screen/test/give_item.ex

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
defmodule Gald.Screen.Test.GiveItem do
2+
@moduledoc """
3+
Test screen (not to be used in the main game)
4+
5+
Let's the player choose which item they want.
6+
"""
7+
8+
use Gald.Screen
9+
import Destructure
10+
alias Gald.{Player}
11+
alias Gald.Usable.{RedPotion}
12+
13+
def init(d%{player}), do: d%{player}
14+
15+
def get_display(_data) do
16+
%StandardDisplay{
17+
title: "Get Item",
18+
body: "What item do you want?",
19+
options: ["Red Potion"]
20+
}
21+
end
22+
23+
def handle_player_option(name, d%{player}) do
24+
item = item_from_name(name)
25+
Player.put_usable(player, item)
26+
Player.emit_stats(player)
27+
{:next, Test.GiveItemResult, %{item_name: name}}
28+
end
29+
30+
defp item_from_name(name) do
31+
case name do
32+
"Red Potion" -> %RedPotion{}
33+
end
34+
end
35+
end
36+
37+
defmodule Gald.Screen.Test.GiveItemResult do
38+
@moduledoc """
39+
Test screen (not to be used in the main game)
40+
41+
Result screen of `Gald.Screen.Test.GiveItem.
42+
43+
Exists as a buffer between giving the item and the
44+
end of the turn, in case the tester wants to use the
45+
item before the end of their current turn.
46+
"""
47+
48+
import Destructure
49+
use Gald.Screen
50+
51+
def init(d%{player_name, item_name}) do
52+
d%{player_name, item_name}
53+
end
54+
55+
def get_display(d%{player_name, item_name}) do
56+
%StandardDisplay{
57+
title: "Item Given",
58+
body: "#{player_name} received a '#{item_name}'.",
59+
log: "#{player_name} received a '#{item_name}'."
60+
}
61+
end
62+
end

Diff for: apps/gald/lib/gald/screen/test/give_status.ex

-4
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,4 @@ defmodule Gald.Screen.Test.GiveStatusResult do
5858
log: "#{player_name} gains the '#{status}' status."
5959
}
6060
end
61-
62-
def handle_player_option(_option, _screen) do
63-
:end_sequence
64-
end
6561
end

Diff for: apps/gald/lib/gald/screen/test/mod.ex

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
defmodule Gald.Screen.Test do
2+
@moduledoc """
3+
Test screen (not to be used in the main game)
4+
5+
This screen lets the player delegate to other Test screens.
6+
"""
7+
8+
use Gald.Screen
9+
10+
def init(_init_arg) do
11+
nil
12+
end
13+
14+
def handle_player_option(option, _data), do: handle_player_option(option)
15+
16+
defp handle_player_option("Give Item"), do: {:next, Test.GiveItem, %{}}
17+
defp handle_player_option("Give Status"), do: {:next, Test.GiveStatus, %{}}
18+
defp handle_player_option("Set Health"), do: {:next, Test.SetHealth, %{}}
19+
defp handle_player_option("End Turn"), do: :end_sequence
20+
21+
def get_display(_data) do
22+
%StandardDisplay{
23+
title: "!!TEST!!",
24+
body: "What do you want to do?",
25+
options: [
26+
"Give Item",
27+
"Give Status",
28+
"Set Health",
29+
"End Turn"
30+
]
31+
}
32+
end
33+
end

Diff for: apps/gald/lib/gald/screen/test/non_event.ex

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,16 @@
11
defmodule Gald.Screen.Test.NonEvent do
2-
use Gald.Screen
3-
42
@moduledoc """
53
The screen is for testing purposes.
64
75
It literally does nothing for the event phase.
86
"""
97

8+
use Gald.Screen
9+
1010
def init(_init_arg) do
1111
nil
1212
end
1313

14-
def handle_player_option(_option, _data) do
15-
:end_sequence
16-
end
17-
1814
def get_display(_data) do
1915
%StandardDisplay{
2016
title: "Nothing Happened",

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

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
defprotocol Gald.Usable do
2+
@moduledoc """
3+
Usables are things that can show up in the inventory - consumables, abilities, equipment, etc.
4+
"""
5+
6+
@spec name(Gald.Usable.t) :: String.t
7+
def name(self)
8+
end

Diff for: apps/gald/lib/gald/usable/red_potion.ex

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule Gald.Usable.RedPotion do
2+
@moduledoc false
3+
4+
defstruct []
5+
6+
defimpl Gald.Usable, for: __MODULE__ do
7+
def name(_self), do: "Red Potion"
8+
end
9+
end

Diff for: apps/gald_site/web/race/lobby_channel.ex

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
defmodule GaldSite.LobbyChannel do
22
use Phoenix.Channel
3-
import ShortMaps
3+
import Destructure
44

55
def join("lobby", _auth_msg, socket) do
66
{:ok, %{races: GaldSite.RaceManager.all()}, socket}
77
end
88

9-
def broadcast_put(~m{internal_name visible_name}a) do
10-
GaldSite.Endpoint.broadcast!("lobby", "public:put", ~m{internal_name visible_name}a)
9+
def broadcast_put(d%{internal_name, visible_name}) do
10+
GaldSite.Endpoint.broadcast!("lobby", "public:put", d%{internal_name, visible_name})
1111
end
1212

13-
def broadcast_delete(~m{internal_name}a) do
14-
GaldSite.Endpoint.broadcast!("lobby", "public:delete", ~m{internal_name}a)
13+
def broadcast_delete(d%{internal_name}) do
14+
GaldSite.Endpoint.broadcast!("lobby", "public:delete", d%{internal_name})
1515
end
1616
end

Diff for: apps/gald_site/web/race/player_out_to_socket_handler.ex

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ defmodule GaldSite.PlayerOutToSocketHandler do
2727
{:ok, d%{socket}}
2828
end
2929

30-
defp serialize_payload(:stats, stats = d%{damage, status_effects}) do
30+
# TODO(Havvy): Rename to something else.
31+
defp serialize_payload(:stats, stats = d%{damage}) do
3132
damage = Enum.into(damage, %{})
32-
status_effects = Enum.map(status_effects, &Gald.Status.name/1)
33-
%{ stats | damage: damage, status_effects: status_effects }
33+
%{ stats | damage: damage }
3434
end
3535
defp serialize_payload(topic, _payload), do: raise "Unknown event '#{inspect topic}'."
3636
end

Diff for: apps/gald_site/web/race/race_controller.ex

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ defmodule GaldSite.RaceController do
2424
manager: Gald.EventManager.Singular,
2525
manager_config: %{event: CrashGame.Index},
2626
}
27+
"test" -> %Gald.Config{
28+
name: visible_name,
29+
manager: Gald.EventManager.Singular,
30+
manager_config: %{event: Test}
31+
}
2732
end
2833
Logger.debug(inspect config)
2934
internal_race_name = GaldSite.RaceManager.start_race(config)

0 commit comments

Comments
 (0)