Example Plugin (Choice Engine)

Example Plugin (Choice Engine)

Choice engine is a tool that was build in the Tool Jam 3 we launched Infomancer Forge in. Choice engine uses a text file to drive an adventure game. We decided to create a tool to build those adventures and output those text files as an example of how you can use Infomancer to enhance projects and other tools.
You can learn more about Choice engine on their itch page here. Or the github page here.


Choice engine creates a story through locations and choices you make at each. Additionally each location may have a zombie fight that is managed by the game engine. To build this in Infomancer we create three Gobs.
  • ChoiceGame.
  • Location.
  • Option.

Choice Game

The Choice game was added to make it easier to figure out the starting Location of a story and to allow the capturing of multiple stories that may even share a lot of parts.
notion image
We have a name for what our story is. We also have a single GOB reference to a starting node. Later we will export each story into it’s own folder with a store.txt file in it. That story will be composed from this node.


The location has a description a description, array of Options and if it is a combat or not.
notion image
Locations are named Base nodes. Notice that we make Options an array. This allows us to add more then one reference there.
Currently there is no way to force only a certain number of options. Like 2 as this game requires. This has been added to features a min and max number of links.
We captured all the locations from the story.txt file as you can see in the screen shot below.
notion image
What is important to notice here we did not capture the options. This is because as they are arrays or references it’s easier and more meaningful to capture those on a View. All the data could be captures in either place but views make links much easier to build.


The Option has a text description and a single destination Gob back to location.
notion image
Of note here is that the Option GOB has been declared as Embedded. This means that it does not have a Name and would in normal situation be embedded into the Location. Here we choice to make it embedded because each choice does not need a unique ID so we are not asked to name each one as we create them.


Now that we have our basic GOB’s designed we can capture the adventure game. The image below is the fully captured and edited Sample adventure from the first release of Choice Engine.
notion image
You can see how the color choice helps us visualize the information. We did have to move things around a bit so we can easily see how all the piece connect to each other.
If you look at the bottom right you will see two story nodes that were not included in the final story in the sample game. A view like this makes it very easy to identify that.

Exporting the Project

So now that we have an adventure captured we need to build the part that takes all that data and turns it into something our game can use. We created two new scripts choiceEngien.lua and choiceInit.lua both will be broken down in more detail below.
notion image


Choice init is the scrip that adds the export to the menu and binds the module of choiceEngien.lua into the application.
local ui=require("ui") local choice=require("choiceEngine") ui.addMenuAction({ actionId="project.choice.export", name="Export Choice Engine", path="Project", icon='iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIOSURBVDhP1ZK7a1RREMa/795NTDDsoqyuEldR0sQFER/YKGLho/GBWqQLYqEgWKkgVpapIkFRQSxEfBAsIiSCxaKyhSAGLRTEwkSjYVNEMGY1m7338zsb8zeIc5jzmJnzmzlzL/65kMWoWyfT91gFoWFLBOKXHS/YoyE9xACe2rMXMRJ7Yu/t9L6BOCrzZoRlOIPlNsbWDFKvDWSboGuegRU+5722WkNMizVjxBIkasEpos/MHMSBiPi9EKizaTOQD3hMvep1+CFejRJ8Y4xWlxBA8wQKqVl5Zwjrek2rodPOnEMd/fjODsNOGDTvAWxQrJXpbXRgAjP44DsztrYRN/yeCBGH+EXDWmsjuIMfUWUXChrROdUxiyMGpdaa623DM/bjui6E2ChMf4XYyWx8mRnk+BxdGMUErzi78faOURh1VW/sH8N5buPWcCljKs32m8yu6EdS8f6O9vlc5D2W7EsDgI9IjnPWN6TVSvBJkwEQYwsuoR0xa+7FUXx2sSVDD/Itl6Lq8O2Y8+h2y6hN6V3t1jA69Rp73Ksy3hH7OYjDOo6iK6i5moyxPx3d57RZ3dJF5Q0IPUhcy+J/4E9lLWOQeOn8I3jF8ahkU3hx+JwZTGtS7VqHjXiMKR5gnQs/UpAASDymFIctuIv3WWWPMyRNNxGpoK+qaA038wnqBszZtwgI4r6p07343wX4A+LzvQlCDxQCAAAAAElFTkSuQmCC', adjustColors=true, action=function() choice.exportGames() end })
We add a single menu item into Project the icon is a base64 png of what we would like the menu item to look like. Once added we get the following new menu item.
notion image
When someone clicks that it will run the code in the function action points to.


