Skip to content

Instantly share code, notes, and snippets.

@selfsame
Created February 27, 2018 15:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save selfsame/6474fa911fb2769ba42e99bcb6ced602 to your computer and use it in GitHub Desktop.
Save selfsame/6474fa911fb2769ba42e99bcb6ced602 to your computer and use it in GitHub Desktop.
[data]
Game entities are hashmaps.
{:id 5
:hp {:max 100 :current 50}
:sentient true
:name "frog"
:color :green}
mud.data/DB is a flat map of {id data}. The id space is global for all
types of entities (room/player/item).
IEntity protocol will work on id numbers or the data literal. Cross references
to entities should use the integer id.
(!set 5 :color :red)
(!update-in some-ref [:hp :current] inc)
Entity definitions are loaded from edn files. Definitions are referred to
by unique keywords :items/chest
When definitions are instantiated into the game, they are given an :id entry
and registered into the DB.
[Component Systems]
An entities top level key/values are considered components.
Components can have lifecycle methods.
(:init :destroy :merge :copy :serialize :deserialize :validate)
These allow configuring new components, cleaning up, and handling
special data types. The first argument is the entity instance, from which
the component data can be derived by it's name.
validate is called when a component has been changed, or possibly for
each component on initialization (which can handle schema changes for the DB)
(fn [o value]
(if-not (int? value) 10 value))
{:name :items/chest
:capacity 10
:contents [:items/dagger :rodents/mouse]}
(component :contents
(init [o]
(mapv instantiate (-> o :contents)))
(destroy [o]
(mapv destroy (-> o :contents))))
Game logic leans heavily on dispatching behaviour for an object based on its
components.
[dialogue]
Dialogues represent state machines for a player, they are declared
by a hashmap.
{:state :start
:start
(fn [this client input]
(write client "enter your name")
(assoc this :state :name))
:name
(fn [this client input]
(if (valid-name? input)
(do (write client "welcome " input)
nil)
(do (write "invalid name, try again")
this)))}
State functions return a modified dialogue map. Usually this means changing
the :state. Returning nil ends the dialogue.
When a player has a :dialogue entry, input handlers are routed.
(defn dialogue-input [client input]
(let [dialogue (:dialogue client)]
(if-let [f (-> dialogue :state)]
(!set client :dialogue
(f dialogue client input)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment