jschomay / elm-narrative-engine / NarrativeEngine.Core.WorldModel

See how the world model is defined in the full working example. Note that you can use the syntax and corresponding parsers defined in NarrativeEngine.Syntax.EntityParser for defining entities, updates, and queries.

Types


type alias ID =
String

A unique identifier for each entity.


type alias WorldModel a =
Dict ID (NarrativeComponent a)

Your story/game will have a store, or "world model", of all of the entities that live in your world, and the various properties that describe them. The narrative engine expects your world model to have this shape.


type alias NarrativeComponent a =
{ a | tags : Tags
, stats : Stats
, links : Links 
}

Entities are just IDs coupled with various fields of information. The engine requires that your entities have tags, stats, and links fields.

It uses these fields to track "salience-based" and "quality/stats-based" narratives (described very well in Emily Shot's blog post), which can provide a more flexible and robust story.

Because this is an extensible record, you can have other properties on your entities as well (like "name" and "description" or "sprite" for example), which works well with the "Entity Component System" design pattern.

Note that you are not restricted to the traditional "items/characters/locations" world model. You can define your entities with what ever properties you want, to fit any story world.


type alias Tags =
Set String

"Tags" on an entity.

Examples: "item", "edible", "poisonous", "SmithFamily", etc.


type alias Stats =
Dict String Basics.Int

"Stats" on an entity.

Examples: "health", "honor", "plotProgression", "bars of gold", etc.


type alias Links =
Dict String ID

"Links" on an entity.

Examples: "locatedIn", "knows", "suspects", etc.

Creating entities

emptyTags : Tags

A empty starting state for the "tags" property

emptyStats : Stats

A empty starting state for the "stats" property

addTag : String -> NarrativeComponent a -> NarrativeComponent a

Add a tag to a narrative component.

setStat : String -> Basics.Int -> NarrativeComponent a -> NarrativeComponent a

Add a stat to a narrative component. A stat is a key and a numeric value on any scale you like.

tag : String -> ( ID, NarrativeComponent a ) -> ( ID, NarrativeComponent a )

A helper function to add a tag to an entity when setting up your world model.

stat : String -> Basics.Int -> ( ID, NarrativeComponent a ) -> ( ID, NarrativeComponent a )

A helper function to add a stat to an entity when setting up your world model. A stat is a key and a numeric value on any scale you like.

link : String -> ID -> ( ID, NarrativeComponent a ) -> ( ID, NarrativeComponent a )

A helper function to add a link to an entity when setting up your world model. The key is the type of relationship, and the value is intended to be the id of another entity.

Updating entities


type ChangeWorld
    = Update ID (List ChangeEntity)
    | UpdateAll (List Query) (List ChangeEntity)

Declarative statements of how an entity should change, designed to be used with rules.

Note that you can use $ as the ID to reference the entity ID that triggered the rule (useful for generic rules).


type ChangeEntity
    = AddTag String
    | RemoveTag String
    | SetStat String Basics.Int
    | IncStat String Basics.Int
    | DecStat String Basics.Int
    | SetLink String LinkTarget

Declarative statements for changing a property on an entity.


type LinkTarget
    = SpecificLinkTarget ID
    | LookUpLinkTarget ID String

Links can set to a specific entity or you can supply an entity and key to lookup a link.

You can use $ as the ID in both cases to reference the entity ID that triggered the rule (useful for generic rules).

Caution, if the look up entity or link isn't found this will keep the original link.

applyChanges : List ChangeWorld -> ID -> WorldModel a -> WorldModel a

Update the world model based on a list of changes. Also takes the id of the entity that triggered the rule to allow changes to use trigger matching (with $).

Querying the world model

Queries are run against the world model to search for matching entities, or to assert that an entity has specific properties. This is useful to render a list of characters in a given location for example. The engine uses this when checking rules.


type EntityMatcher
    = Match ID (List Query)
    | MatchAny (List Query)

Semantic means for matching entities. Specifies an optional entity ID and a list of queries to match against.

Note that you can use $ as the ID to reference the entity ID that triggered the rule (useful for generic rules).


type LinkMatcher
    = SpecificLink EntityMatcher
    | CompareLink ID String

Links can either be a specific entity matcher, or you can supply an entity ID and a link key to do a comparison.

Note that you can use $ as the ID to reference the entity ID that triggered the rule (useful in conditional narrative content).


type StatMatcher
    = SpecificStat Basics.Int
    | CompareStat ID String

Stats can either be a specific integer, or you can supply an entity ID and a stat key to do a comparison.

Note that you can use $ as the ID to reference the entity ID that triggered the rule (useful in conditional narrative content).


type Query
    = HasTag String
    | HasStat String Basics.Order StatMatcher
    | HasLink String LinkMatcher
    | Not Query

Semantic queries for checking properties of an entity.

query : EntityMatcher -> WorldModel a -> List ( ID, NarrativeComponent a )

A way to retrieve information from the store.

Provide an entity matcher to get back a list of matching entities. This is most useful for "match any" style queries, but works with specifc queries as well, just keep in mind the result is always a list.

query (MatchAny [ HasTag "item" ]) worldModel
-- [items...]

query (Match "PLAYER" [ HasStat "brave" GT <| SpecificStat 5 ]) worldModel |> List.isEmpty
-- True/False

Note that you should run replaceTrigger first if you have "$"'s in your matcher.

getStat : ID -> String -> WorldModel a -> Maybe Basics.Int

Get a specific stat from a specific entity.

getLink : ID -> String -> WorldModel a -> Maybe ID

Get a specific link from a specific entity.

Note, if the linked-to value doesn't exist in the world model, this will return Nothing.