Following the google maps convention is a good idea. Google uses the left mouse button for panning, but Trizbort.io needs it for object selection. I have changed the code to allow for panning by holding down the right mouse button; that should cater for everyone who does not have a clickable mouse wheel.
I’ve also fixed object dragging on Chrome. You can now drag objects using the handle on the side of the object box to create container relationships.
Domain-specific languages
Regarding DSLs: Trizbort uses the Handlebars template language to expands its models into a language like TADS or Inform. It is quite easy to add a new Handlebars template to the codebase, provided you know how the models are structured. The relationships are very simple: A map has rooms, and connectors exist between rooms. There are also notes and blocks, but these are generally not interesting for export. Handlebars allows for writing little JavaScript helpers that make it easier to encapsulate complex bits of code generation. It also allows recursion, which is important for object containment relationships.
For example, the code for TADS generation works as follows. It starts off with TADS boilerplate, where several values are filled in use Handlebars expressions ({{{...}}}
). A reference is made to the main model element map
.
#charset "us-ascii"
#include <adv3.h>
#include <en_us.h>
versionInfo: GameID
name = '{{{map.title}}}'
byline = 'by {{{map.author}}}'
version = '1.0'
desc = '"{{{map.description}}}'
gameMain: GameMainDef
initialPlayerChar = me
Further down, the player actor is placed in the start room. TADS requires that a room name has CamelCase notation, so there is a Handlebars helper className
that converts a name to a class name, i.e. “West of house” becomes WestOfHouse
.
+ me: Actor
location = {{{className map.startRoom.name}}}
;
A list of rooms follows, generated using Handlebars’s default #each
block helper. For each room, the template goes through a list of its connections, and uses a custom helper to convert the connection’s compass direction to a string TADS understands.
{{#each map.rooms}}
{{className this.name}}: Room '{{{this.name}}}'
"{{{this.description}}}"
{{#each this.connections}}
{{ dirToStr this.startDir }}: {{{className this.room.name}}}
{{/each}}
;
{{#each this.objects}}{{buildObject this}}{{/each}}
{{/each}}
Within each room, the template processes the objects present. Since this requires recursion, I wrote a custom helper buildObject
to produce the code. Helpers are written in JavaScript:
protected buildObject(obj: Obj, level?: number) {
if(!level) level = 1;
let str = "";
for(let i = 0; i < level; i++) str += "+";
str = str + Handlebars.templates.tadsObject({ obj: obj });
obj.content.forEach((o) => {
str = str + this.buildObject(o, level + 1);
});
return new Handlebars.SafeString(str);
}
The helper uses a subtemplate named tadsObject
to export each object. Here kindToStr
is another helper than converts an object type (actor, item or scenery) into a TADS class (Actor
, Item
or Decoration
):
{{kindToStr obj.kind}} '{{{obj.name}}}'
"{{{obj.description}}}"
;
It is quite easy to build new Handlebars template. The tricky part is usually getting the indentation right.
Current state of DSLs
Trizbort supports export to several domain-specific languages, in varying states of completeness. All DSLs export rooms and connections, some add objects, and some add containment relationships. Missing features are easy to add, but may require better knowledge of the DSLs themselves. I’m a TADS user, and I dug into Inform 7 to get the export right. A github user kindly helped with some of the Quest implementation, but it needs attention. There’s also Alan 2/3, but I am not sure too many people use that.
Trizbort has features for dark rooms, but no template uses that feature yet. I’m currently adding support for (locked) doors, and I’ll be adding export to TADS for that. For Inform - input very welcome.
Adding new DSLs
Currently, adding new export languages to Trizbort requires fiddling with the code. There is no feature for uploading new templates. If you’d like to experiment:
- A package of Handlebars templates and JavaScript helpers are stored under
/src/codegen
.
- To make a new code generation option available, it must be added to the main menu (
/src/panels/menuPanel
), where you can just copy-paste one of the existing options.
Making DSLs dynamic, i.e. where you upload a new specification to Trizbort would mean parsing Handlebars templates on the fly. That is possible to do. However, it would not be easily possible to parse JavaScript helpers, so it might be better to express these in some sort of template language as well. That seems a big task.