Rules are a declarative way of describing meaningful events in your story.
They are made up of 3 parts: a "trigger", a set of "conditions", and a set of "changes" to apply if the rule matches. Each time you call findMatchingRule
, the engine will test all of your rules against the provided trigger and the current state of your story world, and will find the best matching rule (if one exists).
Rules are weighted based on how specific they are, so you can "override" a more generic rule by making a more specific rule that will also match.
It is possible to create generic rules (using MatchAny
) to control basic story logic, and more specific rules to flesh out the story.
See how the rules are defined in the full working example. Note that you can use the syntax and corresponding parsers defined in NarrativeEngine.Syntax.RuleParser
to define rules more easily.
{ a | trigger : Trigger
, conditions : List NarrativeEngine.Core.WorldModel.EntityMatcher
, changes : List NarrativeEngine.Core.WorldModel.ChangeWorld
}
A declarative rule describing the conditions in which it should apply. Specifically, it defines a trigger and a list of other conditions that must be present based on the current world model. All rules are tested on each player interaction, and the highest weighted matching rule will be returned. You can then apply the specified changes.
Note that Rule
s are extensible records, meaning that you can add other fields to them in your game. For example, you could add a narrative
field to add a story text to use when the rule matches, or a sound
to play, etc. All of these "side effects" would be handled in your game code. Alternatively, you could use the returned RuleID
to lookup side effects in a separate data structure. This design follows the Entity Component System (ECS) design pattern.
String
Unique ID for a rule. These ids will be returned when a matching rule is found.
Describes what will trigger the rule. This can either be a specific string to match, or more frequently, an entity matcher.
A SpecificTrigger
is useful for programmatic events (like "new-day" or "wait") or to build ad-hoc interaction systems (like "ITEM1+ITEM2" or "drop-ITEM1"). An EntityTrigger
can describe which entity interactions the rule should apply to, with all of the power of an EntityMatcher
.
Dict RuleID (Rule a)
All of the rules in your "rule book" that define your game logic.
findMatchingRule : String -> Rules a -> NarrativeEngine.Core.WorldModel.WorldModel b -> Maybe ( RuleID, Rule a )
Finds the rule that best matches against the provided trigger and current world model. The trigger is usually an entity ID, but can be a generic string to attempt to match against a SpecificTrigger
. If multiple rules match, this chooses the "best" match based on the most specific rule. In general, the more conditions, the more specific.
Call this any time the player "interacts" with an entity in your game, supplying the ID of the entity that was interacted with.
weight : Rule a -> Basics.Int
Assigns a "weighting" to a rule. Used internally.