5.3 KiB
Mindset
In the world of text adventures, at any given moment, a player:
- Resides in a specific location
- Can issue any arbitrary command
- Said command should never cause an error
- Posseses an inventory with any number of objects
All entities in a text adventure world are typically broken into two categories: scenes and objects. But, I believe there is good reason to abstract all entities into just objects.
Then, objects are duck-typed into specific things by way of their available methods. Methods include but are not limited to:
_onEnter
, used for scenes, to read out text of the location_onExit
, used for scenes, to direct the player to the next destination_onAcquire
, used for objects that are meant to be kept_onInpect
, used for any object when the player wishes to know more
A graph markdown was deemed insufficient for cyano, as my stories are not going to fit cleanly along some API. What I really will need to be able to do is code it, as any good engine of any kind.
Goals for the language:
1. Reading as First Class
A story is only worth what its words convey, and you only have a good story if you can read it.
Imagine a file whose contents read:
func goToWindow:
print("You approach the window and its clear you could survive the jump");
input = get_input()
if input == "jump":
print("You fall gracefully to the ground")
else if
...
It honestly would be just as well to scrap this project and write a one-off in python. The purpose of writing an entire engine would be to pull away all of the unnecessary bits and bytes of sequencing, IO, object relations and requirements and let the writer focus on the actual writing.
Instead picture a file like this:
_onEnter:
You approach the window and its clear you could survive the jump
_onJump:
You fall gracefully to the ground
This is still the outset, so more syntax may be required, but the goal would be to make everything else get out of the way, and reading your story takes the front seat.
2a. Arbitrary Functionality
A story can take us anywhere. So why would the engine that powers it only allow objects to have one of up to a maximum of three conditions (Opened, Closed, Locked).
In reality, a chest could be Opened, Broken, Dusty, Sentient and who knows what else. The goal would be to allow the writer to have utmost freedom in writing the story they want to tell.
2b. Safe Operation
However, we dont want a dynamic story to have dead ends, missing links, or endless loops. When a chest depends on a key that doesnt exist? Thats no good. We want as many conditions as possible to be checked as soon as possible in the writing process to help make the greatest story that has yet to be experienced.
Cyo Spec
Summary
Cyano's underlying framework is using callbacks. You can think of it as defining a series of triggers and effects. Essentially, nothing happens without the user doing something, so we dont need the cyano engine to "run" code. Instead, it should read the user input, figure out what they mean, then lookup the associated trigger that the user is tripping.
Triggers could be anything:
- Entering a room
- Combining things in their inventory
- Putting a monkey idol on a pillar
- Reaching zero health
So, with these two concepts: entities and callbacks (triggers), we can create any story with any sort of form.
Want to make it RPG? Create a player entity with stats, and create triggers like _onKillMob
, _onLevelUp
.
Traditional text escape adventure? Chest entity with _onUnlock
, _onOpen
.
Nitty Gritty
Entities
Defining Entities:
- A file can define multiple entities only if these definitions are qualified.
- A file cannot have unqualified and qualified definitions.
- A file can only define one set of unqualified definitions and no others.
- Entity identifiers are case-insensitive, and can only contain letters, numbers, and underscores.
Qualified Definition:
scenes.cyo
_onEnter_LivingRoom:
_onLeave_LivingRoom:
_onExplode_LivingRoom:
Unqualified Definition:
living_room.cyo
_onEnter:
_onLeave:
_onExplode:
Both would create internally a LivingRoom entity.
In the case of an unqualified definition, the basename of the file is used as the entities identifier. Underscores in
the filename will be removed. If an underscore is desired in the identifier, the filename would need two:
living__room.cyo
Global State
Global state is accessible within any callback with said object properties TBD but would look like:
_onRead:
if $player.wearingPendant:
The book's text comes to life!
else:
The book's dull pages seem ready to fall apart with age.
Attributes that would be handy for the global state to hold:
- Inventory
- Current location
- Recent action(s)
- Arbitrary stats (author defined)
Should these all reside in the $player
object? This will probably evolve as need arises.
Entity State
You want to open a door, but only if the pressure plate in the room is weighed down with something. Entities need to be able to define and track arbitrary internal state. This might look something like:
PressurePlate:
pressed=false
_onInspect_PressurePlate:
if $pressed:
"Its depressed, now what?"
else if $player.:
"Its barely noticable on the dusty stone floor, but you can just make out the lip of the plate. Something heavy could depress it."