Rez v1.2.8 — open source engine for choice-based HTML games

I confess I don’t quite understand how your system works but it’s interesting to see someone take a very different approach to the problem.

I freely confess that Rez is in the “collection of weird symbols and annoying syntax” camp. I guess I’ve been a programmer for over 40 years and Rez is designed to suit me, first and foremost, so it was probably inevitable.

That said Rez is largely declarative with a fairly regular syntax. I’ve tried to make it as clean as possible. Dynamic behaviours are implemented with Javascript so there’s probably no way of avoiding that. But, even here, I’ve made the use of pluggable functions the norm. But there’s no getting away from it.

My target audience is people like me. Someone with at least some programming experience, with an ambitious choice-based game project, and finding that Twine’s constraints aren’t liberating.

I’ll be interested to see a game made with Strand. Maybe one day there will be one made with Rez! :smiley:

2 Likes

I’ve published a new website for Rez.

The previous site was Wordpress. I hated it and, so, did nothing with it. The new site is built using the static site generator Hugo and I’m slowly getting to grips with it.

At the very least it now hosts & links to my own documentation & the generated API documentation, although the latter doesn’t work properly yet.

1 Like

Looks good.

What? Your dad had a PDP?

1 Like

Indeed, from memory, a PDP-11. Playing games is about the only thing I remember about it :slight_smile:

1 Like

Picton Files: The Peter & Paul Case
Picton Files: Murder at the Manor
Solaris
The Tin Mug

2 Likes

But after a while you start wanting to incorporate some more advanced features like actors and inventory. Twine is… just passages of text. Increasingly you gravitate from ‘Harlowe’ and ‘SugarCube’ (the two major ‘formats’ for writing in Twine) to ‘Snowman’ which is a plain wrapper. And then you start making your game mainly by writing Javascript.

The day comes when you realise that Twine isn’t actually offering you very much.

I would like to disagree on this on a few things if you don’t mind.
You can do a lot more than just passages of text in Twine, even while mainly staying with the base macros of the format. Inventories and NPCs (I think that’s what you mean by Actors?) can be done with either of the more basic formats (there are many new users asking for helps for their Combat Systems or how to manage inventories in the Twine Discord).
And there are a lot of resources for Twine to help customise the basic format. Some even create custom macro so you don’t have to deal with coding JavaScript.
See:

I’m gonna plug: DOL-OS and The Thick Table Tavern that rely heavily on visuals and manipulations of elements on the screen. There may be some jQuery coded in the first, but over 95% of the code in both these projects were done in SugarCube.

Twine is a good tool for a lot of people, and it does offer a good starting base for many getting in the community. Some formats might not offer enough for some (which is why there is Snowman to help you do stuff from scratch, and why other people create their own format), but I fail to see how Twine doesn’t offer much with the kinds of games created in Twine…

Or were you just describing your experience with Twine?

2 Likes

Oh, disagree away :smiley:

I by no means meant to suggest that such things are impossible. I think Twine is an amazing tool but, by it’s own admission, it’s sweet spot is as “an open-source tool for telling interactive, nonlinear stories”. At this it excels and has clearly enabled all kinds of people who would never go near the likes of Inform or TADS to create some amazing works.

What I was, in my own clumsy way, trying to get at is that it doesn’t form a coherent system for supporting more complex games. Yes you can use Snowman and build stuff in pure JS. That’s the route I went down.

But at this point you’re often having to build or stitch together a framework in JS and Twine, at this point, largely offers constraints that, I found more frustrating than inspiring.

Again I am not trying to suggest you can’t make games in Twine, even complex games. But I don’t think it’s well suited to the latter purpose.

2 Likes

I am not sure by what you mean by complex game, then.

Without an international standard for complexity this is a difficult question to answer. What I think is complex you may consider trivial or vice verca.

I’m building a game with many NPC’s with behaviour trees, different inventory & item types (memories, dialogs, spells, equipment), procedural generation of elements, factions, relationships, plot clocks, with a UI structured into different scenes, and so on.

Rez has support for all of these concepts “out of the box” as a coherent system.

I agree, you can implement this stuff in Twine. Indeed I built the beginnings of the Rez std library as ad hoc JS libraries for Twine+Snowman before I started work on Rez.

If you want to do calligraphy, you can do it with a biro. But there are other tools more suited. That doesn’t devalue the biro.

3 Likes

Sounds like an impressive enterprise to undertake. Good luck!
:sweat_smile: I thing I was just a bit ticked about the language of the post, it did make it seem to devalue Twine, imo. Even if unintentionally.

2 Likes

Thanks and I think you’re right. I was a little strident and dismissive in my tone. It wasn’t my intention but I can see how it comes across.

2 Likes

I think it’s the same design instinct that behind the Adventures Story Format. Twine lets you do all the things you describe for Rez, but it doesn’t supply them. You have to make your own inventory system, or NPC system, or action-response system — or find someone else’s implementation of them and massage them into your own game.

i.e. beyond the basic branching choice-based narrative, most Story Formats provide you with the tools you’d use to build the systems that the game needs to run on, rather than providing the systems themselves. Of course that’s a strength, if the systems you need aren’t ones that anyone else has ever needed (or needed together). But if you have a particular sort of game structure in mind (and as @manonamora says, there are a lot of people who want inventory/combat/player dolls/quests/character builders) then having a language that offers those systems “out of the box” makes a lot of sense.

1 Like

Yes, it’s perfectly possible to do all these things in Twine and, indeed, that’s what I was doing. But it’s not just implementing them, but also combining things together into a coherent whole. I found that lead to a weak foundation.

What I’ve attempted is a foundation of “game system” over a foundation of “interactive fiction”. The systems in Rez are meant to encompass the core concepts that you’d expect to build a game on top of.

