Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
1d1b598
Implemented basic verb editor functionality
Dak0r Aug 12, 2023
cb34429
Implemented object editor
Dak0r Aug 13, 2023
b9fdc00
Added Location editor
Dak0r Aug 14, 2023
0c5e226
Fixed location object ordering
Dak0r Aug 15, 2023
a7f5097
Added element refresh, instead of reloading everything
Dak0r Aug 16, 2023
f2148a1
Improved Ui structure
Dak0r Aug 16, 2023
756a4f6
Added duplicate button for all types
Dak0r Aug 16, 2023
2582a4b
Implemented table layout
Dak0r Aug 23, 2023
00fa308
Added retro theme css to editor
Dak0r Aug 24, 2023
7c72dd6
Improved theme and replaced type select
Dak0r Aug 28, 2023
f5d3f80
Updated engine to recent actions changes
Dak0r Sep 13, 2023
ff0b7a7
Added Preview Tab to editor
Dak0r Sep 13, 2023
2625b4e
small engine clean up
Dak0r Sep 13, 2023
bcdc0ca
introduced gameState
Dak0r Sep 13, 2023
677ba91
Removed name property, to avoid modifying database in engine
Dak0r Sep 13, 2023
4365a42
added persistent preview
Dak0r Sep 13, 2023
ffb73ba
Added Save and Close buttons
Dak0r Sep 13, 2023
d5d7f8f
Added local caching of database
Dak0r Sep 13, 2023
61a9da0
Included jquery and terminal dependencies
Dak0r Dec 10, 2023
d4eebed
Added gitignore
Dak0r Dec 10, 2023
59251ab
Fixed type switch on delete
Dak0r Dec 10, 2023
5605b8a
Fixed creation of empty elements
Dak0r Dec 10, 2023
cd2d1fa
Removed usableObjects from Schema
Dak0r Dec 10, 2023
e485a1d
Fixed unique name alert
Dak0r Dec 10, 2023
1f260fc
Fixed object creation
Dak0r Dec 10, 2023
d96a4d6
Fixed object name access
Dak0r Dec 10, 2023
1625fb8
Fixed formatting in saved json
Dak0r Dec 10, 2023
681c7aa
Fixed action texts in editor
Dak0r Dec 15, 2025
1e3f804
Improved UI for Editing Table
Dak0r Dec 15, 2025
507fd01
Improved table headlines
Dak0r Dec 15, 2025
ed7ec7d
Improved TextArea Layout
Dak0r Dec 15, 2025
7c2da63
Updated Select Field UI
Dak0r Dec 15, 2025
0316311
Added support for this reference and object specific failures
Dak0r Dec 16, 2025
789ffaf
Added improved Functions Editor
Dak0r Dec 17, 2025
4a3b63c
Improved debugger ui
Dak0r Dec 17, 2025
e91ade1
Improved button font colors
Dak0r Dec 17, 2025
8050e11
Improved drag and drop
Dak0r Dec 17, 2025
4a9157d
Improved new project template
Dak0r Dec 17, 2025
7e425e3
Added parser ignored words to editor
Dak0r Dec 17, 2025
f31873f
Added parsing errors to game database
Dak0r Dec 17, 2025
5468cfc
Improved Delete and Remove wording
Dak0r Dec 17, 2025
891385f
Improved new element placeholder
Dak0r Dec 17, 2025
cc6662f
Added option to edit objects form location screen
Dak0r Dec 17, 2025
d134ae9
Changed icon to remove wording for locations
Dak0r Dec 17, 2025
519d470
Renamed action to commands to reduce ambiguity
Dak0r Dec 17, 2025
85883d6
Fixed let usages
Dak0r Dec 17, 2025
6299eec
Improved Formatting
Dak0r Dec 17, 2025
5b5b716
Improved Location Edit button Ui
Dak0r Dec 18, 2025
c97c642
Added basic game state editing
Dak0r Dec 18, 2025
bdf389e
Implemented basic analytics functionality
Dak0r Dec 19, 2025
8554d92
Improved file structure
Dak0r Dec 19, 2025
eae6e8b
Improvd Editor debugger ui
Dak0r Dec 19, 2025
7d8c3ca
Added placeholder strings that are replaced at runtime
Dak0r Dec 20, 2025
09a54f3
Fixed help command
Dak0r Dec 22, 2025
71b99f1
Adjusted json scheme name and id
Dak0r Dec 22, 2025
a05befe
Added color-shift logo via css
Dak0r Dec 22, 2025
53597e8
Fixed analytics event
Dak0r Dec 22, 2025
c419065
Replaced player log textarea with div
Dak0r Dec 23, 2025
b6398a1
Tweaked auto. into text
Dak0r Dec 23, 2025
47ed3b9
Removed jquery dependency from engine and player
Dak0r Dec 23, 2025
886fc35
Improved included player example a lot
Dak0r Dec 24, 2025
5215707
Made Ineventory a list of object ids instead of objects
Dak0r Dec 24, 2025
f0633e0
Implemented support for loading and saving games
Dak0r Dec 30, 2025
dd0d73f
Reviewed var let and const usages
Dak0r Dec 30, 2025
f3d3457
Removed todo list
Dak0r Dec 30, 2025
c0b28c8
Added log when the game is saved
Dak0r Dec 30, 2025
08e6b81
Added documentation and editor for restartGame
Dak0r Dec 30, 2025
c28f832
Removed unused code to find 2nd object
Dak0r Dec 30, 2025
f1e626a
Added unit tests
Dak0r Dec 30, 2025
87cbd45
Allowing custom name for duplicate button
Dak0r Dec 30, 2025
c59bace
Improved Editor save file
Dak0r Dec 30, 2025
3b101fb
Added second room to new project
Dak0r Dec 30, 2025
c11aaf3
Added tadb suffix to new project template
Dak0r Dec 30, 2025
82c9b28
Added unit tests for goto location
Dak0r Dec 30, 2025
63d88d1
Improved Editor Styling
Dak0r Dec 30, 2025
930d853
Fixed unit tests in ci
Dak0r Dec 30, 2025
3b2fb9b
Change capitalization on templates folder
Dak0r Dec 30, 2025
9a4cd4e
Fixed outputClear delay and some ui issues in player
Dak0r Dec 30, 2025
28293c6
Added screenshots to readme
Dak0r Dec 30, 2025
e62d19f
Tweaked name of pipeline
Dak0r Dec 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

