butler | ||
data | ||
img | ||
include | ||
lib | ||
.gitignore | ||
action.c | ||
action.h | ||
adventure.org | ||
effect.c | ||
effect.h | ||
flag.c | ||
flag.h | ||
game.c | ||
game.h | ||
input.c | ||
input.h | ||
intro.c | ||
intro.h | ||
item.c | ||
item.h | ||
log.c | ||
log.h | ||
main.c | ||
Makefile | ||
parse.c | ||
parse.h | ||
predicate.c | ||
predicate.h | ||
README.org | ||
room_in.c | ||
room_in.h | ||
room.c | ||
room.h | ||
util.c | ||
util.h | ||
word.c | ||
word.h |
Fatal Distractions Chapter 1 - Text Adventures
Concept
I'm not looking for anything super complicated. I've spent maybe 90 minutes in my life playing text adventures, I'm sure there are some with really good mechanics. For this one, I'm aiming for something at about the level of Thy Dungeonman. A map, moving between rooms, getting items, <verb>ing <item>s <preposition> <other item>s. If I'm pretty much finished before the end of the month, I could add
- visual effects
- saving and loading
- pictures
- music
I'm not trying to be a purist about this; I know 99% of all text adventures are just text, but music is also fun to put together.
Implementation
Flags
A flag is a combination name and uinteger value. The value can be changed as the result of an action, or checked within a predicate. Three uses for these:
- Boolean values, 1 or 0
- Countdowns, start at some positive value and eventually become 0 = false
- Counters, start at zero and increment ("you have rung the bell 10 times")
Counters seem really optional, booleans and countdowns seem actually useful. Values should evaluate to false if zero, true otherwise. Effects should be able to enable (set to 1), disable (set to 0), increment, or decrement; if there's need for it, they'll need to set (set to X), I don't think so.
Effects
When an action evaluates, most of the time it will have no effect ("you can't go north from here"). Sometimes though, an action should change the world. Here are some effects:
- Modify a flag (detailed above)
- Change the current room
- Add / remove an item from the inventory
- Do some meta thing (save or load)
Predicates
I guess I need a DSL for predicates. I don't think I'll need to implement "OR", my predicates should be able to be a chain of clauses "AND"ed together. Some clauses:
- IN(room_name), true if the current room has that name
- HAS(item_name), true if that item is in the inventory (or in the room)
- ENABLED(flag_name), true if that flag has a value > 0
-
TO(item_name), this is the real tough one, for transitive verbs with an object
- 'use key on door'
- 'give trinket to dennis'
- 'take torch from sconce'
Some of these things are items, some are definitely not. Not sure how to codify. Maybe:
- DITRANSITIVE(preposition, object), which checks that the command is of the form: <verb> <noun> <preposition> <object>
- Even monotransitive verbs ("pull lever") need to specify what they'll act on.
Actions
Actions are a command, or part of a command, plus a predicate, plus a priority, plus a description, plus (optionally) some effects: PULL | * | 1 | You don't see anything to pull | PULL | IN(lever_room) | 10 | What do you want to pull? | PULL LEVER | IN(lever_room) | 100 | You pull the lever. Nice. | ENABLE(lever_pulled) PULL LEVER | IN(lever_room) & ENABLED(lever_pulled) | 1000 | You already pulled it. | If the command matches all of the first column, it looks at that action. ">PULL LEVER" would match all four, ">PULL" would only match the first two. The game would choose between all matched actions, filter to only the ones whose predicates are fulfilled, and choose from those the one with the highest priority. This might require a lot of typing, but I think it will have enough flexibility to do everything I might want to do.
An action describing a transition would look as follows: NORTH | * | 1 | You can't go north from here. | NORTH | IN(initial_room) | 2 | You enter the nasty room. | GOTO(nasty_room) NORTH | IN(other_room) | 2 | You enter the opulent room. | GOTO(opulent_room) , but there's nicer syntax for transitions I'm sure.
Parsing
I'm sure we want a gallery of synonyms for most verbs and nouns. I assume we split the string by spaces, making an array of canonical words, then write the actions around those canonical words. PULL|PULL,YANK,TUG ROPE|ROPE,CORD,STRING,CABLE With the above words, "PULL ROPE", "YANK CORD", or "TUG STRING" would all check for actions as "PULL ROPE".