The following is a guide to some of Rez’s features and common things you may want to be able to do.
Using @object
Rez defines a number of generally useful elements like @actor
, @item
, @inventory
, @scene
and so forth. These elements have built-in behaviours designed to be useful but flexible.
For example @item
and @inventory
can be used to define much more than physical objects. You could have an inventory representing things different actors know about and use an item for individual topics/thoughts. Or items could represent spells in an inventory spell-book. The @item
/@inventory
elements are flexible enough to cover a range of container/containment situations.
However, there are going to be a range of concepts in a game for which Rez cannot plan or which may require very customised behaviour. A good example is that of "classes" as in RPG classes. There are so many possible ways to have a class work in a game that Rez cannot really offer a useful starting point. For this type of situation there is @object
.
The @object
element allows you to create a fully-custom object that has no built-in behaviours (beyond what you get from the basic_object
runtime prototype that all in-game objects share).
Let’s look at an example:
@object soldier { specialisation: :combat perks: #{#two_weapon_style #pounce #shield_bash #second_wind} } @object two_weapon_style { level: 3 label: "Fight with two weapons almost as well as one" } @object pounce { level: 5 label: "Close distance to an enemy and engage them quicker" } @object shield_bash { level: 7 label: "Shields can be a weapon in the right hands" } @object second_wind { level: 9 label: "When the chips are down, you come out fighting" } @object wizard { specialisation: :magic perks: #{#fast_cast #mana_surge #concentration #max_damage} } @object fast_cast { level: 3 label: "Faster than a speeding magic missile" } @object mana_surge { level: 5 label: "You can always reach down for just one more spell" } @object concentration { level: 7 label: "Nothing can distract you" } @object max_damage { level: 9 label: "Your fireballs are the crispiest" } @actor thaugrim_the_wise { %% Code dealing with this actor can lookup available perks from %% the Wizards class object class: #wizard }
How an author chooses to use these elements in their game is up to them, there are many ways that class membership & perks could be applied to in-game situations. You’d write callbacks or behaviours that make use of them. These elements can be referenced by $(<id>)
, the same as other elements and implement the basic_object
abstraction.
Avoiding Duplication with Aliases
A common scenario is a number of scenes wanting to share the same layout. While it is possible to supply the same layout:
attribute and duplicate the content Rez does offer a better way: aliases.
An alias has a name, element type, and one or more objects to base instances of the alias upon. These objects will define the default attributes.
@item magic_item_template { magical: true } @alias magic_item = item<magic_item_template> @magic_item magic_ring { description: "A plain golden band. Probably nobody is interested in this ring at all." }
Another example might be wanting to specify a common layout for a group of scenes:
@scene standard_scene { layout_format: :markdown layout: ```${content}``` } @alias standard_scene = scene<standard_scene> @standard_scene scene_01 { %% scene specific content here }
Multiple elements sharing a unique random value
In some circumstances you want multiple elements to have an attribute that shares the same random value. This is easily achieved using an extra object and attribute refs. Here is an example:
@object holds_random_value { %% this will be assigned a random value when the game is initialized rand: &{Math.rand_int(1, 10)} } @actor player { %% this will refer to the value from the object rand: &hold_random_value.rand } @actor npc { %% as will this rand: &hold_random_value.rand }
Note that you can change the value, but only in the object that holds it.
Using Decisions
RezDecision
is an object that doesn’t have an element. You create them when you want code (or perhaps users) to make a yes/no decision.
You can use a decision like this:
const decision = new RezDecision("Include Adult themes", {info: "Toggle this on to include themes of sex & violence that might not be suitable for all. Leave it off for a family friendly experience."}); decision.default_no(); some_function_making_the_decision(decision); if(decision.result) { // do something } else { // do something else }
In this case the some_function_making_the_decision(decision)
is expected to call either decision.yes()
or decision.no("reason")
before returning. In most cases you will be passing a decision to a script. In this case if neither function gets called the decision will default to 'no' (false
). If we had used decision.default_yes()
it would work the other way around.
You can pass data into a decision either through the second argument to new RezDecision()
or using the setData(key, value)
API. After receiving a decision you can use the data()
API to retrieve data. This way the callee can pass other information back with the decision.
Linking to things
The current scene will render its card which can include links to render other cards and other scenes. This is done by specifying either a card or scene id in a link.
If the id is of a card then the new card will be rendered as part of the layout of the existing scene. Depending on the scenes layout mode it will either replace the content of the previous card, or be appended to it.
If the id is of a scene then a transition to the new scene will be started.
Static Links
A static link is always embedded and points directly at a card or scene. It is equivalent to a Twine passage link and has the same syntax as follows:
[[Main Street]]
This will embed a link to load a card with the id main_street
and is syntactic sugar for writing:
[[Main Street|main_street]]
If no id is included the link text is converted into lower case and spacres are replaced with underscores, so "Main Street" becomes "main_street".
Event Links
Somes you want to do more than simply link to another card and event links are how you can do that. You write an event link as:
[[Title|*event]]
e.g.
[[Roll the dice|*roll]]
This creates a link that will attempt to find an on_roll
event handler attribute in the current card. If one is found it will be called and can decide how to respond to the event. Event handlers are expected to return an object.
on_roll: (card, evt) => { ... return { card: "after_roll" }; }
In this case the handler, after doing its work, plays the card #after_roll
.
Dynamic Links
Sometimes you want more control over whether links are displayed at all, can be clicked, and what text they present. For example an option may be disabled with a message that informs the player why they can’t take that action at present. Or hidden because it doesn’t make sense yet.
Rez supports dynamic links that give you this level of control. For example if you write:
[[*main_street]]
Rez will look for a main_street
script attribute of the card and will call that script to determine whether a link should be displayed, what the text of the link should be, and whether the player can click it or not, and even what happens when they do.
The options are:
-
allow which will display the link and point to the id of a card or scene to load if the player clicks it.
-
deny which will present the link text but disable the link so that it cannot be selected.
-
hide which will return empty text so that no link is presented at all
Example
@card side_street { main_street: (choice) => { if choice.game.is("dark") { choice.deny("You can't see a thing, maybe use your flashlight or a match."); } else { choice.allow("Head to Main st.", "main_street"); } } }
You can also take over what happens when a link is clicked:
@card side_street { on_main_street: (game, evt) => { // do what you want here } }
Forms and Inputs
Rez has built in support for forms and inputs that is enabled by adding rez-live
to the <form>
or <input>
tag. For example to process a form when it is submitted:
<form name="foo" rez-live> … </form>
When this form is submitted a handler on_foo
will be invoked on the Card
that contains the form.
Alternatively if you just want an input that is "live" you can use:
<input id="…" rez-live … />
Whenever the input generates an event (e.g. the user changes the value of the field) a corresponding handler will be called on the enclosing Card:
on_input: (game, evt) => { // do something with evt.input }
The potential uses for this are endless but typically you will either be updating a stored value or triggering a new scene/interlude.
Switching Scenes
There are two ways to change the scene:
A scene switch is where we move from one scene to another as part of the narrative flow of the game.
A scene interlude is where we suspend the current scene and temporarily switch to another scene before resuming the original scene. Scenes are held in a stack so we can also interlude from an interlude but always with the ability to backtrack to the original scene.
Rez provides three filters to create these links, scene_switch
, scene_interlude
, and scene_resume
:
${card | scene_shift: <scene-id>, 'Title'} ${card | scene_interlude: <scene-id>, 'Title'} ${card | scene_resume: 'Title'}
with the respective shorthand syntaxes:
[[Title|>scene_id]] # Switches to a new scene [[Title|!scene_id]] # Creates an interlude to the new scene
Alternatively you can use Scene API to resume after an iterlude.
Asset Management
Rez has built in support for assets including images, sounds, and movie files. You specify the assets you want to use in your source file.
@asset frobzz_1 { tags: #[:background] file_name: "scary_dungeon.jpg" end
Rez will automatically copy asset files into the games distribution folder.
Rez provides a filter to generate references to the asset file in the distribution folder:
${asset_id | asset_path} ${asset_id | asset_tag}
to generate appropriate markup to embed the asset into the game. Rez assets auto-detect the MIME type of the asset file and generate the appropriate HTML tag for the asset.
Using your own prototypes
The bult in Rez prototype objects are pretty flexible but you may want to replace one of them with your own object. You can do this using the $js_ctor
attribute on any object.
@actor kaspar_gutman { $js_ctor: "Gutman" name: "Kaspar Gutman" villain: true end
Now, instead of using the RezActor()
constructor function the initialization code will look for a Gutman()
constructor function. Constructor functions are passed the id (in this case kaspar_gutman
) and a map of attributes.
It is advisable to base your object on the object you are replacing.
Procedural Generation
Procedural generation is about content that is created at run-time and Rez has good support for this through it’s copyAssigningId()
and copyWithAutoId()
methods in basic_object
Rez supports the idea that you will create 'template' elements that are designed to be copied and modified to create something new. You do this by applying the $template
attribute to it and then calling the appropriate copy method.
Although most objects support copying, by specifying $template: true
you will suppress some of Rez’s automatic initialization. This means that the copy will get its own initialization.
@actor basic_npc { $template: true end