[*.js]
indent_size = 4
24 changes: 24 additions & 0 deletions .github/workflows/test-pipeline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Tests CI Pipeline

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20.x]
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test --silent
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
my-games/
node_modules/
5 changes: 4 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"recommendations": [
"tberman.json-schema-validator",
"ms-vscode.live-server"
"ms-vscode.live-server",
"wayou.vscode-todo-highlight",
"esbenp.prettier-vscode",
"orta.vscode-jest"
]
}
249 changes: 187 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,122 +1,247 @@
# TextAdventureJS
A text based adventure engine written in Javascript.

Here's a very basic example, that is included in this Repositroy:
https://dak0r.github.io/TextAdventureJS/example.html
A text based adventure engine written in Javascript.
This repo comes with a player that uses the engine as well as an editor to create games for it.

A different project, that uses TextAdventureJS can be foundon my website:
https://www.danielkorgel.com
The library and the player are written in pure JavaScript.
The editor uses jquery.

## Player
<img src="./docs/player.gif" width="400" alt="Animated demo for the textAdventureJS player" />

Try it here: https://dak0r.github.io/TextAdventureJS/player/

## Editor

This repo also provides a full editor including debugger functionality for creating your own games:

<img src="./docs/editor.jpg" width="600" alt="Animated demo for the textAdventureJS player" />

Try it here: https://dak0r.github.io/TextAdventureJS/editor/

## Usage

See `example.html` for a working minimal example.
A barebones example that uses jquery:

```js
// Defines where to write output
function witeLine(outputLine){
$("#outputArea").append(outputLine);
}
// Clears output area
function clearArea(){
$("#outputArea").val("");
}
// Defines where to write output
function witeLine(outputLine) {
$("#gameLog").append(outputLine + "<br />");
}
// Clears written output from the area
function clearArea() {
$("#gameLog").html("");
}
// Read user input
function readInput() {
const inputText = $("#inputField").val().trim();
writeLine(inputText);
textAdv.input(inputText);
$("#inputField").val("");
}

// Add event handler for reading user input:
$("#submit").click(function() { readInput(); });

// Init textAdventureJS and load a game
var textAdvEngine = new textAdventureEngine(witeLine, clearArea);
textAdvEngine.loadDatabaseFromFile("game.json");
```
with this html elements:

