Skip to content

Instantly share code, notes, and snippets.

@selfawaresoup
Last active March 14, 2021 16:30
Show Gist options
  • Save selfawaresoup/e3451704c418fdcd738fed3e62f991fd to your computer and use it in GitHub Desktop.
Save selfawaresoup/e3451704c418fdcd738fed3e62f991fd to your computer and use it in GitHub Desktop.
small demo of a flexible text adventure engine
/**
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
*/
const readline = require('readline-sync');
const init_state = {
main_fuses: false,
basement_fuses: false
}
const MANSION = {
MAIN_HALL: [
// having every entry be a function gives you a lot of flexibility down the line. because everything is a function, each stage and action can implement custom logic when necessary
/**
a "room" is always an array with 2 elements, all are functions and get passed the game state object as their only argument:
- 0: returns the description of the room
- 1: returns an array of available actions, actions that are null/false/undefined are automatically removed
an "action" is always an array with 4 elements, all are functions and get passed the game state object as their only argument:
- 0: returns the description of the action that is presented in the selction menu
- 1: return the description of the action once it is selected
- 2: return the new game state object, reflecting any changes that the action caused
- 3: returns the next room that is entered after the action is executed
*/
s => "You're in the main hall of an old mansion. A cold breeze blows in from somwhere. Nobody seems to have been here in a while. A staircase leads up tothe first floor and a door is labeled 'Basement'. Next to it is a fusebox",
s => [
[
s => "Go up the main staircase.", //name of the action
s => "The staircase creaks under your feet", // description of the result whent he action is picked
s => s, // function for state change
s => MANSION.FIRST_FLOOR_GALLERY // resulting stage is always the same
],
s.main_fuses ? null : [ //action is only available once before the state changes
s => "Enable the fuse labeled 'main'",
s => "With a buzzing sound, a few bulbs on the old chandelier light up",
s => ({ ...s, main_fuses: true }),
s => MANSION.MAIN_HALL
],
s.basement_fuses ? null : [ //action is only available once before the state changes
s => "Enable the unlabeled fuse",
s => "It clicks into place.",
s => ({ ...s, basement_fuses: true }),
s => MANSION.MAIN_HALL
],
[
s => "Go to the basement",
s => {
return s.basement_key //result depends on game state
? "You go down the narrow stairs into the basement."
: "The basement door is locked"
},
s => s,
s => s.basement_key ? MANSION.BASEMENT : MANSION.MAIN_HALL //resulting room depends on game state
]
]
],
FIRST_FLOOR_GALLERY: [
s => {
if (s.main_fuses) {
return s.basement_key
? "The first floor gallery has nothing but dust and cobwebs" // key was already picked up
: "On the first floor gallery you see a key hanging from a rusty nail on the wall"
} else {
return "You can't see anything up here, it's too dark."
}
},
s => [
!s.basement_key && s.main_fuses ? [ //key only available once and with ligths turned on
s => "Take the key",
s => "You take the key, it feels unusually cold",
s => ({ ...s, basement_key: true }),
s => MANSION.FIRST_FLOOR_GALLERY
] : null,
[
s => "Go back downstairs",
s => "You had back to the main hall",
s => s,
s => MANSION.MAIN_HALL
]
]
],
BASEMENT: [
s => s.basement_fuses
? "The basement is dimly lit by a single bulb, there's a chair in the middle of the room with a long decayed corpse sitting in it."
: "The basement is dark and cold. Your can't see anything.",
s => [
[
s => "Go back upstairs",
s => s.basement_fuses
? "You go back up the stairs. The hairs on your neck stand up for a moment."
: "You turn around towards the main hall, on the lat step of the staircase, you feel a large hand yanking you back down into the basement.",
s => s,
s => s.basement_fuses ? MANSION.MAIN_HALL : EATEN
],
s.basement_fuses ? [
s => "Investigate the corpse",
s => "It seems to be the old housekeeper. You feel a shiver.",
s => s,
s => MANSION.BASEMENT
] : null
]
]
}
const EATEN = [
s => "The monster has eaten you, you're dead.",
s => [
[
s => "Restart game",
s => "",
s => init_state,
s => MANSION.MAIN_HALL
]
]
]
const print = s => console.log(s)
const run = (init_stage, init_state) => {
let stage = init_stage
let state = init_state
while(true) {
const description = stage[0](state)
const actions = stage[1](state).filter(a => !!a)
print("\n----------")
print(description)
print("----------\n")
actions.forEach((action, index) => {
const action_description = action[0](state)
print(" " + (index + 1) + ": " + action_description)
})
let waiting = true
let selected_action;
while (waiting) {
const selection = parseInt(readline.question('? '), 10) - 1
if (actions[selection]) {
waiting = false
selected_action = actions[selection]
}
}
print("")
print(" => " + selected_action[1](state))
print("")
state = selected_action[2](state)
stage = selected_action[3](state)
}
}
run(MANSION.MAIN_HALL, init_state)
//to test a different entry point into the game, to avoid having to play it through every time:
//run(MANSION.BASEMENT, { basement_fuses: false, basement_key: true, main_fuses: true })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment