UNPKG

adventure-engine

Version:

Simple text based adventure game library.

439 lines (321 loc) 18.4 kB
Simple text-based adventure game engine for NodeJS. ## Setting up repl.it 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. ## Creating the World - 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/). ### World File Structure - 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." } } ``` ### Defining an Individual Room - 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. ### Template Strings 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. ### Text Display Control Codes 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# - pause for some amount of time where # is 0-9 in 100 ms intervals, 0 is 1 second %r# - repeat some number of times where # is 0-9 where 0 repeats forever %n# - add a number of blank lines where # is 0-9 where 0 is 10 lines ``` ## Adding Music 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#4 4, Eb4 1, D3 16, R 4, ! 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# controls the tone for where # is 0-3 depending on the desired waveform ! %r# controls the number of repeats where # is 0-9, 0 being repeat forever ! 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 ``` ## Writing the Code 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](#callbacks) section for more information on this. - 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 ... } ``` ### Global API 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); ``` ### Room Object API 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); ``` ### Thing Object API 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(); ### Inventory Object API 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); ``` ### <a id="callbacks"></a>Callbacks 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. #### Welcome Callbacks - `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. #### Basic Command Callbacks - `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.