// Init engine and load a game
var textAdv = new textAdventureEngine(witeLine, clearArea);
textAdv.loadDatabaseFromFile("game.TADB.json");
```html
<div id="gameLog"></div>
<input id="inputField" type="text"/>
<button id="submit">Submit</button>
```

// Send Input to game
textAdv.input("look at cookie");
See [player/index.html](./player/index.html) for a more complex example.

```
## Game Database

## Game Database
A Text Adventure Database (TADB) is JSON file which describes games that can run in the TextAdventureJS Engine.
A Text Adventure Game Database is JSON file which describes games that can run in the TextAdventureJS Engine.

`.tadb.json` files can be validated using the JSON schema in this repo: `textAdventureDatabase.schema.json`.
The schema contains also includes descriptions for the properties. I recommend using the [JSON Schema Validator](https://marketplace.visualstudio.com/items?itemName=tberman.json-schema-validator) for this task.
These game files can be validated using the JSON schema in this repo: [textAdventureGameDatabase.schema.json](./textAdventureGameDatabase.schema.json).

I recommend using the [JSON Schema Validator](https://marketplace.visualstudio.com/items?itemName=tberman.json-schema-validator), if editing the json files manually.

## Concept

Each game exists of `objects` which are either in the players inventory or in `locations`. The player can interact with object using `verbs`.

### Locations

Locations are basically groups of `objects`.

The description text of a location soley exists of the objects which can be found in it. This means an empty location has no description. Thus a location should always have at least one object, at any given moment.

### Verbs

Verbs are commands that the user can type. \
Each verb has a...
- a name
- list of synonyms (`words`)
- a text that is shown, in case the verb can't be used with the object the user mentioned (`failure`) \
E.G. if the user tries to 'open' an object, that can't be opened.
Each verb has a...

- a name
- list of synonyms (`words`)
- a text that is shown, in case the verb can't be used with the object the user mentioned (`failure`) \
E.G. if the user tries to 'open' an object, that can't be opened.

### Objects
Everything that player can see or interact with is an object.

Everything that the player can see or interact with is an object.

Each object has...

- a unique name
- a list of `words` that the player can type to refer to this object
- an optional text that is added to the location description if the object is in the players current location or in his inventory (`locationDescription`)
- an optional text that is added to the location description if the object is in the players current location or in their inventory (`locationDescription`)
- a list of `actions` which describes the `verbs` that can be used with this object. \
each of these actions has...
- a `text` that will be shown if the verb is used with this object
- zero, one or more functions listed under `action`, which can be used to change the current location and its objects (see Functions)
- a list of 'usableObjects' *which is currently unused*. \
It is designed to implement usage of object with other objects.
each of these actions has...
- a `text` that will be shown if the verb is used with this object
- zero, one or more functions listed under `commands`, which can be used to change the current location and its objects (see Commands)
- a list of 'usableObjects' _which is currently unused_. \
It is designed to implement usage of object with other objects.

#### Changing Objects

In almost every game there are scenarios where objects have to change their description texts or behaviors during gameplay. For example if you need a `chest` which the player can open only once, after that it will be open.

In this case you have to create a second object `chest_opened`, which has it's own description and verbs it can handle.
Now you can use the `objectReplaceInLocation` function in `chest`s `open` action to replace `chest` in the current location with `chest_opened`.

To close the chest again, you can use `objectReplaceInLocation` again in `chest_opened`s `close` action.

### Functions
Functions can be used in actions to modify the current location or the plazers inventory.
#### Object specific failure texts

If the player tries to do soemthing with an object and the action is not defined, the engine will output the default verb failure sentance. In some cases you might find it more immersive to have an object specfic failure text, though verbs have no object specifc failures, as they usually will vary by object.

So In this case, you simply have to add the verb as an action to the object and add your failure message as text to the action.

### Placeholders
When adding a text to an action, you can use predefined placeholders which will be filled in automatically when the text is written. If the placeholder does not apply in the given context, the value is not replaced.

Existing placeholders are:
- `{verb}` is replaced with the word the player used to describe the verb / action
- `{object}` is replaced with the word the player used to describe the object

### Commands

Commands must be used for any logic that goes beyond outputting text. You can change locations, add and remove objects from location or the players inventory and more.

#### 'this' in command parameters

If the command is supposed to affect the object that the action is defined on, you can refer to it using `this` instead of its unique nanme.

#### objectRemoveFromLocation
```
objectRemoveFromLocation {objectId}
```

```
objectRemoveFromLocation {objectName}
objectRemoveFromLocation this
```

Removes the given object from the current location

#### objectAddToLocation
```
objectAddToLocation {objectId}
```

```
objectAddToLocation {objectName}
objectAddToLocation this
```

Adds a given object to the current location

#### objectReplaceInLocation
```
objectReplaceInLocation {objectIdToRemove} {objectIdToAdd}
```
Removes `{objectIdToRemove}` and adds `{objectIdToAdd}`. Shorthand for sequentially calling `objectRemoveFromLocation` and `objectAddToLocation`.

```
objectReplaceInLocation {objectNameToRemove} {objectNameToAdd}
objectReplaceInLocation this {objectNameToAdd}
```

Removes `{objectNameToRemove}` and adds `{objectNameToAdd}`. Shorthand for sequentially calling `objectRemoveFromLocation` and `objectAddToLocation`.

Useful if an object transitions into a different one like `chest_closed` to `chest_opened`.

#### gotoLocation
```
gotoLocation {locationId}
```

```
gotoLocation {locationName}
```

Changes the current location to a different one

#### showLocationDescription
```

