adventure-engine
Version:
Simple text based adventure game library.
439 lines (321 loc) • 18.4 kB
Markdown
Simple text-based adventure game engine for NodeJS.
1. Go to repl.it and make an account. You can sign up using Google.
1. Click on *+ new repl*. Select *NodeJS*, make new repl.
1. Give the game a name and a brief description.
- See the _world.json_ file in the [example project](https://repl.it/@BrianPiltin/haunted-house-5) for an example of how to define the world.
- In your repl.it window, in the files section create a new file named _world.json_. You will create your game world in this file.
- For a quick lesson on the JSON format, check out [this nice tutorial](https://beginnersbook.com/2015/04/json-tutorial/)
- To error-check your .json file, [use this handy tool](https://jsonlint.com/).
- The world consists of one large JSON object (dictionary) with the following structure:
```
{
"welcome": {
"description": "Optional description for game. Presented upon starting.",
"entrance": "optional-name-of-entrance-room-defaults-to-entrance"
},
"unique-room-name": {
(See "Defining a Room" section below.)
},
"unique-room-name": {
...
},
... any number of rooms
"end":
"description": "Optional Text to display upon quitting."
}
}
```
- You should define individual rooms according to the following structure:
```
...
"unique-room-name": {
"description": "Description text for room. Presented upon entering.",
"exits": {
"north": "optional-room-to-the-north-name",
"south": "optional-room-to-the-south-name",
...
"up": "optional-room-up-name",
"down": "optional-room-down-name"
}
"things": {
"unique-thing-name": {
"description": "Description text for thing. Presented upon inspection.",
"attributes": {
The following optional attributes are built into the game engine:
"hidden": "optional-boolean-hidden-state",
"stationary": "optional-boolean-stationary-can't-be-taken",
"uses": "optional-integer-number-of-times-can-be-used-in-attack",
"health": "optional-integer-1-to-10-amount-of-health-of-character",
"agression": "optional-integer-1-to-10-chance-character-attacks-player",
"accuracy": "optional-integer-1-to-10-chance-character-or-weapon-hits",
"damage": "optional-integer-1-to-10-amount-of-damage-character-or-weapon-inflicts",
...any other attributes you define for your own game.
You can add additional attributes to things using setAttribute function
(see below).
}
}
}
}
...
```
## Adding Artwork
Pictures are optional, but add some life to your game. Start by looking at the pictures from the [example project](https://repl.it/@BrianPiltin/haunted-house-5) in the pictures folder for examples of a picture files. [This amazing program](https://sourceforge.net/projects/ascgen2/) can be used to convert images to ASCII art.
- To add ASCII art (text-based) pictures to your game, in the repl.it files section add a new folder named _pictures_.
- Inside of the _pictures_ folder add the individual room or thing artwork files.
- Room picture files should be named as follows: _room-name.txt_, with room name being the name of the room.
- Thing picture files should be named as follows: _thing-name.txt_, with thing name being the name of the thing.
- Room pictures are displayed when a room is entered or on a look command.
- Thing pictures are displayed when a thing is inspected.
- Pictures should be no larger than 80 characters wide by 30 characters in order to be displayed correctly in the terminal.
- If available, _title.txt_ will be displayed as the opening screen (before user presses enter).
- If available, _welcome.txt_ will be displayed as the welcome screen (after user presses enter).
- If available, _end.txt_ will be displayed as the quit screen.
- If available, _credits.txt_ will be displayed as the credits screen.
## Adding Descriptions
Descriptions can be added as properties of the rooms or things in the world.json map or they can be individual text files located in the _descriptions_ folder.
- To add a description file, name it _thing-name.txt_ or _room-name.txt_ and store it in the descriptions folder.
- You can use template strings within the descriptions by enlosing a string with brackets like so: {{string}}. These strings will be replaced when the description is used in the game. In your code you will need to register these strings by using the API function: `setTemplateString(string, value)`. See the welcome.txt file in the descriptions folder of the [example project](https://repl.it/@BrianPiltin/haunted-house-5) for an example of how to do this.
Templates can be used in descriptions and pictures and allows for simply replacements to be made. A template string is defined as `{{string-name}}` where `{{string-name}}` will be replaced by the value that it is set with using the `setTemplateString` command.
Control codes are available for advanced displaying of text or animation as follows:
```
%c - clear the screen
%w - wait for the user to press any key
%p
%r
%n
```
Old Skool style 8-bit music can be added to the game using "song" files. These are text files locatied in the _songs_ folder. Songs files will have the name of a room or thing and they will be played when the room is entered or the thing is inspected. See the welcome.txt file in the _songs_ folder of the [example project](https://repl.it/@BrianPiltin/haunted-house-5) for an example of how to do this.
- To add a song file, name it _room-name.txt_ or _thing-name.txt_ and store it in the _songs_ folder.
- Use the following format for creating a song:
```
! Exlamation mark starts a line comment
! Note Duration, Note Duration, Note Duration, Note Duration...
C
! Where a note is:
! [note-letter][note-sharp-flat]?[note-octave]?[ ][note-duration][,]
! Where R is a rest/pause
! Control codes are as follows:
! %t
! %r
! Each event be it a note or control code MUST be followed by a comma!
Note durations are as follows:
0 = triplet, 1 = sixteenth, 2 = eighth, 3 = dotted eighth, 4 = quarter
5 = 5/16 note, 6 = dotted quarter, 7 = dotted dotted quarter, 8 = half note
12 = dotted half note, 16 = whole note
```
See the index.js file in the [example project](https://repl.it/@BrianPiltin/haunted-house-5) for an example on coding using the adventure-engine.
- You game code should be written in the repl.it _index.js_ file.
- A lot of your code will be written in the form of callback functions that respond to different events that occur in the game. See the [callback](
- The basic program template is as fallows.
Note that all of your functions should be defined INSIDE of a function called `game`:
```
// This line is necessary and starts the game on port 3000
require("adventure-engine").init(game, 3000);
function game() {
// Your code here
...
}
```
The following functions/methods are available globally as part of the API:
```
// Register a callback for responding to different game events
addCallback(callback-function);
// OR
addCallback(callback-name, function);
// Remove a callback function (prevents game from using that function unless it is re-registered)
removeCallback(callback-name);
// End the game by presenting the end picture/description and quitting the game
end();
// Get a thing object with thing-name from the world, optionally include room-name to restrict getting the thing from a specific room
var thing = getThing(thing-name, optional-room-name);
// Get a room object with room-name from the world
var room = getRoom(room-name);
// Get the player's inventory object
var inventory = getInventory();
// Read a line of text from the console, printing the prompt beforehand
var text = readLine(prompt);
// Print a line of text to the console
println(text);
// Print several lines of text with pauses in between based on ".." being present in text
printPaused(text);
// Print the description of a room or thing to the console
printDescription(room-or-thing-name-or-filename);
// Print the picture of a room or thing to the console
printPicture(room-or-thing-name-or-filename);
// Clear the console
clearScreen();
// Play a song file on a channel (0 or 1)
playSong(text-or-filename, optional-channel-number);
// Stop playing a song on a channel
stop(optional-channel-number);
// Mute the sound
muteSound();
// UnMute the sound
unmuteSound();
// Get a random true value based on a certain percentage
var isTrue = getRandomChance(percentage, optional-scale);
// Get a random integer between a set range
var intVal = getRandomInt(lower-limit, upper-limit);
// Get the current high scores list from a file as an array of object in the form:
// [ { name: "Dave", points: 10 }, { name: "Sara", points: 20 } ...]
var highScores = loadHighScores();
// Save the current high score to a file
saveHighScore(name, points, optional-max-scores);
// Add a command to the player's command menu
addCommand(command-name-or-function);
// OR
addCommand(command-name, function);
// Remove a command from the player's command menu
removeCommand(command-name);
// Sets the value for a string used within a description template for example {{string-name}}, the {{string-name}} will be replaced with the supplied value.
setTemplateString(string-name, value);
```
The following functions/methods are part of the room object API:
```
// First get the object for the room
var room = getRoom(room-name);
// Get the text description for the room
var text = room.getDescription();
// Set the text description for the room
room.setDescription(text);
// Print the room's current description
room.printDescription();
// Get the text (ascii) picture for the room
var text = room.getPicture());
// Set the text (ascii) picture for the room
room.setPicture(text);
// Print the room's current picture
room.printPicture();
// Get an array listing of the names of the things in the room
var thingNames = room.listThings();
// Determine if the room contains a certain thing name
var roomHasThing = room.contains(thing-name);
// Add a thing object to the room (uses the same object format as in world.json)
addThing(thing-name, thing-object);
// Get a thing object from the room
var thing = room.getThing(thing-name);
// Remove a thing from the room, returns true/false if thing was succesfully removed
var wasThingRemoved = room.removeThing(thing-name);
// Get an array listing of the naems of the exits in the room
var exitNames = room.listExits();
// Add an exit to the room
room.addExit(exit-name, to-room-name);
// Remove and exit from the room, return true/false if exit was succesfully removed
room.removeExit(exit-name);
// Get an array listing of the rooms adjacent to this one based on the exits available
var roomNames = room.listAdjacentRooms();
// Get the exit for a room that is adjacent to this one based on the room name
var exitName = room.getExitForRoom(adjacent-room-name);
```
The following functions/methods are part of the room object API:
```
// First, get the object for the thing.
// If room-name is not provided, search is global
// If room-name is provided, search will be limited to room and player's inventory
var thing = getThing(thing-name, optional-room-name);
// Get the text description for the thing
var text = thing.getDescription();
// Set the text description for the thing
thing.setDescription(text);
// Print the thing's current description
thing.printDescription();
// Get the text (ascii) picture for the thing
var text = thing.getPicture());
// Set the text (ascii) picture for the thing
thing.setPicture(text);
// Print the thing's current picture
thing.printPicture();
// Get an array listing of the thing's attributes
var attributeNames = thing.listAttributes();
// Get the value of a thing's attribute given its name
var attribute = thing.getAttribute(attribute-name);
// Set the value of a thing's attribute given its name and value
thing.setAttribute(attributeName, value);
// Determine if the thing is stationary based on its stationary attribute
var isStationary = thing.isStationary();
// Determine if the thing is visible based on its hidden attribute
var isVisible = thing.isVisible();
// Set the thing's hidden attribute to true
thing.hide();
// Set the thing's hidden attribute to false
thing.reveal();
// Determine if the thing is alive by checking that health attribute > 0
var isAlive = thing.isAlive();
// Subtract from the thing's health attribute by a certain amount, limit to 0
thing.injure(amount);
// Add to the thing's health attribute by a certain amount, limit to 10
thing.heal(amount);
// Set thing's health attribute to 0
thing.kill()
// Move thing to another room, or through an exit
thing.move(in-direction-or-room-name);
// Determine if a thing is expired by checking that uses attribute is 0
var isExpired = thing.isExpired();
// Decrement thing's uses attribute by amount or 1 if not provided
thing.expend();
// Expire thing by setting thing's uses attribute to 0
thing.expire();
// Get thing's current location name
var locationName = thing.getLocationName();
// If thing is the player then get its inventory object, if not return undefined
var inventory = thing.getInventory();
The following functions/methods are part of the inventory object API:
// First, get the inventory from the player
var inventory = getInventory();
// Get an array listing of the player's inventory
var thingNames = inventory.list();
// Determine if the player's inventory contains a thing given its name
var inventoryContainsThing = inventory.contains(thing-name);
// Remove a thing from the player's inventory or return false if it wasn't found
inventory.removeThing(thing-name);
// Get a thing object from the player's inventory
var thing = inventory.getThing(thing-name);
```
All callbacks need to be registerd using the `addCallback(callbackName or function)` function. Returning nothing or false from a callback will override the default behavior, returning true will run execute behavior.
- `beforeWelcome()`: Called before the picture and description of the welcome screen are displayed.
- `afterWelcome()`: Called after the picture and description of the welcome screen are displayed.
- `onPrompt(prompt)`: Called before prompt displayed. Add to prompt or return a different prompt to override the default.
- `onCommand(commandName)`: Called before a command is run. Can be used to override/add to default command behavior.
- `onLookAt(roomName) or onLookAtRoomName()`: Called before default _look_ command output.
- `onInspect(thingName) or onInspectThingName()`: Called before default _inspect_ command output.
- `onTake(thingName) or onTakeThingName()`: Called before default _take_ command output.
- `onCarrying()`: Called before default _carrying_ command output.
- `onUse(thingName) or onUseThingName()`: Called before default _use_ command output.
- `afterUse(thingName) or afterUseThingName()`: Called after _use_command.
- `onDrop(thingName) or onDropThingName()`: Called before default _drop_ command output.
#### Attack Command Callbacks
- `onAttack(thingName, withWeaponName) or onAttackThingName(withWeaponName)`: Called before running an attack on a thing and before default _attack_ command output.
- `onAttackUsing(weaponName, thingName) or onAttackUsingWeaponName(thingName)`: Called before running an attack on a thing and before default _attack_ command output.
- `onExpired(weaponName) or onExpiredWeaponName()`: Called after a weapon has just expired.
- `afterHit(thingName, damage) or afterHitThingName(damage)`: Called after a thing has been hit in an attack by the player.
- `onKilled(thingName, usingWeaponName) or onKilledThingName(usingWeaponName)`: Called before a thing has been killed by the player.
- `afterKilled(thingName, usingWeaponName) or afterKilledThingName(usingWeaponName)`: Called after a thing has been killed by the player.
- `onRunAttacks()`: Called before character attacks are run against player.
- `onAttackedBy(thingName) or onAttackedByThingName()`: Called before a thing attacks the player.
- `onHitBy(thingName, damage) or onHitByThingName(damage)`: Called before a thing hits the player.
- `afterHitBy(thingName, damage) or afterHitByThingName(damage)`: Called after a thing hits the player.
- `onKilledBy(thingName) or onKilledByThingName()`: Called before the player is killed by a thing.
#### Move Command Callbacks
- `onMoveTo(roomName, fromRoomName) or onMoveToRoomName(fromRoomName)`: Called before the player moves from one room to another.
- `onExit(fromRoomName, toRoomName) or onExitRoomName(toRoomName)`: Called when the player exits a room.
- `beforeEnter(roomName, fromRoomName) or beforeEnterRoomName(fromRoomName)`: Called before player enters a room.
- `onPrintRoom(roomName) or onPrintRoomRoomName()`: Called before the default room picture and description is printed.
- `onEnter(roomName, fromRoomName) or onEnterRoomName(fromRoomName)`: Called before automatic look is output when entering a room.
- `afterEnter(roomName, fromRoomName) or afterEnterRoomName(fromRoomName)`: Called after player enters a room.
#### Quit Callbacks
- `onQuit()`: Called before end screen is displayed.