While, of course, those systems are biased towards my needs I’ve given thought to leaving them flexible enough to handle use cases I haven’t anticipated. That can’t be perfect of course, but it’s the intention.

For example the Rez inventory system employs 4 interlocking elements (‘element’ being the Rez term for a game component):

  • inventory
  • slot
  • item
  • effect

An inventory is a container, composed of a set of slots, and optionally attached to another game element (e.g. an actor).

Slots accept particular kinds of items and can have rules defined about how they combine (Example: in a fantasy RPG game, we might have a slot for main-hand & off-hand, and a two-handed slot. We can setup rules so that the 2-handed slot is unavailable if either the main or off-hand slots have contents, and vice verca).

Items are a generic ‘thing’ so can be used as easily for memories and potions. Every item has a type and there are rules for matching the types of items to the types that any given slot accepts. These rules include a conceptual kind of inheritance of item types that is relatively simple but can express most combinations.

Finally, effects can be applied to items and triggered by slots. Having a ring in your pocket might do nothing, but put it in a ‘hand’ slot and you might turn invisible.

So far, I haven’t come across a “container” situation I can’t express with these tools. Of course sooner or later it will happen and I will have to adapt :slight_smile:

If anyone else gives a serious attempt to building a game in Rez I will, of course, be interested to hear their feedback and where possible to accommodate their needs as authors.

1 Like

So… it sounds like a weapon is just an item that goes in the hand slot (making it equipped) for attacking. If I wanted to make the weapon have gem slots, the weapon item could also be a container and have it’s own slots associated with it?

I hadn’t thought of that but it would be a simple enough adjustment. In fact it might actually work out of the box, I don’t think I check that the container is actually an actor.

This would look like this:

@derive :1h_item :item

@slot hand_slot {
  accepts :1h_item
}

@slot belt_slot {
  accepts: :item
}

@inventory player_inventory {
  slots: #{#hand_slot #belt_slot}
}

@item sword {
  type: 1h_item
}

@item rock {
  type: item
}

The @derive directive establishes a hierarchy of types. In the example above it says that :1h_item is a type of :item.

The belt_slot accepts anything with type :item. The hand_slot only accepts things that are of type :1h_item. So the sword can go in either slot but the rock will only go in the belt_slot.

From a practical perspective it means you can answer the question “Should the player be allowed to put this item here?”

1 Like

Building Rez I knew I wanted to be make use of dynamic UI, so I needed a way of creating templates. After looking at several options I picked Handlebars. Pre-1.0 versions of Rez allowed you write @card content as a Handlebars template. The Rez compiler shelled out to the Handlebars compiler to precompile these templates into functions that could be executed at run-time.

From the get go I was unhappy with the approach I had taken. I could never like the Handlebars syntax, how it was difficult to integrate with Rez, and the dependency on the external compiler made the installation story more annoying.

For 1.0 I decided to bite the bullet and replace Handlebars with Rez’s own template framework that would be deeply embedded. It was a bit of effort but the result is, I think, worth it.

There are four types of expression, the most simple is an interpolation. When you want to put a variable into a template you do this:

${variable}

So, for example, to display the players name

${player.name}

But you cannot execute arbitrary Javascript here so:

${player.name + "'s"}

Is not a legal template expression. But this is where the nod to Liquid comes because we have filters that can alter a value. It’s like sending the data through a pipeline where, at each stage, it is transformed. So, in this case, we would write:

${player.name | possessive}

Which makes use of the possessive filter. Here is how that’s implemented in the stdlib:

@filter STRING_POSSESSIVE_FILTER {
  %% String -> String

  name: "possessive"
  impl: (s) => {return s.possessive();}
}

The standard library defines over 40 such filters (for things like plurals, array manipulation, generating links) and you can implement your own filters in exactly the same way.

The second expression is the “conditional”:

$if(cond) {% true output %}, {% false output %}

If the cond expression evaluates to true output the first sub-expression, otherwise the second sub-expression (or nothing if there isn’t a 2nd expression). These expressions may, themselves, be template expressions and nest as deeply as you need them to.

$if(player.wounded) {%
  <p style="color: red;">You are wounded, and cannot move very quickly.</p>
%}, {%
  <p style="color: green;">You are fit and healthy and can move normally.</p>
%}

The third type of expression is the “iterator”:

$for(x:xs) {% each-x output %}, {% separator output %}

When using the iterator xs must Javascript expression that you can run map over (e.g. an array). It binds x to each value in turn, running the sub-expression, and collecting its output. Then it joins all the output together (if an optional second expression is giving it uses that to join them).

From here you can visit:<ul>
$for(loc: location.exits) {%
  <li><a data-event="move" data-target="${loc.id}">${loc.name}</a></li>
%}
</ul>

With a separator:

$for(p:people) {% ${p.name} %}, {%, %}

The last type of expression is the “do” expression:

$do{...code...}

This allows for executing arbitrary code as the template is being rendered. Care should be taken here and it’s likely more appropriate to use one of the built in callbacks such as on_start and on_render. But the facility is there if it’s needed.

The result is a decently expressive template language that is built right in and tailored to Rez’s needs. All template expressions are compiled to Javascript functions at compile time so they are pretty fast to execute.

1 Like

Do you intend to support an equivalent of $elseif ?

2 Likes

I wonder how that might be formatted, if it exists or is in the works…

$if(player.pristine) {%
     OKAY
%}, (player.wounded) {%
     NOT OKAY
%}, {%
     NURSE!
%}

The need hasn’t arisen for me personally, although I’m not opposed to adding it, depending on finding a good syntax.

1 Like

This looks plausible although I will have to give it a little thought. Thanks for the suggestion!

1 Like