```
showLocationDescription
```
```

Automatically shows the current location description, as if the user typed 'look'

#### inventoryAdd
```
inventoryAdd {objectId}
```
Adds the item to users inventory.
The user can have multiple items in his inventory, the location descriptions will be listed below each other.

```
inventoryAdd {objectName}
inventoryAdd this
```

Adds the item to users inventory.
The player can have multiple items in their inventory, the location description will list them sequentially, after the objects in the location itself.

#### inventoryRemove
```
inventoryRemove {objectId}
```
Removes the item from users inventory

```
inventoryRemove {objectName}
inventoryRemove this
```

Removes the item from users inventory

#### restartGame

```
restartGame
```

Restarts the game. If a game save exits, it is deleted.
Can be used to restart the game on demand or when the game was finished.

### Analytics

TextAdventureJS does not come with any analytics. Though it allows to provide a function which is then called for pre-defined analytics related events. The events are all related to the command parser, with the intention to improve the games based on player data.

Defined events are:

- `command`: a command was successfully parsed
- `unknown_verb`: the user tried to use a verb that is not defined
- `unknwon_object`: the user tried to use an object that is not present in the players current location or inventory.
- `unkown_verb_for_object`: the user tried to do something with an object that is not defined
- `unknown_command`: other parsing error

Each event contains a body, that includes:

- `input`: the full command the user entered
- `currentLocation`: name of the current location
- `location`: list of all object in the current location
- `inventory`: list of all objects in the players inventory

Example Analytics Function:

```js
function analyticsFunction(eventName, eventData) {
console.log("Analytics event: " + eventName);
console.log(eventData);
}
```

## Testing

## Running Editor and Player locally
Running the editor and player html files locally requires a local webserver.
I recommend the `ms-vscode.live-server` extension for vscode.

### Unit Tests
Quick steps to run tests locally:

1. Install Node.js from https://nodejs.org/ if you don't already have it.
2. From the project root run:
- `npm install` (installs dev dependencies like Jest)
- `npm test` (runs the test suite)
21 changes: 11 additions & 10 deletions Templates/empty.tadb.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
{
"$schema": "../textAdventureDatabase.schema.json",
"$schema": "../textAdventureGameDatabase.schema.json",

"general": {
"title": "TextAdventureJS Empty Database Template",
"author": "Your Name",
"version": "0.1",
"request": [ "", "What do you do?" ],
"continue_enabled": true,
"request": ["", "What do you do?"],
"start": {
"text": "Welcome to the Empty Template",
"text": ["Welcome to the Empty Template"],
"inventory": "",
"action": "gotoLocation first_room"
}
},
"ignored_words" :[ ],
"verbs": {
},
"objects": {
"commands": []
},
"parser_ignored_words": [],
"parser_error_text": "Sorry, I didn't understand that.",
"parser_unknown_verb_text": "Sorry, I don't know how to do that."
},
"verbs": {},
"objects": {},
"locations": {
"first_room": {
"objects": []
Expand Down
Loading