162 lines
5.3 KiB
Markdown
162 lines
5.3 KiB
Markdown
# 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:
|
|
```cyo
|
|
scenes.cyo
|
|
|
|
_onEnter_LivingRoom:
|
|
_onLeave_LivingRoom:
|
|
_onExplode_LivingRoom:
|
|
```
|
|
|
|
Unqualified Definition:
|
|
```cyo
|
|
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:
|
|
```cyo
|
|
|
|
_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:
|
|
```cyo
|
|
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."
|
|
|
|
```
|
|
|
|
### Callback Rules
|