This is where we take the gobs as a Lua table and rework them into the text file. There is some tricky recursive stuff needed here so we don’t add nodes that are orphaned.
local choiceEngine={} local table=require("tables") local json=require("json") -- Adds a choice to a line will also add a location to the set if it's not know. choiceEngine.addChoice=function(text,line,locationName,knownLocations,locations,option) option=option or {} return line .. "|" .. (option.description or 'Continue') .. "|" .. choiceEngine.addLocation(text,option.destination,knownLocations,locations) end -- Returns the number of the location choiceEngine.addLocation=function(text,locationName,knownLocations,locations) -- Don't add a location we have already added if locationName~=nil then if knownLocations[locationName]==nil then local locationNumber=#text+1 text[locationNumber]="" local l=locations[locationName] local line=l.description local o1,o2 if l.options~=nil then o1=l.options[1] o2=l.options[2] end knownLocations[locationName]=locationNumber line=choiceEngine.addChoice(text,line,locationName,knownLocations,locations,o1) line=choiceEngine.addChoice(text,line,locationName,knownLocations,locations,o2) if l.combat then line=line .. "|true" else line=line .. "|false" end text[locationNumber]=line end return knownLocations[locationName] end return 1 end choiceEngine.exportGames=function() -- this is needed for now sine the GOBS type is not done in a ways the lua libraries understand local lua=table.tostring(gobs,"","","") local baseGobs=load("return " .. lua)() if baseGobs.ChoiceGame~=nil and baseGobs.ChoiceGame.data~=nil then local locations={} -- Create a named list of all locations for n,g in pairs(baseGobs.Location.data) do locations[g.name]=g end -- For each game perform export for n,g in pairs(baseGobs.ChoiceGame.data) do local gameText={} local knownLocations={} -- Add first location it will do the rest choiceEngine.addLocation(gameText,g.startLocation,knownLocations,locations) -- pack into a single text string local story="" for l,t in ipairs(gameText) do story=story .. t .. "\n" end -- Save the string to the file environment:saveFile("Build/" .. g.name .. "/story.txt",story) print("Story " .. g.name .. " saved to Build/" .. g.name .. "/story.txt") end else print("Unable to find games to export.") end end return choiceEngine
So its about 75 lines not really a huge piece of code. I could shorten it but I really wanted to keep it more readable.
It keeps track of each location it has added while adding it and this allows us to reference backwards to locations without adding them a second time. Adding the first location will then add each location those choices call and it will keep doing that until all locations needed have been added.

Final output file

Once we click the export button it will create a story folder in Build and write story.txt into it.
notion image
The story.txt file looks as follows.
You are a survivor in a post-apocalyptic world infested with zombies. You have heard that there is a safe haven for survivors in a nearby city and you decide to undertake the perilous journey there. Your mission is to make wise decisions and ensure that you survive the dangers in the road and reach a safe place|Use the main road|2|Take the road less traveled|11|false You go down the main road and you meet several zombies. What do you do?|fight zombies|3|run|10|false You see a hospital in front of you, what do you do?|Go to the hospital|4|ignore hospital|7|true You get a key from the monster|Continue your path|5|investigate the hospital|6|true After several hours of walking, you finally arrive at a shelter where you are received and you live peacefully for the rest of your life.|YAY|1|YAY|1|false you realize that the key is for a bunker under the hospital, where you find people and security|YAY|1|YAY|1|false Injured and tired, you continue advancing on the highway, you find a person alive on the ground, he tells you that there is no shelter, everyone is infected|don't believe him|8|believe him|9|false Congratulations, you have saved the camp, now you are a zombie, but everyone will remember you as a hero.|YAY|1|YAY|1|false Now you are a zombie, thanks to the death, there is a camp with humans, so you eat them|YAY|1|YAY|1|false You run away and the zombies chase you, but you manage to escape.|continue|11|continue|11|false You come across a police barrier that covers the road, what do you do?|investigate restaurant to find a way to go around|12|jump the barrier|13|false You find an energy drink and a door to the back, when you open the door a zombie appears|continue|6|continue|6|false When you jump over the barrier, a zombie grabs your foot and bites you, you fall on the other side, you see some lights at the end of the street|go to abandoned ambulance|14|go towards the light|15|false you find yourself with 3 bandages and a frenzy|continue|15|continue|15|false The light you saw is a refuge, a base with survivors, they are being attacked by zombie|help them|8|do not help|9|false

Full version.

Below is the full version of the project. This include the data, GOVS plugin and view. You could open this and build your own adventures to export.