The Programs of the Week We Were Kept in Suspense
This Week’s Program: Oct 17 - Oct 21
I spent a bit of time this week reading the rules of Necromunda and
expanding hive-city
a bit more. No animated gif though; a lot of
what I worked on was under the hood. Check out the code I wrote
this week!
c40be00e4c246dc3aecfffac149d09d5b7e504ac
I flesh out the Turn
module a bit more. A turn in both Necromunda
and Warhammer 40K is broken up into a series of phases. A player can
only do certain actions depending on the phase.
4b73f3a9765a91509b893943b1785cf3df36a31a
Here, I make it so that you can only move a Model if you’re in the
Movement phase of the Turn. I also do a little trick I saw in Richard
Feldman’s elm-conf talk,
Making Impossible States Impossible. In
this talk, Richard walks through using Elm’s Sum Types (aka Algebraic
Data Types) to hide implementation details. I use that in the Turn
type:
type Turn = Turn Int Phase
This basically says that a Turn
type has 1 constructor, also called
Turn
, that takes an Int
and a Phase
. Within the Turn module, I
can deconstruct on this, but I don’t expose the Turn
constructor
outside of the module. Only functions within the Turn
module can
create new turns.
cf12f7104848c8bce105bc6457ab42e0195b4f8f
There are four different types of fighters in Necromunda: Gangers, Heavies, Juves, and Leaders. Each one of these types start off with a base level attributes. I formalize those a bit more.
29b00dc9299bab3db46726b921494fc012973218
I apply the same constructor type pattern from the Turn
type to the
Gang
type. Previously, a Gang was just a Dict
— a key/value
pair. Now, a Gang has a rich set of information, but that information
is only accessible from using functions from the Gang
module. Nothing changes in the API, all the functions keep their type
signatures, but the implementation details are all different. Now a
Gang can also “recruit” members. In Necromunda, you’re given a certain
number of “Guilder credits” that you can use to “buy” gang members and
weapons. In this way, you can bring the same Gang from game to game
and power them up over time. I make it so that recruiting new Models
deducts points from your available credits in the recruit
function.
60fce4f78f48843dc2fe93f627d87b7e62b0150a
Here’s a new module: Action
. An Action
is a thing a Model is
doing: either awaiting instructions, moving, shooting, etc.
be9e5bcfc9503bc576a9b100f03d73b025fb6980
The Player
type is always performing some Action
. When the Player
selects a Model, then the Action is rendered. Typically, the Player is
performing the Await
action, which just means that the selected
Model is awaiting some instruction.
36075dedfb3751813a149d30d91e66b354b6a928
When the Player clicks on the screen, if they’re not 2 inches near the
selected Model, the Model will be deselected. I make the
Tabletop.isWithinDistance
function to handle that scenario.
290293c718a9f054242679cb842244ddb97c59ac
When you hit the “1” through “5” keys on your keyboard, that selects
the corresponding Gang member. I expose Gang.toArray
to make this
easier. You’ll notice I’m really loving Elm’s pipeline operator (|>
)
and using Maybe.map
and Maybe.withDefault
together. That pattern
is used all throughout this program.
c54834bf163a22839c7ac78774a362825646e700
There’s a lot going on here. When a Player has the Await
action,
selecting a Model will render a small little control that shows the
available actions that Model can take in the current Phase. This code
sets that up and also sets up the control for Move
. When the Move
control is clicked, the Player is now in the Move
action and renders
the measuring tape UI. Now when the Player clicks and the current
action is Move
, it moves the Model just as it had done before.
Harry’s, my employer, is having a Chili cookoff today. So I’m going to go enjoy that now. Have a good weekend!
🌶 Mark