diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..4a8fae8
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+ "configurations": [
+ {
+ "type": "chrome",
+ "name": "Editor",
+ "request": "launch",
+ "url": "http://127.0.0.1:3000/editor/index.html"
+ },
+ {
+ "type": "chrome",
+ "name": "Player",
+ "request": "launch",
+ "url": "http://127.0.0.1:3000/player/index.html"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 70ca1f7..f9d8be3 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,17 @@
# TextAdventureJS
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.
+Allows you to create your own text adventure games and embed them into your website or share and play them with included demo player.
+
+- Games are json files, that follow the textAdventureGameDatabase schema (tadb).
+- Editor folder contains an editor that allows to create games with a GUI.
+- Player folder contains a demo player that shows how to integreate the engine
The library and the player are written in pure JavaScript.
-The editor uses jquery.
+The editor uses jQuery.
## Player
-
+
Try it here: https://dak0r.github.io/TextAdventureJS/player/
@@ -15,44 +19,63 @@ Try it here: https://dak0r.github.io/TextAdventureJS/player/
This repo also provides a full editor including debugger functionality for creating your own games:
-
+
Try it here: https://dak0r.github.io/TextAdventureJS/editor/
## Usage
-
-A barebones example that uses jquery:
-
+Usage is simple: the engine needs to be initilized with a JS functions that allows the engine to write output and to clear all written output. Then any compatible game file can be loaded:
```js
-// Defines where to write output
-function witeLine(outputLine) {
- $("#gameLog").append(outputLine + " ");
-}
-// 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");
+ var textAdvEngine = new textAdventureEngine(writeLine, clearArea);
+ textAdvEngine.loadDatabaseFromFile(
+ "https://dak0r.github.io/TextAdventureJS/games/new_project.tadb.json"
+ );
```
-with this html elements:
+A minimalistic working example, which uses jquery to keep it short:
```html
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
```
See [player/index.html](./player/index.html) for a more complex example.
diff --git a/Templates/new_project.tadb.json b/Templates/new_project.tadb.json
deleted file mode 100644
index df69190..0000000
--- a/Templates/new_project.tadb.json
+++ /dev/null
@@ -1,189 +0,0 @@
-{
- "$schema": "../textAdventureGameDatabase.schema.json",
- "general": {
- "title": "New TextAdventureJS Game",
- "author": "Your Name",
- "version": "0.1",
- "continue_enabled": true,
- "request": ["", "What do you do?"],
- "start": {
- "text": ["Welcome to the textAdventureJS Mini Example"],
- "commands": ["gotoLocation first_room"]
- },
- "parser_ignored_words": [
- "to",
- "through",
- "on",
- "off",
- "from",
- "around",
- "at"
- ],
- "parser_error_text": "Sorry, I didn't understand that.",
- "parser_unknown_verb_text": "Sorry, I don't know how to do that."
- },
- "verbs": {
- "look": {
- "failure": "Sorry, you can't see that.",
- "words": ["look", "view", "watch", "read", "search"],
- "standalone_action": {
- "text": [],
- "commands": ["showLocationDescription"]
- }
- },
- "restart": {
- "failure": "Be careful! 'restart' will reset the game.",
- "words": ["restart"],
- "standalone_action": {
- "text": [],
- "commands": ["restartGame"]
- }
- },
- "pickup": {
- "failure": "Sorry, you can't see that.",
- "words": ["pick", "pickup", "lift", "take", "get", "reach"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "drop": {
- "failure": "How do you want to drop that?",
- "words": ["drop", "let go"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "activate": {
- "failure": "Sorry, you can't do that.",
- "words": ["turn", "power", "switch"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "go": {
- "failure": "Sorry, you can't go there.",
- "words": ["go", "walk", "run", "goto"],
- "standalone_action": {
- "text": ["Where do you want to {verb}?"],
- "commands": []
- }
- },
- "open": {
- "failure": "Sorry, you can't open that.",
- "words": ["open", "break"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "close": {
- "failure": "Sorry, you can't close that.",
- "words": ["close", "shut"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "jump": {
- "failure": "Sorry, this is not possible.",
- "words": ["jump"],
- "standalone_action": {
- "text": ["You jump up and down."],
- "commands": []
- }
- },
- "use": {
- "failure": "Well.. this does not work.",
- "words": ["use", "combine", "throw", "attack"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "light": {
- "failure": "Well.. this does not work.",
- "words": ["light", "ignite", "burn", "fire"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- },
- "remove": {
- "failure": "Well.. this does not work.",
- "words": ["remove", "break", "split", "destroy"],
- "standalone_action": {
- "text": ["What do you want to {verb}?"],
- "commands": []
- }
- }
- },
- "objects": {
- "template_object": {
- "words": ["object", "obj"],
- "locationDescription": "An object is lying on the floor.",
- "actions": {
- "pickup": {
- "text": ["Okay got it."],
- "commands": [
- "objectRemoveFromLocation this",
- "inventoryAdd template_object_pickedUp"
- ]
- },
- "look": {
- "text": ["A mysterious object."],
- "commands": []
- }
- },
- "useableObjects": {}
- },
- "template_object_pickedUp": {
- "words": ["object", "obj"],
- "locationDescription": "You are holding an object in your hands.",
- "actions": {
- "drop": {
- "text": ["Okay dropped it."],
- "commands": [
- "objectAddToLocation template_object",
- "inventoryRemove this"
- ]
- },
- "look": {
- "text": ["A mysterious object."],
- "commands": []
- }
- },
- "useableObjects": {}
- },
- "door_to_second_room": {
- "words": ["door", "north", "up"],
- "locationDescription": "A door is leading north.",
- "actions": {
- "go": {
- "text": ["You walk through the door."],
- "commands": ["gotoLocation second_room"]
- }
- }
- },
- "door_to_first_room": {
- "words": ["door", "south", "down"],
- "locationDescription": "A door is leading south.",
- "actions": {
- "go": {
- "text": ["You walk through the door."],
- "commands": ["gotoLocation first_room"]
- }
- }
- }
- },
- "locations": {
- "first_room": {
- "objects": ["template_object", "door_to_second_room"]
- },
- "second_room": {
- "objects": ["door_to_first_room"]
- }
- }
-}
diff --git a/__tests__/textAdventureEngine.test.js b/__tests__/textAdventureEngine.test.js
index 1a7a6c9..9942800 100644
--- a/__tests__/textAdventureEngine.test.js
+++ b/__tests__/textAdventureEngine.test.js
@@ -3,12 +3,12 @@ const path = require("path");
let sampleGame;
let found = false;
-const p = path.join(__dirname, "..", "templates", "new_project.tadb.json");
+const p = path.join(__dirname, "..", "games", "new_project.tadb.json");
if (fs.existsSync(p)) {
sampleGame = JSON.parse(fs.readFileSync(p, "utf8"));
found = true;
} else {
- throw new Error("Could not find templates/new_project.tadb.json.");
+ throw new Error("Could not find sample game at " + p);
}
const TextAdventureEngine = require("../textAdventure.js");
@@ -52,18 +52,18 @@ describe("textAdventureEngine parser & action integration tests (using template)
test("take object moves it to inventory and removes from location", () => {
engine.input("take object");
const gs = engine.devGetGameState();
- expect(gs.inventory).toContain("template_object_pickedUp");
+ expect(gs.inventory).toContain("demo_object_pickedUp");
const objects = gs.locations[gs.currentLocation].objects;
- expect(objects).not.toContain("template_object");
+ expect(objects).not.toContain("demo_object");
});
test("drop object returns it to location", () => {
engine.input("take object");
engine.input("drop object");
const gs = engine.devGetGameState();
- expect(gs.inventory).not.toContain("template_object_pickedUp");
+ expect(gs.inventory).not.toContain("demo_object_pickedUp");
expect(gs.locations[gs.currentLocation].objects).toContain(
- "template_object"
+ "demo_object"
);
});
@@ -156,7 +156,7 @@ describe("textAdventureEngine parser & action integration tests (using template)
);
engine2.loadDatabaseFromObject(sampleGame);
expect(engine2.devGetGameState().inventory).toContain(
- "template_object_pickedUp"
+ "demo_object_pickedUp"
);
});
});
diff --git a/css/channel-shift.css b/css/channel-shift.css
deleted file mode 100644
index e864228..0000000
--- a/css/channel-shift.css
+++ /dev/null
@@ -1,22 +0,0 @@
-.channel-shift {
- position: relative;
- padding: 0 0 0 0;
- &:before,
- &:after {
- top: 0;
- position: absolute;
- left: 0;
- padding: 0 0 0 0;
- display: block;
- mix-blend-mode: screen;
- content: attr(data-text);
- }
- &:before {
- color: #ff3c74;
- transform: translate(-1px, 1px);
- }
- &:after {
- transform: translate(1px, -1px);
- color: #62c4ff;
- }
-}
diff --git a/editor/index.html b/editor/index.html
index bae78e6..01a9a4f 100644
--- a/editor/index.html
+++ b/editor/index.html
@@ -35,8 +35,7 @@
-
-
+
diff --git a/editor/tba_editor.js b/editor/tba_editor.js
index 4b7c13d..368470e 100644
--- a/editor/tba_editor.js
+++ b/editor/tba_editor.js
@@ -307,7 +307,7 @@ function deleteDatabaseFromStorage() {
async function getDefaultProjectJson() {
try {
- const response = await fetch("../templates/new_project.tadb.json");
+ const response = await fetch("../games/new_project.tadb.json");
const json = await response.json();
return JSON.stringify(json);
} catch (err) {
diff --git a/Templates/empty.tadb.json b/games/empty.tadb.json
similarity index 85%
rename from Templates/empty.tadb.json
rename to games/empty.tadb.json
index e49f5a8..64bce5c 100644
--- a/Templates/empty.tadb.json
+++ b/games/empty.tadb.json
@@ -1,6 +1,5 @@
{
- "$schema": "../textAdventureGameDatabase.schema.json",
-
+ "$schema": "https://dak0r.github.io/TextAdventureJS/textAdventureGameDatabase.schema.json",
"general": {
"title": "TextAdventureJS Empty Database Template",
"author": "Your Name",
diff --git a/templates/new_project.tadb.json b/games/new_project.tadb.json
similarity index 94%
rename from templates/new_project.tadb.json
rename to games/new_project.tadb.json
index df69190..b0e474b 100644
--- a/templates/new_project.tadb.json
+++ b/games/new_project.tadb.json
@@ -1,5 +1,5 @@
{
- "$schema": "../textAdventureGameDatabase.schema.json",
+ "$schema": "https://dak0r.github.io/TextAdventureJS/textAdventureGameDatabase.schema.json",
"general": {
"title": "New TextAdventureJS Game",
"author": "Your Name",
@@ -121,7 +121,7 @@
}
},
"objects": {
- "template_object": {
+ "demo_object": {
"words": ["object", "obj"],
"locationDescription": "An object is lying on the floor.",
"actions": {
@@ -129,7 +129,7 @@
"text": ["Okay got it."],
"commands": [
"objectRemoveFromLocation this",
- "inventoryAdd template_object_pickedUp"
+ "inventoryAdd demo_object_pickedUp"
]
},
"look": {
@@ -139,14 +139,14 @@
},
"useableObjects": {}
},
- "template_object_pickedUp": {
+ "demo_object_pickedUp": {
"words": ["object", "obj"],
"locationDescription": "You are holding an object in your hands.",
"actions": {
"drop": {
"text": ["Okay dropped it."],
"commands": [
- "objectAddToLocation template_object",
+ "objectAddToLocation demo_object",
"inventoryRemove this"
]
},
@@ -180,7 +180,7 @@
},
"locations": {
"first_room": {
- "objects": ["template_object", "door_to_second_room"]
+ "objects": ["demo_object", "door_to_second_room"]
},
"second_room": {
"objects": ["door_to_first_room"]
diff --git a/player/textadventurejs_teaser.tadb.json b/games/textadventurejs_teaser.tadb.json
similarity index 99%
rename from player/textadventurejs_teaser.tadb.json
rename to games/textadventurejs_teaser.tadb.json
index 24b11ba..4a7be95 100644
--- a/player/textadventurejs_teaser.tadb.json
+++ b/games/textadventurejs_teaser.tadb.json
@@ -1,11 +1,11 @@
{
- "$schema": "../textAdventureGameDatabase.schema.json",
+ "$schema": "https://dak0r.github.io/TextAdventureJS/textAdventureGameDatabase.schema.json",
"general": {
"title": "TextAdventureJS Teaser",
"author": "Daniel Korgel",
"version": "1.0",
"request": ["", "What do you do?"],
- "continue_enabled": true,
+ "continue_enabled": false,
"start": {
"text": ["", "", "", "You wake up with a headache..."],
"commands": ["gotoLocation start_chamber"]
diff --git a/player/index.html b/player/index.html
index 556eff4..68459b8 100644
--- a/player/index.html
+++ b/player/index.html
@@ -1,7 +1,7 @@
- TextAdventureJS Player
+ textAdventureJS Player
-
+
@@ -28,14 +28,14 @@
analyticsFunction // from textAdventurePlayer.js
);
await textAdvEngine.loadDatabaseFromFile(
- "./textadventurejs_teaser.tadb.json"
+ "../../games/textadventurejs_teaser.tadb.json"
);
});
-
TextAdventureJS
+
TextAdventureJS Player
diff --git a/shared/channel-shift.css b/shared/channel-shift.css
new file mode 100644
index 0000000..fc7044e
--- /dev/null
+++ b/shared/channel-shift.css
@@ -0,0 +1,29 @@
+/**
+* A css class that applies a RGB channel shift effect to text elements.
+* Usage:
+*
Your Text Here
+* Wrapper div is required. The data-text attribute describe the text that the effect is applied to.
+* If the text is longer, the effect will only be applied to the first part, which should match the data-text attribute.
+*/
+.channel-shift {
+ position: relative;
+ padding: 0 0 0 0;
+ &:before,
+ &:after {
+ top: 0;
+ position: absolute;
+ left: 0;
+ padding: 0 0 0 0;
+ display: block;
+ mix-blend-mode: screen;
+ content: attr(data-text);
+ }
+ &:before {
+ color: #ff3c74;
+ transform: translate(-1px, 1px);
+ }
+ &:after {
+ transform: translate(1px, -1px);
+ color: #62c4ff;
+ }
+}
diff --git a/docs/editor.jpg b/shared/editor.jpg
similarity index 100%
rename from docs/editor.jpg
rename to shared/editor.jpg
diff --git a/docs/player.gif b/shared/player.gif
similarity index 100%
rename from docs/player.gif
rename to shared/player.gif
diff --git a/templates/empty.tadb.json b/templates/empty.tadb.json
deleted file mode 100644
index e49f5a8..0000000
--- a/templates/empty.tadb.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "$schema": "../textAdventureGameDatabase.schema.json",
-
- "general": {
- "title": "TextAdventureJS Empty Database Template",
- "author": "Your Name",
- "version": "0.1",
- "continue_enabled": true,
- "request": ["", "What do you do?"],
- "start": {
- "text": ["Welcome to the Empty Template"],
- "inventory": "",
- "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": []
- }
- }
-}
diff --git a/textAdventure.js b/textAdventure.js
index 8e35f66..f48fdb0 100644
--- a/textAdventure.js
+++ b/textAdventure.js
@@ -15,20 +15,28 @@ class textAdventureEngine {
}
async loadDatabaseFromFile(gamedatabasePath, showGameInfo = true) {
- this.outputClear();
- this.#writeOutputLines("Initializing Text Adventure Engine...");
- this.outputClear();
- const response = await fetch(gamedatabasePath);
- const json = await response.json();
this.showGameInfo = showGameInfo;
- this.#initDatbase(json);
+ try {
+ this.outputClear();
+ this.#writeOutputLines("Initializing Text Adventure Engine...");
+ const response = await fetch(gamedatabasePath);
+ const json = await response.json();
+ this.outputClear();
+ this.#initDatbase(json);
+ } catch (err) {
+ console.error(err);
+ this.#writeOutputLines("Error loading game database!");
+ }
}
loadDatabaseFromObject(json) {
- this.outputClear();
- this.#writeOutputLines("Initializing Text Adventure Engine...");
- this.outputClear();
- this.#initDatbase(json);
+ try {
+ this.outputClear();
+ this.#initDatbase(json);
+ } catch (err) {
+ console.error(err);
+ this.#writeOutputLines("Error loading game database!");
+ }
}
input(cmd) {