From 1d1b5981f163f266631a644f73704c3dc842b72c Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Sat, 12 Aug 2023 14:46:45 +0200 Subject: [PATCH 01/80] Implemented basic verb editor functionality --- editor/editor-style.css | 13 ++++ editor/editor.html | 35 +++++++++ editor/tba_editor.js | 168 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+) create mode 100644 editor/editor-style.css create mode 100644 editor/editor.html create mode 100644 editor/tba_editor.js diff --git a/editor/editor-style.css b/editor/editor-style.css new file mode 100644 index 0000000..1f39f0b --- /dev/null +++ b/editor/editor-style.css @@ -0,0 +1,13 @@ +/* Sticky footer styles +-------------------------------------------------- */ +html { + position: relative; + min-height: 100%; + } + + .container { + width: auto; + max-width: 680px; + padding: 0 15px; + } + \ No newline at end of file diff --git a/editor/editor.html b/editor/editor.html new file mode 100644 index 0000000..bbd3523 --- /dev/null +++ b/editor/editor.html @@ -0,0 +1,35 @@ + + + + +testAdventureJS Editor + + + + + + + + + +
+

textAdventureJS Game Editor

+
+

DROP HERE

+
+
+

+ +

+
+
+
+
+
+
+ + diff --git a/editor/tba_editor.js b/editor/tba_editor.js new file mode 100644 index 0000000..2f7705f --- /dev/null +++ b/editor/tba_editor.js @@ -0,0 +1,168 @@ +TBA_DATABASE = undefined; +TBA_DEBUG = false; + +$( document ).ready(function() { + $(".file-drop-area").on('dragover', (e) => { + // Prevent navigation. + e.preventDefault(); + }); + + $(".file-drop-area").on('drop', async (e) => { + e.preventDefault(); + + /*const fileHandlesPromises = [...e.originalEvent.dataTransfer.items] + .filter((item) => item.kind === 'file') + .map((item) => item.getAsFileSystemHandle()); // not supported in Firefox, but would allow writing + + for await (const handle of fileHandlesPromises) { + if (handle.kind === 'directory') { + console.log(`Directory: ${handle.name}`); + } else { + console.log(`File: ${handle.name}`); + } + }*/ + + var file = e.originalEvent.dataTransfer.files[0], + reader = new FileReader(); + reader.onload = function(event) { + console.log(event.target); + tba_init(event.target.result); + }; + reader.readAsText(file); + }); + updateEditorState(); + //tba_init(JSON.stringify($.getJSON('../lonesurvivor.tadb.json'))); +}); + +function updateEditorState() { + if(TBA_DATABASE !== undefined) { + $("#drop-area").hide(); + $("#editor-aera").show(); + }else{ + $("#drop-area").show(); + $("#editor-aera").hide(); + } +} + +function tba_init(json){ + TBA_DATABASE = JSON.parse(json); + updateEditorState(); + initEditorForSlection(); +} + +function initEditorForSlection(){ + type = $("#type").val(); + + $("#elementSelection").html(""); + + let elementSelector = $(''); + $.each( TBA_DATABASE[type], function( key, val ) { + elementSelector.append($('')); + }); + $("#elementSelection").append(elementSelector); + if(type==="verbs") { + $("#elementSelection").append(generateNewButton(function(name){ + if(TBA_DATABASE.verbs[name]!==undefined){ + alert("A verb with this name already exists."); + return; + } + let newVerb = getNewVerb(name); + TBA_DATABASE.verbs[name]=newVerb; + initEditorForSlection(); + })); + } + $("#elementEditor").html(""); +} + +function onElementChanged(){ + let gui; + let element = $("#element").val(); + if(type=="verbs"){ + gui = generateUiForVerbElement(element, TBA_DATABASE.verbs[element]); + }else if(type=="objects"){ + + }else{ + + } + + $("#elementEditor").html(gui); +} + +function generateNewButton(onClick) { + let editorGui = $('
'); + let elementNameInput = $(''); + + let addButton = $(''); + addButton.click(function() { onClick(elementNameInput.val()); }); + editorGui.append(elementNameInput); + editorGui.append(addButton); //getNewVerb + return editorGui; +} + +function generateUiForVerbElement(verbName, verb) { + let editorGui = $('
'); + let name = $('

Name: '+verbName+'

'); + let removeButton = $('') + removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; initEditorForSlection(); }); + name.append(removeButton); + editorGui.append(name); + editorGui.append(generateInput("Failure", verb.failure, function(value){ verb.failure = value; })); + editorGui.append(generateInput("Words", verb.words.join(", "), + function(value){ + verb.words = value.split(",").map(function(item) { + return item.trim(); + }); + })); + return editorGui; +} + +function generateInput(name, value, onChange){ + let inputFieldArea = $('

'); + inputFieldArea.append(' '); + let inputField = $(''); + inputField.on( "change", function() { + onChange(inputField.val()); + } ); + inputFieldArea.append(inputField); + return inputFieldArea; +} + +function generateGui(objectToBeEdited){ + let editorGui = $('
'); + $.each( objectToBeEdited, function( key, value ) { + if(typeof value === 'object'){ + editorGui.append("

"+key+"

"); + editorGui.append(generateGui(value)); + }else{ + let inputField = $('

'); + inputField.append(' '); + inputField.append(''); + editorGui.append(inputField); + } + }); + return editorGui; +} + +function getNewVerb(name){ + var newVerb = {}; + newVerb["failure"] = "That didnt work."; + newVerb["words"] = [name]; + return newVerb; +} + + +//FOR OLD BROWSERS +if (typeof Object.keys !== "function") { + (function() { + Object.keys = Object_keys; + function Object_keys(obj) { + var keys = [], name; + for (name in obj) { + if (obj.hasOwnProperty(name)) { + keys.push(name); + } + } + return keys; + } + })(); +} From cb344291d68acb6499403f5c025f5afdac4894c4 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Sun, 13 Aug 2023 19:39:20 +0200 Subject: [PATCH 02/80] Implemented object editor --- Templates/empty.tadb.json | 2 +- Templates/miniExample.tadb.json | 6 +- editor/tba_editor.js | 113 ++++++++++++++++++++++++++---- lonesurvivor.tadb.json | 58 +++++++-------- textAdventureDatabase.schema.json | 15 ++-- 5 files changed, 137 insertions(+), 57 deletions(-) diff --git a/Templates/empty.tadb.json b/Templates/empty.tadb.json index 97c9541..9f0dfb0 100644 --- a/Templates/empty.tadb.json +++ b/Templates/empty.tadb.json @@ -9,7 +9,7 @@ "start": { "text": "Welcome to the Empty Template", "inventory": "", - "action": "gotoLocation first_room" + "action": [ "gotoLocation first_room" ] } }, "ignored_words" :[ ], diff --git a/Templates/miniExample.tadb.json b/Templates/miniExample.tadb.json index 1c394fb..a7724b8 100644 --- a/Templates/miniExample.tadb.json +++ b/Templates/miniExample.tadb.json @@ -7,7 +7,7 @@ "request": [ "", "What do you do?" ], "start": { "text": "Welcome to the textAdventureJS Mini Example", - "action": "gotoLocation template_room" + "action": [ "gotoLocation template_room" ] } }, "ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ], @@ -32,7 +32,7 @@ }, "look": { "text": "soft and comfy", - "action": "" + "action": [] } }, "useableObjects": { } @@ -51,7 +51,7 @@ }, "look": { "text": "soft and comfy", - "action": "" + "action": [] } }, "useableObjects": { } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 2f7705f..3a8049d 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -56,7 +56,7 @@ function initEditorForSlection(){ $("#elementSelection").html(""); let elementSelector = $(''); - $.each( TBA_DATABASE[type], function( key, val ) { + $.each( TBA_DATABASE[type], function( key, val ) { elementSelector.append($('')); }); $("#elementSelection").append(elementSelector); @@ -70,6 +70,15 @@ function initEditorForSlection(){ TBA_DATABASE.verbs[name]=newVerb; initEditorForSlection(); })); + }else if(type==="objects"){ + $("#elementSelection").append(generateNewButton(function(name){ + if(TBA_DATABASE.objects[name]!==undefined){ + alert("An object with this name already exists."); + return; + } + TBA_DATABASE.objects[name]=getNewObject(name); + initEditorForSlection(); + })); } $("#elementEditor").html(""); } @@ -80,7 +89,7 @@ function onElementChanged(){ if(type=="verbs"){ gui = generateUiForVerbElement(element, TBA_DATABASE.verbs[element]); }else if(type=="objects"){ - + gui = generateUiForObjectElement(element, TBA_DATABASE.objects[element]); }else{ } @@ -88,17 +97,6 @@ function onElementChanged(){ $("#elementEditor").html(gui); } -function generateNewButton(onClick) { - let editorGui = $('
'); - let elementNameInput = $(''); - - let addButton = $(''); - addButton.click(function() { onClick(elementNameInput.val()); }); - editorGui.append(elementNameInput); - editorGui.append(addButton); //getNewVerb - return editorGui; -} - function generateUiForVerbElement(verbName, verb) { let editorGui = $('
'); let name = $('

Name: '+verbName+'

'); @@ -116,6 +114,69 @@ function generateUiForVerbElement(verbName, verb) { return editorGui; } +function generateUiForObjectElement(objectName, object) { + let editorGui = $('
'); + let name = $('

Name: '+objectName+'

'); + let removeButton = $(''); + removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; initEditorForSlection(); }); + name.append(removeButton); + editorGui.append(name); + editorGui.append(generateInput("Location Description", object.locationDescription, function(value){ object.locationDescription = value; })); + editorGui.append(generateInput("Words", object.words.join(", "), + function(value){ + object.words = value.split(",").map(function(item) { return item.trim(); }); + })); + editorGui.append($('

Actions:

')); + editorGui.append(generateNewActionButton(object.actions, function(verb){ + if(object.actions[name]!==undefined){ + alert("An action with this verb already exists for this object."); + return; + } + alert(verb); + let newAction = getNewObjectAction(); + object.actions[verb]=newAction; + initEditorForSlection(); + })); + $.each(object.actions, function( verb, action ) { + let actionGui = $('
'); + let name = $('

Name: '+verb+'

'); + actionGui.append(name); + actionGui.append(generateInput("Text", action.text, function(value){ action.text = value; })); + actionGui.append(generateTextArea("Functions", action.action.join("\n"), function(value){ + action.action = value.split("\n").map(function(item) { return item.trim(); }).filter(e => e); + })); + editorGui.append(actionGui); + }); + + return editorGui; +} + +function generateNewButton(onClick) { + let editorGui = $('
'); + let elementNameInput = $(''); + + let addButton = $(''); + addButton.click(function() { onClick(elementNameInput.val()); }); + editorGui.append(elementNameInput); + editorGui.append(addButton); + return editorGui; +} + +function generateNewActionButton(existingActions, onClick) { + let editorGui = $('
'); + let selectNewAction = $(''); + inputField.on( "change", function() { + onChange(inputField.val()); + } ); + inputFieldArea.append(inputField); + return inputFieldArea; +} + function generateGui(objectToBeEdited){ let editorGui = $('
'); $.each( objectToBeEdited, function( key, value ) { @@ -150,6 +222,21 @@ function getNewVerb(name){ return newVerb; } +function getNewObject(name){ + var newObject = {}; + newObject["words"] = [name]; + newObject["locationDescription"] = ""; + newObject["actions"] = []; + return newObject; +} + +function getNewObjectAction(){ + var newAction = {}; + newAction["text"] = "That worked!"; + newAction["action"] = []; + return newAction; +} + //FOR OLD BROWSERS if (typeof Object.keys !== "function") { diff --git a/lonesurvivor.tadb.json b/lonesurvivor.tadb.json index 74acd9e..2057eff 100644 --- a/lonesurvivor.tadb.json +++ b/lonesurvivor.tadb.json @@ -7,7 +7,7 @@ "request": [ "", "What do you do?" ], "start": { "text": [ "", "", "", "You wake up with a headache..." ], - "action": "gotoLocation start_chamber" + "action": [ "gotoLocation start_chamber" ] } }, "ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ], @@ -69,21 +69,21 @@ "actions": { "pickup": { "text": "okay got it", - "action": "inventoryAdd template_object" + "action": [ "inventoryAdd template_object" ] }, "look": { "text": "soft and comfy", - "action": "" + "action": [] } }, "useableObjects": { "bedroom_desk": { "text": "soft and comfy", - "action": "" + "action": [] }, "test": { "text": "works", - "action": "" + "action": [] } } }, @@ -93,15 +93,15 @@ "actions": { "look": { "text": "Plaster is crumbling from the walls. Something seems off, but it's too dark to have a closer look.", - "action": "" + "action": [] }, "touch": { "text": "The plaster feels wet and is crumbling in your hands as you touch it.", - "action": "" + "action": [] }, "break": { "text": "Why would you do that?", - "action": "" + "action": [] } }, "useableObjects": { } @@ -112,7 +112,7 @@ "actions": { "look": { "text": "You notice some rusty metal emerging behind the crumbling PLASTER of one wall.", - "action": "" + "action": [] }, "remove": { "text": "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR.", @@ -130,15 +130,15 @@ "actions": { "look": { "text": "A heavy metal door that was hidden under the plaster.", - "action": "" + "action": [] }, "go": { "text": "You open the rusty door and enter a hallway.", - "action": "gotoLocation long_hallway" + "action": [ "gotoLocation long_hallway" ] }, "open": { "text": "You open the rusty door and enter a hallway.", - "action": "gotoLocation long_hallway" + "action": [ "gotoLocation long_hallway" ] } }, "useableObjects": { } @@ -149,11 +149,11 @@ "actions": { "look": { "text": "It looks like a rusty metal object is hidden behind the crumbling plaster.", - "action": "" + "action": [] }, "touch": { "text": "The plaster feels loose, you might be able to remove it with your hands.", - "action": "" + "action": [] }, "remove": { "text": "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR.", @@ -173,17 +173,17 @@ "text": [ "You wake up with a headache." ], - "action": "" + "action": [] }, "look": { "text": [ "You look around..." ], - "action": "showLocationDescription" + "action": [ "showLocationDescription" ] }, "light": { "text": "If only you'd had something to enlighten the room with...", - "action": "" + "action": [] } }, "useableObjects": { } @@ -196,11 +196,11 @@ "text": [ "You look at each wall..." ], - "action": "showLocationDescription" + "action": [ "showLocationDescription" ] }, "light": { "text": "The room is already slightly illuminated.", - "action": "" + "action": [] } }, "useableObjects": { } @@ -220,7 +220,7 @@ }, "look": { "text": "It's too dark to see the small box properly. You could probably reach it.", - "action": "" + "action": [] } }, "useableObjects": { } @@ -256,7 +256,7 @@ }, "look": { "text": "An almost empty box of matches.", - "action": "" + "action": [] } }, "useableObjects": { } @@ -274,7 +274,7 @@ }, "look": { "text": "A small box of matches, that you dropped here...", - "action": "" + "action": [] } }, "useableObjects": { } @@ -285,7 +285,7 @@ "actions": { "look": { "text": "", - "action": "" + "action": [] } }, "useableObjects": { } @@ -296,11 +296,11 @@ "actions": { "look": { "text": "It seems to be sunlight that enlightens the end of the hallway.", - "action": "" + "action": [] }, "go": { "text": "You walk towards the light, but you don't seem to get any closer. A gust of wind blows the LEAFLET to you.", - "action": "" + "action": [] } }, "useableObjects": { } @@ -311,11 +311,11 @@ "actions": { "look": { "text": "It seems to be sunlight that enlightens the end of the hallway.", - "action": "" + "action": [] }, "go": { "text": "You walk towards the light, but you don't seem to get any closer.", - "action": "" + "action": [] } }, "useableObjects": { } @@ -326,7 +326,7 @@ "actions": { "look": { "text": "The text is too small to read the LEAFLET, while it's on the ground.", - "action": "" + "action": [] }, "pickup": { "text": "You take the leaflet.", @@ -348,7 +348,7 @@ "\"Dear Player,", "Wow, you actually played this :-) I'm afraid your adventure ends here, already. This Text Based Adventure Engine was just a quick project on a rainy weekend. I hope you liked it, feel free to contact me if you did. -Daniel.\"" ], - "action": "" + "action": [] }, "drop": { "text": "You dropped the leaflet.", diff --git a/textAdventureDatabase.schema.json b/textAdventureDatabase.schema.json index 27d25a7..638cb4c 100644 --- a/textAdventureDatabase.schema.json +++ b/textAdventureDatabase.schema.json @@ -24,17 +24,10 @@ ] }, "action": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ] + "type": "array", + "items": { + "type": "string" + } } } } From b9fdc007c98ce18f4a1ce5a9abe893c94a906f95 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Mon, 14 Aug 2023 21:44:59 +0200 Subject: [PATCH 03/80] Added Location editor --- editor/tba_editor.js | 64 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 3a8049d..c1d92fa 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -79,6 +79,15 @@ function initEditorForSlection(){ TBA_DATABASE.objects[name]=getNewObject(name); initEditorForSlection(); })); + }else if(type==="locations"){ + $("#elementSelection").append(generateNewButton(function(name){ + if(TBA_DATABASE.locations[name]!==undefined){ + alert("A location with this name already exists."); + return; + } + TBA_DATABASE.locations[name]=getNewLocation(); + initEditorForSlection(); + })); } $("#elementEditor").html(""); } @@ -91,9 +100,8 @@ function onElementChanged(){ }else if(type=="objects"){ gui = generateUiForObjectElement(element, TBA_DATABASE.objects[element]); }else{ - + gui = generateUiForLocationElement(element, TBA_DATABASE.locations[element]); } - $("#elementEditor").html(gui); } @@ -132,7 +140,6 @@ function generateUiForObjectElement(objectName, object) { alert("An action with this verb already exists for this object."); return; } - alert(verb); let newAction = getNewObjectAction(); object.actions[verb]=newAction; initEditorForSlection(); @@ -151,6 +158,36 @@ function generateUiForObjectElement(objectName, object) { return editorGui; } +function generateUiForLocationElement(locationName, location) { + let editorGui = $('
'); + let name = $('

Name: '+locationName+'

'); + let removeButton = $(''); + removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; initEditorForSlection(); }); + name.append(removeButton); + editorGui.append(name); + editorGui.append($('

Objects:

')); + let objSelector = $(''); @@ -177,6 +214,21 @@ function generateNewActionButton(existingActions, onClick) { return editorGui; } +function generateNewObjectForLocationButton(existingObjects, onClick) { + let editorGui = $('
'); + let selectNewObject = $(''); From a7f50978aefb5dffa02c858d42c0d8bbd607bde3 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 16 Aug 2023 18:13:58 +0200 Subject: [PATCH 05/80] Added element refresh, instead of reloading everything --- editor/editor.html | 2 +- editor/tba_editor.js | 35 +++++++++++++++++++++++------------ 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/editor/editor.html b/editor/editor.html index bbd3523..835c10f 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -19,7 +19,7 @@

DROP HERE

- diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 2fd171a..ab4744b 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -1,6 +1,8 @@ TBA_DATABASE = undefined; TBA_DEBUG = false; +var type; + $( document ).ready(function() { $(".file-drop-area").on('dragover', (e) => { // Prevent navigation. @@ -47,11 +49,12 @@ function updateEditorState() { function tba_init(json){ TBA_DATABASE = JSON.parse(json); updateEditorState(); - initEditorForSlection(); + onTypeChanged(); } -function initEditorForSlection(){ +function onTypeChanged(){ type = $("#type").val(); + if(type===null){ type=$("#type option:first");} $("#elementSelection").html(""); @@ -68,7 +71,7 @@ function initEditorForSlection(){ } let newVerb = getNewVerb(name); TBA_DATABASE.verbs[name]=newVerb; - initEditorForSlection(); + onTypeChanged(); })); }else if(type==="objects"){ $("#elementSelection").append(generateNewButton(function(name){ @@ -77,7 +80,7 @@ function initEditorForSlection(){ return; } TBA_DATABASE.objects[name]=getNewObject(name); - initEditorForSlection(); + onTypeChanged(); })); }else if(type==="locations"){ $("#elementSelection").append(generateNewButton(function(name){ @@ -86,15 +89,18 @@ function initEditorForSlection(){ return; } TBA_DATABASE.locations[name]=getNewLocation(); - initEditorForSlection(); + onTypeChanged(); })); } $("#elementEditor").html(""); + onElementChanged(); } function onElementChanged(){ let gui; - let element = $("#element").val(); + let element = $('#element').val(); + if(element===null){ type=$("#element option:first");} + if(type=="verbs"){ gui = generateUiForVerbElement(element, TBA_DATABASE.verbs[element]); }else if(type=="objects"){ @@ -109,7 +115,7 @@ function generateUiForVerbElement(verbName, verb) { let editorGui = $('

'); let name = $('

Name: '+verbName+'

'); let removeButton = $('') - removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; initEditorForSlection(); }); + removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; onTypeChanged(); }); name.append(removeButton); editorGui.append(name); editorGui.append(generateInput("Failure", verb.failure, function(value){ verb.failure = value; })); @@ -126,7 +132,7 @@ function generateUiForObjectElement(objectName, object) { let editorGui = $('
'); let name = $('

Name: '+objectName+'

'); let removeButton = $(''); - removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; initEditorForSlection(); }); + removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; onTypeChanged(); }); name.append(removeButton); editorGui.append(name); editorGui.append(generateInput("Location Description", object.locationDescription, function(value){ object.locationDescription = value; })); @@ -142,11 +148,14 @@ function generateUiForObjectElement(objectName, object) { } let newAction = getNewObjectAction(); object.actions[verb]=newAction; - initEditorForSlection(); + onElementChanged(); })); $.each(object.actions, function( verb, action ) { let actionGui = $('
'); let name = $('

Name: '+verb+'

'); + let removeActionButton = $('') + removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); + name.append(removeActionButton); actionGui.append(name); actionGui.append(generateInput("Text", action.text, function(value){ action.text = value; })); actionGui.append(generateTextArea("Functions", action.action.join("\n"), function(value){ @@ -162,7 +171,7 @@ function generateUiForLocationElement(locationName, location) { let editorGui = $('
'); let name = $('

Name: '+locationName+'

'); let removeButton = $(''); - removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; initEditorForSlection(); }); + removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onElementChanged(); }); name.append(removeButton); editorGui.append(name); editorGui.append($('

Objects:

')); @@ -176,7 +185,7 @@ function generateUiForLocationElement(locationName, location) { let index = objSelector.val(); if(index === null || index < 0) { alert("No object selected"); return; } delete location.objects.splice(index, 1); - initEditorForSlection(); + onElementChanged(); }); let moveUpButton = $(''); moveUpButton.click(function() { @@ -185,6 +194,7 @@ function generateUiForLocationElement(locationName, location) { const indexInt = parseInt(index); if(indexInt > 0) { moveArrayElement(location.objects, indexInt, indexInt-1); + onElementChanged(); } }); let moveDownButton = $(''); @@ -194,6 +204,7 @@ function generateUiForLocationElement(locationName, location) { const indexInt = parseInt(index); if (indexInt < location.objects.length-1 ) { moveArrayElement(location.objects, indexInt, indexInt+1); + onElementChanged(); } }); editorGui.append(objSelector); @@ -202,7 +213,7 @@ function generateUiForLocationElement(locationName, location) { editorGui.append(removeObjectButton); editorGui.append(generateNewObjectForLocationButton(location.objects, function(obj){ location.objects.push(obj); - initEditorForSlection(); + onElementChanged(); })); return editorGui; From f2148a13b5f2cefc9c4140dacdb52464e3175dd5 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 16 Aug 2023 22:45:13 +0200 Subject: [PATCH 06/80] Improved Ui structure --- editor/editor-style.css | 56 +++++++++++++++++++++++++++++++++++++++-- editor/editor.html | 3 ++- editor/tba_editor.js | 50 ++++++++++++++++++++++++++---------- 3 files changed, 93 insertions(+), 16 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index 1f39f0b..f9dddd6 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -7,7 +7,59 @@ html { .container { width: auto; - max-width: 680px; + max-width: 960px; padding: 0 15px; + } - \ No newline at end of file + + .w100 { + width: 100%; + } + .w90 { + width: 90%; + } + .w80 { + width: 80%; + } + .w70 { + width: 70%; + } + .w60 { + width: 60%; + } + .w50 { + width: 50%; + } + .w40 { + width: 40%; + } + .w30 { + width: 30%; + } + .w20 { + width: 20%; + } + .w15 { + width: 15%; + } + .w10 { + width: 10%; + } + + #editor { + display: grid; + grid-template-areas: "sidebar main"; + grid-template-columns: 300px auto; + width: 100%; + } + + #elementSelection { + height: 100vw; + grid-area: sidebar; + } + + #elementEditor { + padding: 15px; + height: 100vw; + grid-area: main; + } \ No newline at end of file diff --git a/editor/editor.html b/editor/editor.html index 835c10f..a96f60c 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -20,9 +20,10 @@

DROP HERE

diff --git a/editor/tba_editor.js b/editor/tba_editor.js index ab4744b..f3a6390 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -57,14 +57,10 @@ function onTypeChanged(){ if(type===null){ type=$("#type option:first");} $("#elementSelection").html(""); - - let elementSelector = $(''); - $.each( TBA_DATABASE[type], function( key, val ) { - elementSelector.append($('')); - }); - $("#elementSelection").append(elementSelector); + var newArea = $('
'); + $("#elementSelection").append(newArea); if(type==="verbs") { - $("#elementSelection").append(generateNewButton(function(name){ + newArea.append(generateNewButton(function(name){ if(TBA_DATABASE.verbs[name]!==undefined){ alert("A verb with this name already exists."); return; @@ -74,7 +70,7 @@ function onTypeChanged(){ onTypeChanged(); })); }else if(type==="objects"){ - $("#elementSelection").append(generateNewButton(function(name){ + newArea.append(generateNewButton(function(name){ if(TBA_DATABASE.objects[name]!==undefined){ alert("An object with this name already exists."); return; @@ -83,7 +79,7 @@ function onTypeChanged(){ onTypeChanged(); })); }else if(type==="locations"){ - $("#elementSelection").append(generateNewButton(function(name){ + newArea.append(generateNewButton(function(name){ if(TBA_DATABASE.locations[name]!==undefined){ alert("A location with this name already exists."); return; @@ -92,6 +88,13 @@ function onTypeChanged(){ onTypeChanged(); })); } + + let elementSelector = $(''); + $.each( TBA_DATABASE[type], function( key, val ) { + elementSelector.append($('')); + }); + $("#elementSelection").append(elementSelector); + $("#elementEditor").html(""); onElementChanged(); } @@ -99,7 +102,7 @@ function onTypeChanged(){ function onElementChanged(){ let gui; let element = $('#element').val(); - if(element===null){ type=$("#element option:first");} + if(element===null){ element=$("#element option:first");} if(type=="verbs"){ gui = generateUiForVerbElement(element, TBA_DATABASE.verbs[element]); @@ -170,9 +173,15 @@ function generateUiForObjectElement(objectName, object) { function generateUiForLocationElement(locationName, location) { let editorGui = $('
'); let name = $('

Name: '+locationName+'

'); + let removeButton = $(''); - removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onElementChanged(); }); + removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onTypeChanged(); }); name.append(removeButton); + + let duplicateButton = $(''); + duplicateButton.click(function() { TBA_DATABASE.locations[getAvailableLocationName(locationName)] = clone(location); onTypeChanged(); }); + name.append(duplicateButton); + editorGui.append(name); editorGui.append($('

Objects:

')); let objSelector = $(''); + let elementNameInput = $(' '); - let addButton = $(''); + let addButton = $(''); addButton.click(function() { onClick(elementNameInput.val()); }); editorGui.append(elementNameInput); editorGui.append(addButton); From 756a4f6b0e9e13818acb9de2d2ae5a7232c3fcd6 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 16 Aug 2023 22:49:33 +0200 Subject: [PATCH 07/80] Added duplicate button for all types --- editor/tba_editor.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index f3a6390..8e70b62 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -117,9 +117,15 @@ function onElementChanged(){ function generateUiForVerbElement(verbName, verb) { let editorGui = $('
'); let name = $('

Name: '+verbName+'

'); + let removeButton = $('') removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; onTypeChanged(); }); name.append(removeButton); + + let duplicateButton = $(''); + duplicateButton.click(function() { TBA_DATABASE.verbs[getAvailableVerbName(verbName)] = clone(verb); onTypeChanged(); }); + name.append(duplicateButton); + editorGui.append(name); editorGui.append(generateInput("Failure", verb.failure, function(value){ verb.failure = value; })); editorGui.append(generateInput("Words", verb.words.join(", "), @@ -134,9 +140,15 @@ function generateUiForVerbElement(verbName, verb) { function generateUiForObjectElement(objectName, object) { let editorGui = $('
'); let name = $('

Name: '+objectName+'

'); + let removeButton = $(''); removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; onTypeChanged(); }); name.append(removeButton); + + let duplicateButton = $(''); + duplicateButton.click(function() { TBA_DATABASE.objects[getAvailableObjectName(objectName)] = clone(object); onTypeChanged(); }); + name.append(duplicateButton); + editorGui.append(name); editorGui.append(generateInput("Location Description", object.locationDescription, function(value){ object.locationDescription = value; })); editorGui.append(generateInput("Words", object.words.join(", "), @@ -252,6 +264,24 @@ function getAvailableLocationName(locationName) { } return testName; } +function getAvailableObjectName(objectName) { + var index=1; + var testName = objectName; + while(TBA_DATABASE.objects[testName] !== undefined) { + testName = objectName + " " + index; + index++; + } + return testName; +} +function getAvailableVerbName(verbName) { + var index=1; + var testName = verbName; + while(TBA_DATABASE.verbs[testName] !== undefined) { + testName = verbName + " " + index; + index++; + } + return testName; +} function generateNewButton(onClick) { let editorGui = $('
'); From 2582a4be3fb0972b55d3e09c13d83ce2cd185e3f Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 23 Aug 2023 22:25:26 +0200 Subject: [PATCH 08/80] Implemented table layout --- editor/editor-style.css | 4 + editor/tba_editor.js | 245 +++++++++++++++++++++++++--------------- 2 files changed, 160 insertions(+), 89 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index f9dddd6..18e2e40 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -12,6 +12,10 @@ html { } + td { + padding: 5px; + } + .w100 { width: 100%; } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 8e70b62..da390c1 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -1,6 +1,8 @@ TBA_DATABASE = undefined; TBA_DEBUG = false; +const NEWLINE = " "; + var type; $( document ).ready(function() { @@ -57,76 +59,105 @@ function onTypeChanged(){ if(type===null){ type=$("#type option:first");} $("#elementSelection").html(""); - var newArea = $('
'); - $("#elementSelection").append(newArea); - if(type==="verbs") { - newArea.append(generateNewButton(function(name){ - if(TBA_DATABASE.verbs[name]!==undefined){ - alert("A verb with this name already exists."); - return; - } - let newVerb = getNewVerb(name); - TBA_DATABASE.verbs[name]=newVerb; - onTypeChanged(); - })); - }else if(type==="objects"){ - newArea.append(generateNewButton(function(name){ - if(TBA_DATABASE.objects[name]!==undefined){ - alert("An object with this name already exists."); - return; - } - TBA_DATABASE.objects[name]=getNewObject(name); - onTypeChanged(); - })); - }else if(type==="locations"){ - newArea.append(generateNewButton(function(name){ - if(TBA_DATABASE.locations[name]!==undefined){ - alert("A location with this name already exists."); - return; - } - TBA_DATABASE.locations[name]=getNewLocation(); - onTypeChanged(); - })); - } + if(type=="general") { + $("#elementEditor").html(generateUiForGeneral(TBA_DATABASE.general)); + return; + }else{ + var newArea = $('
'); + $("#elementSelection").append(newArea); + if(type==="verbs") { + newArea.append(generateNewButton(function(name){ + if(TBA_DATABASE.verbs[name]!==undefined){ + alert("A verb with this name already exists."); + return; + } + let newVerb = getNewVerb(name); + TBA_DATABASE.verbs[name]=newVerb; + onTypeChanged(); + })); + }else if(type==="objects"){ + newArea.append(generateNewButton(function(name){ + if(TBA_DATABASE.objects[name]!==undefined){ + alert("An object with this name already exists."); + return; + } + TBA_DATABASE.objects[name]=getNewObject(name); + onTypeChanged(); + })); + }else if(type==="locations"){ + newArea.append(generateNewButton(function(name){ + if(TBA_DATABASE.locations[name]!==undefined){ + alert("A location with this name already exists."); + return; + } + TBA_DATABASE.locations[name]=getNewLocation(); + onTypeChanged(); + })); + } - let elementSelector = $(''); - $.each( TBA_DATABASE[type], function( key, val ) { - elementSelector.append($('')); - }); - $("#elementSelection").append(elementSelector); + let elementSelector = $(''); + $.each( TBA_DATABASE[type], function( key, val ) { + elementSelector.append($('')); + }); + $("#elementSelection").append(elementSelector); - $("#elementEditor").html(""); - onElementChanged(); + $("#elementEditor").html(""); + onElementChanged(); + } } function onElementChanged(){ - let gui; + let gui = undefined; let element = $('#element').val(); - if(element===null){ element=$("#element option:first");} + if(element===null){ element=$("#element option:first").val(); $('#element').val(element);} if(type=="verbs"){ gui = generateUiForVerbElement(element, TBA_DATABASE.verbs[element]); }else if(type=="objects"){ gui = generateUiForObjectElement(element, TBA_DATABASE.objects[element]); - }else{ + }else if(type=="locations"){ gui = generateUiForLocationElement(element, TBA_DATABASE.locations[element]); } - $("#elementEditor").html(gui); + if(gui !== undefined){ + $("#elementEditor").html(gui); + } +} + +function generateUiForGeneral(general) { + let editorGui = $('
'); + let table = $(''); + editorGui.append(table); + table.append(tableH3('Info')); + table.append(generateInput("Title", general.title, function(value){ general.title = value; })); + table.append(generateInput("Author", general.author, function(value){ general.author = value; })); + table.append(generateInput("Version", general.version, function(value){ general.version = value; })); + table.append(tableH3('Game Settings')); + table.append(generateTextArea("Request", general.request.join(NEWLINE), function(value){ general.request = value.split(NEWLINE); })); + table.append(tableH3('Game Start')); + table.append(generateTextArea("Introduction", general.start.text.join(NEWLINE), function(value){ general.start.text = value.split(NEWLINE); })); + table.append(generateTextArea("Functions", general.start.action.join(NEWLINE), function(value){ + general.start.action = value.split(NEWLINE).map(function(item) { return item.trim(); }).filter(e => e); + })); + + return editorGui; } + function generateUiForVerbElement(verbName, verb) { - let editorGui = $('
'); - let name = $('

Name: '+verbName+'

'); + let editorGui = $('
'); + let name = $('

'+verbName+'

'); + + let nameOptions = $(''); let removeButton = $('') removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; onTypeChanged(); }); - name.append(removeButton); + nameOptions.append(removeButton); let duplicateButton = $(''); duplicateButton.click(function() { TBA_DATABASE.verbs[getAvailableVerbName(verbName)] = clone(verb); onTypeChanged(); }); - name.append(duplicateButton); + nameOptions.append(duplicateButton); - editorGui.append(name); + editorGui.append(tableRow2(name, nameOptions)); editorGui.append(generateInput("Failure", verb.failure, function(value){ verb.failure = value; })); editorGui.append(generateInput("Words", verb.words.join(", "), function(value){ @@ -138,25 +169,37 @@ function generateUiForVerbElement(verbName, verb) { } function generateUiForObjectElement(objectName, object) { - let editorGui = $('
'); - let name = $('

Name: '+objectName+'

'); + let editorGui = $('
'); + let name = $('

'+objectName+'

'); + let nameOptions = $(''); let removeButton = $(''); removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; onTypeChanged(); }); - name.append(removeButton); + nameOptions.append(removeButton); let duplicateButton = $(''); duplicateButton.click(function() { TBA_DATABASE.objects[getAvailableObjectName(objectName)] = clone(object); onTypeChanged(); }); - name.append(duplicateButton); + nameOptions.append(duplicateButton); + + editorGui.append(tableRow2(name, nameOptions)); - editorGui.append(name); editorGui.append(generateInput("Location Description", object.locationDescription, function(value){ object.locationDescription = value; })); editorGui.append(generateInput("Words", object.words.join(", "), function(value){ object.words = value.split(",").map(function(item) { return item.trim(); }); })); - editorGui.append($('

Actions:

')); - editorGui.append(generateNewActionButton(object.actions, function(verb){ + editorGui.append(tableH3('Actions')); + $.each(object.actions, function( verb, action ) { + let name = $('
'); + let removeActionButton = $('') + removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); + editorGui.append(tableRow2(name, removeActionButton)); + editorGui.append(generateInput("Text", action.text, function(value){ action.text = value; })); + editorGui.append(generateTextArea("Functions", action.action.join(NEWLINE), function(value){ + action.action = value.split(NEWLINE).map(function(item) { return item.trim(); }).filter(e => e); + })); + }); + editorGui.append(tableRow2("
Add Action
", generateNewActionButton(object.actions, function(verb){ if(object.actions[name]!==undefined){ alert("An action with this verb already exists for this object."); return; @@ -164,43 +207,36 @@ function generateUiForObjectElement(objectName, object) { let newAction = getNewObjectAction(); object.actions[verb]=newAction; onElementChanged(); - })); - $.each(object.actions, function( verb, action ) { - let actionGui = $('
'); - let name = $('

Name: '+verb+'

'); - let removeActionButton = $('') - removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); - name.append(removeActionButton); - actionGui.append(name); - actionGui.append(generateInput("Text", action.text, function(value){ action.text = value; })); - actionGui.append(generateTextArea("Functions", action.action.join("\n"), function(value){ - action.action = value.split("\n").map(function(item) { return item.trim(); }).filter(e => e); - })); - editorGui.append(actionGui); - }); + }))); return editorGui; } function generateUiForLocationElement(locationName, location) { - let editorGui = $('
'); - let name = $('

Name: '+locationName+'

'); + let editorGui = $('

'+verb+'

'); + let name = $('

'+locationName+'

'); + let nameOptions = $(''); let removeButton = $(''); removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onTypeChanged(); }); - name.append(removeButton); + nameOptions.append(removeButton); let duplicateButton = $(''); duplicateButton.click(function() { TBA_DATABASE.locations[getAvailableLocationName(locationName)] = clone(location); onTypeChanged(); }); - name.append(duplicateButton); + nameOptions.append(duplicateButton); - editorGui.append(name); - editorGui.append($('

Objects:

')); - let objSelector = $('
'); + let leftCellSelector = $(''); + rowNewObject.append(generateNewObjectForLocationButton(location.objects, function(obj){ location.objects.push(obj); onElementChanged(); })); + editorGui.append(rowNewObject); return editorGui; } +function paragraph(element) { + let p = $('

'); + p.append(element); + return p; +} +function tableH3(title){ + return $('

'); +} +function tableRow(element){ + let e = $(''); + e.append(element); + return e; +} +function tableRow2(left, right){ + let r = $(''); + let el = $(''); + inputFieldArea.append(''); let inputField = $(''); inputField.on( "change", function() { onChange(inputField.val()); } ); - inputFieldArea.append(inputField); + let valueTableField = $(''); + inputFieldArea.append(''); + let valueTableField = $(''); - let removeActionButton = $('') + let name = $('

'+verb+'

'); + let removeActionButton = button('Remove', 'btn-error btn-ghost') removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); editorGui.append(tableRow2(name, removeActionButton)); editorGui.append(generateInput("Text", action.text, function(value){ action.text = value; })); @@ -217,11 +217,11 @@ function generateUiForLocationElement(locationName, location) { let name = $('

'+locationName+'

'); let nameOptions = $(''); - let removeButton = $(''); + let removeButton = button('Remove', 'btn-error'); removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onTypeChanged(); }); nameOptions.append(removeButton); - let duplicateButton = $(''); + let duplicateButton = button('Duplicate'); duplicateButton.click(function() { TBA_DATABASE.locations[getAvailableLocationName(locationName)] = clone(location); onTypeChanged(); }); nameOptions.append(duplicateButton); @@ -237,14 +237,14 @@ function generateUiForLocationElement(locationName, location) { leftCellSelector.append(objSelector); rowSelector.append(leftCellSelector); let rightCellSelector = $('
'); + let objSelector = $(''); let removeObjectButton = $(''); removeObjectButton.click(function() { let index = objSelector.val(); @@ -228,18 +264,45 @@ function generateUiForLocationElement(locationName, location) { onElementChanged(); } }); - editorGui.append(objSelector); - editorGui.append(moveUpButton); - editorGui.append(moveDownButton); - editorGui.append(removeObjectButton); - editorGui.append(generateNewObjectForLocationButton(location.objects, function(obj){ + rightCellSelector.append(paragraph(moveUpButton)); + rightCellSelector.append(paragraph(moveDownButton)); + rightCellSelector.append(paragraph(removeObjectButton)); + rowSelector.append(rightCellSelector); + editorGui.append(rowSelector); + let rowNewObject = $('
Add Object

'+title+'

'); + el.append(left); + let er = $('') + er.append(right); + r.append(el); + r.append(er); + return r; +} + function moveArrayElement(arr, old_index, new_index) { if (new_index >= arr.length) { new_index = arr.length-1; @@ -295,7 +358,7 @@ function generateNewButton(onClick) { } function generateNewActionButton(existingActions, onClick) { - let editorGui = $('
'); + let editorGui = $(''); let selectNewAction = $('
'); + valueTableField.append(inputField); + inputFieldArea.append(valueTableField); return inputFieldArea; } function generateTextArea(name, value, onChange){ - let inputFieldArea = $('

'); - inputFieldArea.append('
'); + let inputFieldArea = $('
'); let inputField = $(''); inputField.on( "change", function() { onChange(inputField.val()); } ); - inputFieldArea.append(inputField); + valueTableField.append(inputField); + inputFieldArea.append(valueTableField); return inputFieldArea; } @@ -353,7 +420,7 @@ function generateGui(objectToBeEdited){ editorGui.append("

"+key+"

"); editorGui.append(generateGui(value)); }else{ - let inputField = $('

'); + let inputField = $('

'); inputField.append(' '); inputField.append(''); editorGui.append(inputField); From 00fa30865072d862930be76975209230068be999 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Thu, 24 Aug 2023 20:20:24 +0200 Subject: [PATCH 09/80] Added retro theme css to editor --- editor/editor-style.css | 9 ++++++++ editor/editor.html | 3 +++ editor/tba_editor.js | 50 +++++++++++++++++++++++------------------ 3 files changed, 40 insertions(+), 22 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index 18e2e40..b3de967 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -12,6 +12,15 @@ html { } + .input-pair-container { + display: flex; + width: 100%; + } + .left-pair-element { + flex-grow: 1; + margin-right: 10px; + } + td { padding: 5px; } diff --git a/editor/editor.html b/editor/editor.html index a96f60c..9349cc6 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -6,6 +6,9 @@ + + + diff --git a/editor/tba_editor.js b/editor/tba_editor.js index da390c1..9cf3299 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -149,11 +149,11 @@ function generateUiForVerbElement(verbName, verb) { let nameOptions = $(''); - let removeButton = $('') + let removeButton = button('Remove', 'btn-error'); removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; onTypeChanged(); }); nameOptions.append(removeButton); - let duplicateButton = $(''); + let duplicateButton = button('Duplicate'); duplicateButton.click(function() { TBA_DATABASE.verbs[getAvailableVerbName(verbName)] = clone(verb); onTypeChanged(); }); nameOptions.append(duplicateButton); @@ -173,11 +173,11 @@ function generateUiForObjectElement(objectName, object) { let name = $('

'+objectName+'

'); let nameOptions = $(''); - let removeButton = $(''); + let removeButton = button('Remove', 'btn-error'); removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; onTypeChanged(); }); nameOptions.append(removeButton); - let duplicateButton = $(''); + let duplicateButton = button('Duplicate'); duplicateButton.click(function() { TBA_DATABASE.objects[getAvailableObjectName(objectName)] = clone(object); onTypeChanged(); }); nameOptions.append(duplicateButton); @@ -190,8 +190,8 @@ function generateUiForObjectElement(objectName, object) { })); editorGui.append(tableH3('Actions')); $.each(object.actions, function( verb, action ) { - let name = $('

'+verb+'

'); - let removeObjectButton = $(''); + let removeObjectButton = button('Remove Object', 'btn-error btn-ghost'); removeObjectButton.click(function() { let index = objSelector.val(); if(index === null || index < 0) { alert("No object selected"); return; } delete location.objects.splice(index, 1); onElementChanged(); }); - let moveUpButton = $(''); + let moveUpButton = button('Move Up'); moveUpButton.click(function() { let index = objSelector.val(); if(index === null || index < 0) { alert("No object selected"); return; } @@ -254,7 +254,7 @@ function generateUiForLocationElement(locationName, location) { onElementChanged(); } }); - let moveDownButton = $(''); + let moveDownButton = button('Move Down'); moveDownButton.click(function() { let index = objSelector.val(); if(index === null || index < 0) { alert("No object selected"); return; } @@ -279,6 +279,10 @@ function generateUiForLocationElement(locationName, location) { return editorGui; } +function button(text, btnClasses = 'btn-default') { + return $(''); +} + function paragraph(element) { let p = $('

'); p.append(element); @@ -347,10 +351,10 @@ function getAvailableVerbName(verbName) { } function generateNewButton(onClick) { - let editorGui = $('

'); - let elementNameInput = $(' '); + let editorGui = $('
'); + let elementNameInput = $(''); - let addButton = $(''); + let addButton = button('Add'); addButton.click(function() { onClick(elementNameInput.val()); }); editorGui.append(elementNameInput); editorGui.append(addButton); @@ -358,14 +362,14 @@ function generateNewButton(onClick) { } function generateNewActionButton(existingActions, onClick) { - let editorGui = $(''); - let selectNewAction = $(''); $.each(TBA_DATABASE.verbs, function( verb ) { if(existingActions[verb] !== undefined) { return; } selectNewAction.append($('
'); + let container = $('
'); + let selectNewObject = $(' - - - - - -

+

General | Verbs | Objects | Locations | Preview

diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 9cf3299..a063b15 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -54,9 +54,9 @@ function tba_init(json){ onTypeChanged(); } -function onTypeChanged(){ - type = $("#type").val(); - if(type===null){ type=$("#type option:first");} +function onTypeChanged(typeParam){ + type = typeParam; + if(type===null){ type="general"; } $("#elementSelection").html(""); if(type=="general") { From f5d3f809fdadefd6742a21d7affb7d80f17c8766 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 13 Sep 2023 11:44:19 +0200 Subject: [PATCH 11/80] Updated engine to recent actions changes --- textAdventure.js | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/textAdventure.js b/textAdventure.js index 88b0720..0523f83 100644 --- a/textAdventure.js +++ b/textAdventure.js @@ -31,7 +31,7 @@ class textAdventureEngine { loadDatabaseFromObject(json, showGameName = true){ this.outputClear(); this.#writeOutputLines("Initializing Text Adventure Engine..."); - base.#initDatbase(json, showGameName); + this.#initDatbase(json, showGameName); } input(cmd){ @@ -100,7 +100,7 @@ class textAdventureEngine { if(this.#database.general.start.text.length > 0){ this.#writeOutputLines(this.#database.general.start.text); } - this.#parseActionString(undefined, this.#database.general.start.action); + this.#runActions(undefined, this.#database.general.start.action); }else if(cmd == "debug"){ if(this.TBA_DEBUG==true){ this.TBA_DEBUG = true; @@ -165,16 +165,7 @@ class textAdventureEngine { // let objectStateVerbDefinition = object.actions[verb.name]; this.#writeOutputLines(objectStateVerbDefinition.text); // This might be a string here - - if(objectStateVerbDefinition.action!=undefined){ - if($.isArray(objectStateVerbDefinition.action) && objectStateVerbDefinition.action.length > 0) { - for(var i=0; i Date: Wed, 13 Sep 2023 11:44:50 +0200 Subject: [PATCH 12/80] Added Preview Tab to editor --- editor/editor.html | 1 + editor/tba_editor.js | 53 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/editor/editor.html b/editor/editor.html index 5095f28..f5994a6 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -4,6 +4,7 @@ testAdventureJS Editor + - - + + +
-

textAdventureJS Game Editor

+

textAdventureJS Game Database Editor

-

DROP HERE

+

DRAG & DROP *.tadb.json HERE

+ +
diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 9509bce..5c2a488 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -24,43 +24,63 @@ $( document ).ready(function() { $(".file-drop-area").on('drop', async (e) => { e.preventDefault(); - - /*const fileHandlesPromises = [...e.originalEvent.dataTransfer.items] - .filter((item) => item.kind === 'file') - .map((item) => item.getAsFileSystemHandle()); // not supported in Firefox, but would allow writing - - for await (const handle of fileHandlesPromises) { - if (handle.kind === 'directory') { - console.log(`Directory: ${handle.name}`); - } else { - console.log(`File: ${handle.name}`); - } - }*/ var file = e.originalEvent.dataTransfer.files[0]; - reader = new FileReader(); - reader.onload = function(event) { - console.log(event.target); - tba_init(event.target.result); - }; - filename = file.name; - reader.readAsText(file); + importFile(file); + + }); + $("#btn-new").click(() => { + // Load the inlined default database JSON + const defaultJson = getDefaultProjectJson(); + if (defaultJson) { + tba_init(defaultJson); + } else { + alert('Default project JSON not available.'); + } }); $("#btn-save").click(() => { download(JSON.stringify(TBA_DATABASE, null, 2), filename, 'text/plain'); }); $("#btn-close").click(() => { TBA_DATABASE = undefined; + textAdv = undefined; deleteDatabaseFromStorage(); updateEditorState(); }); loadToDatabaseFromStorage(); updateEditorState(); - if(TBA_DATABASE != undefined){ + if (TBA_DATABASE != undefined) { onTypeChanged(); } }); +function importFile(file) { + reader = new FileReader(); + + // Handle successful read and catch JSON/initialization errors + reader.onload = function(event) { + try { + console.log(event.target); + tba_init(event.target.result); + } catch (err) { + console.error("Error initializing database from file:", err); + alert("Error loading file '" + (file && file.name ? file.name : '') + "': " + (err && err.message ? err.message : err)); + } + }; + + // Inform the user if reading the file fails or is aborted + reader.onerror = function() { + console.error("FileReader error:", reader.error); + alert("Error reading file '" + (file && file.name ? file.name : '') + "': " + ((reader.error && reader.error.message) ? reader.error.message : 'Unknown error')); + }; + reader.onabort = function() { + alert("File read aborted."); + }; + + filename = file.name; + reader.readAsText(file); +} + function download(content, fileName, contentType) { var a = document.createElement("a"); var file = new Blob([content], {type: contentType}); @@ -82,6 +102,17 @@ function deleteDatabaseFromStorage(){ localStorage.removeItem("database"); } +function getDefaultProjectJson() { + try { + const el = document.getElementById('default-db'); + if (!el) return null; + return el.textContent.trim(); + } catch (err) { + console.error('Failed to read default DB:', err); + return null; + } +} + function updateEditorState() { if(TBA_DATABASE !== undefined) { $("#drop-area").hide(); @@ -93,9 +124,14 @@ function updateEditorState() { } function tba_init(json){ - TBA_DATABASE = JSON.parse(json); - updateEditorState(); - onTypeChanged(); + try { + TBA_DATABASE = JSON.parse(json); + updateEditorState(); + onTypeChanged(); + } catch (err) { + console.error("Failed to initialize database:", err); + alert("Error parsing database JSON: " + (err && err.message ? err.message : err)); + } } function onTypeChanged(typeParam){ @@ -348,7 +384,7 @@ function generateUiForObjectElement(objectName, object) { let removeActionButton = button('Remove', 'btn-error btn-ghost') removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); editorGui.append(tableRow2(name, removeActionButton)); - editorGui.append(generateInput("Text", action.text, function(value){ action.text = value; })); + editorGui.append(generateTextArea("Text", action.text.join(NEWLINE), function(value){ action.text = value.split(NEWLINE); })); editorGui.append(generateTextArea("Functions", action.action.join(NEWLINE), function(value){ action.action = value.split(NEWLINE).map(function(item) { return item.trim(); }).filter(e => e); })); diff --git a/lonesurvivor.tadb.json b/lonesurvivor.tadb.json index 2057eff..3e91715 100644 --- a/lonesurvivor.tadb.json +++ b/lonesurvivor.tadb.json @@ -68,21 +68,21 @@ "locationDescription": "", "actions": { "pickup": { - "text": "okay got it", + "text": [ "okay got it" ], "action": [ "inventoryAdd template_object" ] }, "look": { - "text": "soft and comfy", + "text": [ "soft and comfy" ], "action": [] } }, "useableObjects": { "bedroom_desk": { - "text": "soft and comfy", + "text": [ "soft and comfy" ], "action": [] }, "test": { - "text": "works", + "text": [ "works" ], "action": [] } } @@ -92,15 +92,15 @@ "locationDescription": "Plaster is crumbling from the WALLS.", "actions": { "look": { - "text": "Plaster is crumbling from the walls. Something seems off, but it's too dark to have a closer look.", + "text": [ "Plaster is crumbling from the walls. Something seems off, but it's too dark to have a closer look." ], "action": [] }, "touch": { - "text": "The plaster feels wet and is crumbling in your hands as you touch it.", + "text": [ "The plaster feels wet and is crumbling in your hands as you touch it." ], "action": [] }, "break": { - "text": "Why would you do that?", + "text": [ "Why would you do that?" ], "action": [] } }, @@ -111,11 +111,11 @@ "locationDescription": "Plaster is crumbling from the WALLS.", "actions": { "look": { - "text": "You notice some rusty metal emerging behind the crumbling PLASTER of one wall.", + "text": [ "You notice some rusty metal emerging behind the crumbling PLASTER of one wall." ], "action": [] }, "remove": { - "text": "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR.", + "text": [ "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR." ], "action": [ "objectReplaceInLocation plaster_wall_door_unidentified plaster_wall_door_door_found", "objectRemoveFromLocation metal_behind_plaster" @@ -129,15 +129,15 @@ "locationDescription": "On the other side for the room is a RUSTY METAL DOOR.", "actions": { "look": { - "text": "A heavy metal door that was hidden under the plaster.", + "text": [ "A heavy metal door that was hidden under the plaster." ], "action": [] }, "go": { - "text": "You open the rusty door and enter a hallway.", + "text": [ "You open the rusty door and enter a hallway." ], "action": [ "gotoLocation long_hallway" ] }, "open": { - "text": "You open the rusty door and enter a hallway.", + "text": [ "You open the rusty door and enter a hallway." ], "action": [ "gotoLocation long_hallway" ] } }, @@ -148,15 +148,15 @@ "locationDescription": "", "actions": { "look": { - "text": "It looks like a rusty metal object is hidden behind the crumbling plaster.", + "text": [ "It looks like a rusty metal object is hidden behind the crumbling plaster." ], "action": [] }, "touch": { - "text": "The plaster feels loose, you might be able to remove it with your hands.", + "text": [ "The plaster feels loose, you might be able to remove it with your hands." ], "action": [] }, "remove": { - "text": "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR.", + "text": [ "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR." ], "action": [ "objectReplaceInLocation plaster_wall_door_door_visible plaster_wall_door_door_found", "objectRemoveFromLocation metal_behind_plaster" @@ -182,7 +182,7 @@ "action": [ "showLocationDescription" ] }, "light": { - "text": "If only you'd had something to enlighten the room with...", + "text": [ "If only you'd had something to enlighten the room with..." ], "action": [] } }, @@ -199,7 +199,7 @@ "action": [ "showLocationDescription" ] }, "light": { - "text": "The room is already slightly illuminated.", + "text": [ "The room is already slightly illuminated." ], "action": [] } }, @@ -212,14 +212,14 @@ "locationDescription": "You see a small BOX near you.", "actions": { "pickup": { - "text": "You got it. It's a box of matches!", + "text": [ "You got it. It's a box of matches!" ], "action": [ "objectRemoveFromLocation box_matches_unidentified", "inventoryAdd box_matches_pickedUp" ] }, "look": { - "text": "It's too dark to see the small box properly. You could probably reach it.", + "text": [ "It's too dark to see the small box properly. You could probably reach it." ], "action": [] } }, @@ -230,7 +230,7 @@ "locationDescription": "You are holding the box of MATCHES.", "actions": { "use": { - "text": "You light the last match. The room is now slightly illumanted.", + "text": [ "You light the last match. The room is now slightly illumanted." ], "action": [ "objectReplaceInLocation plaster_wall_door_unidentified plaster_wall_door_door_visible", "objectReplaceInLocation room_start_chamber_dark room_start_chamber_enlighted", @@ -239,7 +239,7 @@ ] }, "light": { - "text": "You light the last match. The room is now slightly illumanted.", + "text": [ "You light the last match. The room is now slightly illumanted." ], "action": [ "objectReplaceInLocation plaster_wall_door_unidentified plaster_wall_door_door_visible", "objectReplaceInLocation room_start_chamber_dark room_start_chamber_enlighted", @@ -248,14 +248,14 @@ ] }, "drop": { - "text": "You dropped the box of matches", + "text": [ "You dropped the box of matches" ], "action": [ "objectAddToLocation box_matches_dropped", "inventoryRemove box_matches_pickedUp" ] }, "look": { - "text": "An almost empty box of matches.", + "text": [ "An almost empty box of matches." ], "action": [] } }, @@ -266,14 +266,14 @@ "locationDescription": "You dropped the the box of MATCHES here.", "actions": { "pickup": { - "text": "You picked up the Box of Matches again!", + "text": [ "You picked up the Box of Matches again!" ], "action": [ "objectRemoveFromLocation box_matches_dropped", "inventoryAdd box_matches_pickedUp" ] }, "look": { - "text": "A small box of matches, that you dropped here...", + "text": [ "A small box of matches, that you dropped here..." ], "action": [] } }, @@ -284,7 +284,7 @@ "locationDescription": "The long corridor has cold stone walls.", "actions": { "look": { - "text": "", + "text": [ "" ], "action": [] } }, @@ -295,11 +295,11 @@ "locationDescription": "You see LIGHT at the other end of the hallway.", "actions": { "look": { - "text": "It seems to be sunlight that enlightens the end of the hallway.", + "text": [ "It seems to be sunlight that enlightens the end of the hallway." ], "action": [] }, "go": { - "text": "You walk towards the light, but you don't seem to get any closer. A gust of wind blows the LEAFLET to you.", + "text": [ "You walk towards the light, but you don't seem to get any closer. A gust of wind blows the LEAFLET to you." ], "action": [] } }, @@ -310,11 +310,11 @@ "locationDescription": "You see LIGHT at the other end of the hallway.", "actions": { "look": { - "text": "It seems to be sunlight that enlightens the end of the hallway.", + "text": [ "It seems to be sunlight that enlightens the end of the hallway." ], "action": [] }, "go": { - "text": "You walk towards the light, but you don't seem to get any closer.", + "text": [ "You walk towards the light, but you don't seem to get any closer." ], "action": [] } }, @@ -325,11 +325,11 @@ "locationDescription": "A LEAFLET is lying on the ground.", "actions": { "look": { - "text": "The text is too small to read the LEAFLET, while it's on the ground.", + "text": [ "The text is too small to read the LEAFLET, while it's on the ground." ], "action": [] }, "pickup": { - "text": "You take the leaflet.", + "text": [ "You take the leaflet." ], "action": [ "objectReplaceInLocation exit_light exit_light_without_leaflet", "objectRemoveFromLocation dev_leaflet_on_ground", @@ -351,7 +351,7 @@ "action": [] }, "drop": { - "text": "You dropped the leaflet.", + "text": [ "You dropped the leaflet." ], "action": [ "objectReplaceInLocation exit_light_without_leaflet exit_light", "objectAddToLocation dev_leaflet_on_ground", diff --git a/textAdventureDatabase.schema.json b/textAdventureDatabase.schema.json index aa665ff..3d50f12 100644 --- a/textAdventureDatabase.schema.json +++ b/textAdventureDatabase.schema.json @@ -10,18 +10,11 @@ "required": ["text", "action"], "properties": { "text": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - ] + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } }, "action": { "type": "array", @@ -67,7 +60,7 @@ }, "required": ["title", "author", "version", "request", "start"] }, - "ignored_words" : { + "ignored_words": { "description": "Words that will be ignored when parsing an user input. This prevent that they get interpreted as verbs or objects (Note: Thus objects and names can't have this as on of their 'words')", "type": "array", "items": { @@ -99,11 +92,7 @@ "type": "object", "additionalProperties": { "type": "object", - "required": [ - "words", - "locationDescription", - "actions" - ], + "required": ["words", "locationDescription", "actions"], "properties": { "words": { "description": "Alternative words that the player may use", From 1e3f80447543daadffeff3e5cb672a8ca10d7f77 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Mon, 15 Dec 2025 23:11:21 +0100 Subject: [PATCH 29/80] Improved UI for Editing Table --- editor/editor-style.css | 101 +++++++++++++++++++++++++++- editor/editor.html | 2 +- editor/tba_editor.js | 142 +++++++++++++++++++++++++--------------- 3 files changed, 189 insertions(+), 56 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index 1562045..b68da56 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -65,13 +65,108 @@ html { width: 100%; } + /* Sidebar and main area should scroll and size with viewport */ #elementSelection { - height: 100vw; grid-area: sidebar; + min-height: calc(100vh - 220px); + overflow:auto; + background: rgba(255,255,255,0.02); + padding: 8px; + border-right: 1px solid rgba(255,255,255,0.04); } #elementEditor { - padding: 15px; - height: 100vw; + padding: 20px; grid-area: main; + min-height: calc(100vh - 220px); + overflow:auto; + background: transparent; + } + + /* Simple modal form styles */ + #editModalDialog input[type="text"], #editModalDialog textarea, #editModalDialog select { + width: 100%; + padding: 6px 8px; + margin: 6px 0 12px 0; + box-sizing: border-box; + } + + /* Make selects readable on dark background */ + select, select option, select optgroup { + background: rgb(60, 60, 60); + color: var(--font-color); + border: 1px solid rgba(255,255,255,0.04); + padding:6px 8px; + } + + select::-ms-expand { display: none; } + + .modal-action-row { padding:8px 0; border-bottom:1px solid rgba(255,255,255,0.03); } + .modal-action-row:last-child { border-bottom:none; } + + .list-item { + display:flex; + align-items:center; + justify-content:space-between; + padding:8px 10px; + border-bottom:1px solid rgba(255,255,255,0.03); + background: transparent; + color: var(--font-color); + transition: background 0.15s ease; + } + .list-item .label { flex:1; } + .list-item .actions { margin-left:8px; } + .small-btn { padding:6px 8px; font-size:0.9em; border-radius:4px; margin-left:6px; } + + /* Inline group for per-object buttons */ + .object-list { table-layout: fixed; } + .object-list .btn-group-inline { display:flex; gap:8px; align-items:center; } + .object-list td { vertical-align: middle; } + .object-list td:first-child { width:25%; max-width:25%; white-space: normal; overflow-wrap: break-word; word-break: break-word; } + /* Generic left column class for other tables */ + .left-col { width:25%; max-width:25%; white-space: normal; overflow-wrap: break-word; word-break: break-word; } + + .list-item:hover { background: rgba(255,255,255,0.02); } + + /* Modal styles */ + .modal { display:none; position:fixed; inset:0; align-items:center; justify-content:center; z-index:9999; } + .modal-backdrop { position:absolute; inset:0; background:rgba(0,0,0,0.6); } + .modal-dialog { position:relative; background: var(--code-bg-color); color: var(--font-color); max-width:900px; width:min(900px,95%); padding:18px; border-radius:8px; box-shadow:0 10px 40px rgba(0,0,0,0.6); max-height:80vh; overflow:auto; } + .modal-body { margin-top:8px; } + .modal-actions { margin-top:12px; text-align:right; } + + /* Buttons */ + .btn { background: transparent; color: var(--font-color); border: 1px solid rgba(255,255,255,0.08); padding:8px 12px; border-radius:6px; cursor:pointer; } + .btn:hover { opacity:0.95; } + .btn-primary { background: var(--primary-color); color: var(--invert-font-color); border: none; } + .btn-error { background: var(--error-color); color: var(--invert-font-color); border: none; } + .btn-default { background: rgba(255,255,255,0.03); } + + /* Tabs */ + .editor-tab { color: var(--secondary-color); cursor: pointer; text-decoration: none; padding: 4px 8px; border-radius:6px; transition: background 0.12s ease, color 0.12s ease; } + .editor-tab:hover { color: var(--font-color); background: rgba(255,255,255,0.03); } + .editor-tab.active { background: var(--primary-color); color: var(--invert-font-color); font-weight:600; text-decoration: none; } + .editor-tab.active:hover { background: var(--primary-color); color: var(--invert-font-color); } + .editor-tab + .editor-tab { margin-left: 8px; } + + /* Inputs in modal—dark friendly */ + #editModalDialog input[type="text"], #editModalDialog textarea, #editModalDialog select { + width: 100%; + padding: 8px 10px; + margin: 6px 0 12px 0; + box-sizing: border-box; + background: rgba(255,255,255,0.03); + color: var(--font-color); + border: 1px solid rgba(255,255,255,0.04); + } + + #validationResults { padding:8px; border-radius:6px; margin-top:6px; } + #validationResults ul { margin:6px 0 0 18px; } + #validationResults div { font-weight:bold; } + + /* responsive */ + @media (max-width: 700px) { + #editor { grid-template-columns: 1fr; grid-template-areas: "main"; } + #elementSelection { order:2; min-height: 200px; } + #elementEditor { order:1; } } \ No newline at end of file diff --git a/editor/editor.html b/editor/editor.html index 07f2214..e9e9a94 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -119,7 +119,7 @@

DRAG & DROP *.tadb.json HERE

diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 5c2a488..1c5f685 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -140,6 +140,11 @@ function onTypeChanged(typeParam){ } if(type===null || type === undefined){ type="general"; } + // Highlight the active tab + $('.editor-tab').removeClass('active'); + let tabId = 'tab' + type.charAt(0).toUpperCase() + type.slice(1); + $('#' + tabId).addClass('active'); + $("#elementSelection").html(""); if(type=="general") { $("#elementEditor").html(generateUiForGeneral(TBA_DATABASE.general)); @@ -224,6 +229,7 @@ function generateUiForPreview() { previewRestartButton = button('Restart Game'); previewReloadButton = button('Reload Current Room'); buttonBar.append(previewReloadButton); + buttonBar.append(' '); buttonBar.append(previewRestartButton); previewContainer.append(buttonBar); @@ -335,19 +341,21 @@ function generateUiForGeneral(general) { function generateUiForVerbElement(verbName, verb) { let editorGui = $(''); - let name = $('

'+verbName+'

'); + let title = $('

Verb

'); let nameOptions = $(''); let removeButton = button('Remove', 'btn-error'); + nameOptions.append(''+verbName+''); + nameOptions.append(' '); removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; onTypeChanged(); }); //TODO: Also delete from all Objects nameOptions.append(removeButton); - + nameOptions.append(' '); let duplicateButton = button('Duplicate'); duplicateButton.click(function() { TBA_DATABASE.verbs[getAvailableVerbName(verbName)] = clone(verb); onTypeChanged(); }); nameOptions.append(duplicateButton); - editorGui.append(tableRow2(name, nameOptions)); + editorGui.append(tableRow2(title, nameOptions)); editorGui.append(generateInput("Failure", verb.failure, function(value){ verb.failure = value; })); editorGui.append(generateInput("Words", verb.words.join(", "), function(value){ @@ -360,18 +368,20 @@ function generateUiForVerbElement(verbName, verb) { function generateUiForObjectElement(objectName, object) { let editorGui = $('
'); - let name = $('

'+objectName+'

'); + let title = $('

Object

'); let nameOptions = $(''); let removeButton = button('Remove', 'btn-error'); + nameOptions.append(''+objectName+''); + nameOptions.append(' '); removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; onTypeChanged(); }); //TODO: Also delete from all locations nameOptions.append(removeButton); - + nameOptions.append(' '); let duplicateButton = button('Duplicate'); duplicateButton.click(function() { TBA_DATABASE.objects[getAvailableObjectName(objectName)] = clone(object); onTypeChanged(); }); nameOptions.append(duplicateButton); - editorGui.append(tableRow2(name, nameOptions)); + editorGui.append(tableRow2(title, nameOptions)); editorGui.append(generateInput("Location Description", object.locationDescription, function(value){ object.locationDescription = value; })); editorGui.append(generateInput("Words", object.words.join(", "), @@ -389,7 +399,7 @@ function generateUiForObjectElement(objectName, object) { action.action = value.split(NEWLINE).map(function(item) { return item.trim(); }).filter(e => e); })); }); - editorGui.append(tableRow2("
Add Action
", generateNewActionButton(object.actions, function(verb){ + editorGui.append(tableRow2("

Add Action

", generateNewActionButton(object.actions, function(verb){ if(object.actions[name]!==undefined){ alert("An action with this verb already exists for this object."); return; @@ -404,62 +414,90 @@ function generateUiForObjectElement(objectName, object) { function generateUiForLocationElement(locationName, location) { let editorGui = $('
'); - let name = $('

'+locationName+'

'); + let title = $('

Location

'); let nameOptions = $(''); let removeButton = button('Remove', 'btn-error'); + nameOptions.append(''+locationName+''); + nameOptions.append(' '); removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onTypeChanged(); }); nameOptions.append(removeButton); - + nameOptions.append(' '); let duplicateButton = button('Duplicate'); duplicateButton.click(function() { TBA_DATABASE.locations[getAvailableLocationName(locationName)] = clone(location); onTypeChanged(); }); nameOptions.append(duplicateButton); - - editorGui.append(tableRow2(name, nameOptions)); + + editorGui.append(tableRow2(title, nameOptions)); editorGui.append(tableH3('Objects')); + + let previewRow = $(''); + let previewHeadline = $(''); + let previewCell = $(''); - let leftCellSelector = $('
Preview Location Description'); + + editorGui.append(previewRow); + previewRow.append(previewHeadline); + previewRow.append(previewCell); + + function updatePreviewLocationText() { + let text = ""; + $.each(location.objects, function(index, objectName) { + if(text.length > 0) { text += " "; } + text += TBA_DATABASE.objects[objectName].locationDescription; + }); + previewCell.text(text); + } + updatePreviewLocationText(); + let rowSelector = $('
'); - let objSelector = $(''); - let removeObjectButton = button('Remove Object', 'btn-error btn-ghost'); - removeObjectButton.click(function() { - let index = objSelector.val(); - if(index === null || index < 0) { alert("No object selected"); return; } - delete location.objects.splice(index, 1); - onElementChanged(); - }); - let moveUpButton = button('Move Up'); - moveUpButton.click(function() { - let index = objSelector.val(); - if(index === null || index < 0) { alert("No object selected"); return; } - const indexInt = parseInt(index); - if(indexInt > 0) { - moveArrayElement(location.objects, indexInt, indexInt-1); - onElementChanged(); - } - }); - let moveDownButton = button('Move Down'); - moveDownButton.click(function() { - let index = objSelector.val(); - if(index === null || index < 0) { alert("No object selected"); return; } - const indexInt = parseInt(index); - if (indexInt < location.objects.length-1 ) { - moveArrayElement(location.objects, indexInt, indexInt+1); - onElementChanged(); - } + let leftCellSelector = $(''); + + // Render a table where each object has its own Move Up / Move Down / Remove buttons + let objList = $(''); + $.each(location.objects, function(index, objectName) { + let tr = $(''); + tr.append($(''); + let rowNewObject = $(''); rowNewObject.append(generateNewObjectForLocationButton(location.objects, function(obj){ location.objects.push(obj); onElementChanged(); @@ -488,7 +526,7 @@ function tableRow(element){ } function tableRow2(left, right){ let r = $(''); - let el = $(''); inputFieldArea.append(''); - let inputField = $(''); + let inputField = $(''); inputField.on( "change", function() { onChange(inputField.val()); onDatabaseChanged(); @@ -646,13 +646,32 @@ function generateTextArea(name, value, onChange){ let inputFieldArea = $(''); inputFieldArea.append(''); let valueTableField = $(''); + const col1 = $(''); + const col2 = $('
').text(objectName)); + let btnsTd = $(''); + + let moveUpButton = button('Move Up'); + moveUpButton.click(function() { + if(index > 0) { + moveArrayElement(location.objects, index, index-1); + onElementChanged(); + } + }); + if(index === 0) { moveUpButton.prop('disabled', true); } + + let moveDownButton = button('Move Down'); + moveDownButton.click(function() { + if(index < location.objects.length - 1) { + moveArrayElement(location.objects, index, index+1); + onElementChanged(); + } + }); + if(index === location.objects.length - 1) { moveDownButton.prop('disabled', true); } + + let removeObjectButton = button('Remove', 'btn-error btn-ghost'); + removeObjectButton.click(function() { + if(confirm('Remove "'+objectName+'"?')) { + location.objects.splice(index, 1); + onElementChanged(); + } + }); + + // Put buttons inline in a small button group + let btnGroup = $('
'); + btnGroup.append(moveUpButton); + btnGroup.append(moveDownButton); + btnGroup.append(removeObjectButton); + btnsTd.append(btnGroup); + tr.append(btnsTd); + objList.append(tr); }); - rightCellSelector.append(paragraph(moveUpButton)); - rightCellSelector.append(paragraph(moveDownButton)); - rightCellSelector.append(paragraph(removeObjectButton)); - rowSelector.append(rightCellSelector); + + leftCellSelector.append(objList); + rowSelector.append(leftCellSelector); editorGui.append(rowSelector); - let rowNewObject = $('
Add Object

Add Object

'); + let el = $(''); el.append(left); let er = $('') er.append(right); From 507fd010f6496515a53de6dd62ba79085c78bf0f Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Mon, 15 Dec 2025 23:39:25 +0100 Subject: [PATCH 30/80] Improved table headlines --- editor/editor-style.css | 85 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index b68da56..db9e3ce 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -20,8 +20,89 @@ html { margin-right: 10px; } - td { - padding: 5px; + /* Form table styles: stronger separators, subtle zebra, no hover highlighting */ + table.w100 { + width: 100%; + border-collapse: separate; + border-spacing: 0; + } + table.w100 td { + padding: 8px 10px; + border: none; /* remove any visible white borders */ + vertical-align: middle; + } + table.w100 tr { + border-bottom: 1px solid rgba(255,255,255,0.08); + background: transparent; + } + table.w100 tr.section-title td { + padding: 12px 8px 8px; + background: transparent; + } + + /* Headline variants for headings inside tables */ + table.w100 tr.section-title td h1, + table.w100 td h1 { + margin: 0; + display: inline-block; + background: rgba(98,196,255,0.9); + color: var(--invert-font-color); + padding: 8px 14px; + border-radius: 10px; + box-shadow: 0 3px 8px rgba(0,0,0,0.45); + font-size: 1.15em; + font-weight: 700; + } + + table.w100 tr.section-title td h2, + table.w100 td h2 { + margin: 0; + display: inline-block; + background: rgb(75, 151, 198); + color: var(--font-color); + padding: 4px 8px; + border-radius: 6px; + font-size: 1.00em; + font-weight: 600; + } + + table.w100 tr.section-title td h3, + table.w100 td h3 { + margin: 0; + display: inline-block; + background: rgb(171, 66, 115); + color: var(--font-color); + padding: 4px 8px; + border-radius: 6px; + font-size: 1.00em; + font-weight: 600; + } + + table.w100 tr.section-title td h4, + table.w100 td h4 { + margin: 0; + display: inline-block; + background: rgb(16, 94, 98); + color: var(--font-color); + padding: 4px 8px; + border-radius: 6px; + font-size: 1.00em; + font-weight: 600; + } + + table.w100 tr.section-title td h5, + table.w100 td h5 { + margin: 0; + display: inline-block; + background: linear-gradient(90deg, var(--error-color), rgba(255,60,116,0.95)); + color: var(--invert-font-color); + padding: 4px 8px; + border-radius: 6px; + font-size: 0.95em; + font-weight: 600; + } + table.w100 tr:nth-child(odd) { + background: rgba(255,255,255,0.02); } .w100 { From ed7ec7dd29812b8ff45968a4e13271715a5f2c8d Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Tue, 16 Dec 2025 00:10:43 +0100 Subject: [PATCH 31/80] Improved TextArea Layout --- editor/editor-style.css | 63 +++++++++++++++++++++++++++++++++++++++++ editor/tba_editor.js | 31 ++++++++++++++++---- 2 files changed, 88 insertions(+), 6 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index db9e3ce..5197852 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -241,6 +241,69 @@ html { border: 1px solid rgba(255,255,255,0.04); } + /* Modern textarea used in editor forms */ + .modern-textarea { + width: 100%; + min-height: 36px; /* single-line default */ + max-height: 400px; /* sensible upper bound */ + overflow: hidden; /* hide scrollbars, we'll auto expand */ + resize: none; + padding: 8px 10px; + background: rgba(255,255,255,0.02); + border: 1px solid rgba(255,255,255,0.06); + border-radius: 6px; + color: var(--font-color); + line-height: 1.4; + font-family: var(--mono-font-stack); + transition: box-shadow 0.12s ease, border-color 0.12s ease; + } + .modern-textarea:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 6px 18px rgba(98,196,255,0.08); + } + + /* Modern single-line inputs that match textarea styling */ + .modern-input { + width: 100%; + height: 36px; + padding: 8px 10px; + background: rgba(255,255,255,0.02); + border: 1px solid rgba(255,255,255,0.06); + border-radius: 6px; + color: var(--font-color); + box-sizing: border-box; + line-height: 1.4; + font-family: var(--mono-font-stack); + transition: box-shadow 0.12s ease, border-color 0.12s ease; + -webkit-appearance: none; + appearance: none; + } + .modern-input:focus { + outline: none; + border-color: var(--primary-color); + box-shadow: 0 6px 18px rgba(98,196,255,0.08); + } + + /* Ensure selects with modern-input and textarea match and override terminal defaults */ + input.modern-input, select.modern-input, textarea.modern-textarea { + -webkit-appearance: none; + appearance: none; + outline: none; + background: rgba(255,255,255,0.02); + border: 1px solid rgba(255,255,255,0.06); + } + input.modern-input:focus, + select.modern-input:focus, + textarea.modern-textarea:focus, + input.modern-input:focus-visible, + select.modern-input:focus-visible, + textarea.modern-textarea:focus-visible { + outline: none; + border-color: var(--primary-color) !important; + box-shadow: 0 6px 18px rgba(98,196,255,0.08) !important; + } + #validationResults { padding:8px; border-radius:6px; margin-top:6px; } #validationResults ul { margin:6px 0 0 18px; } #validationResults div { font-weight:bold; } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 1c5f685..6cdf9d4 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -580,7 +580,7 @@ function getAvailableVerbName(verbName) { function generateNewButton(onClick) { let editorGui = $('
'); - let elementNameInput = $(''); + let elementNameInput = $(''); let addButton = button('Add'); addButton.click(function() { @@ -598,7 +598,7 @@ function generateNewButton(onClick) { function generateNewActionButton(existingActions, onClick) { let editorGui = $('
'); - let selectNewAction = $(''); $.each(TBA_DATABASE.verbs, function( verb ) { if(existingActions[verb] !== undefined) { return; } selectNewAction.append($('
'); let container = $('
'); - let selectNewObject = $(''); $.each(TBA_DATABASE.objects, function( obj ) { if(existingObjects[obj] !== undefined) { return; } selectNewObject.append($('
'); - let inputField = $(''); - inputField.on( "change", function() { + let inputField = $(''); + + // Auto-resize on input and persist changes + inputField.on('input', function() { + this.style.height = 'auto'; + this.style.height = (this.scrollHeight) + 'px'; + onChange(inputField.val()); + onDatabaseChanged(); + }); + + // Also handle change event (blur) for compatibility + inputField.on( 'change', function() { onChange(inputField.val()); onDatabaseChanged(); } ); + valueTableField.append(inputField); inputFieldArea.append(valueTableField); + inputField.val(value); + + // Firefox may not compute scrollHeight correctly until the element is in the DOM, + // so run a delayed resize to ensure the textarea height matches its content. + setTimeout(function(){ + inputField.each(function(){ this.style.height = 'auto'; this.style.height = (this.scrollHeight) + 'px'; }); + }, 0); + return inputFieldArea; } From 7c2da6358f6ec5dd2370f92f05914148bf273d01 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Tue, 16 Dec 2025 00:25:17 +0100 Subject: [PATCH 32/80] Updated Select Field UI --- editor/editor-style.css | 4 +++- editor/editor.html | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index 5197852..985e9b3 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -174,7 +174,7 @@ html { /* Make selects readable on dark background */ select, select option, select optgroup { - background: rgb(60, 60, 60); + background: rgb(35, 35, 35); color: var(--font-color); border: 1px solid rgba(255,255,255,0.04); padding:6px 8px; @@ -289,10 +289,12 @@ html { input.modern-input, select.modern-input, textarea.modern-textarea { -webkit-appearance: none; appearance: none; + -moz-appearance: none; outline: none; background: rgba(255,255,255,0.02); border: 1px solid rgba(255,255,255,0.06); } + input.modern-input:focus, select.modern-input:focus, textarea.modern-textarea:focus, diff --git a/editor/editor.html b/editor/editor.html index e9e9a94..ba14bd4 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -119,6 +119,7 @@

DRAG & DROP *.tadb.json HERE

+

General | Verbs | Objects | Locations | Preview

From 03163118ac2196d968377b434b195bf7dda86c4f Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Tue, 16 Dec 2025 10:41:58 +0100 Subject: [PATCH 33/80] Added support for this reference and object specific failures --- README.md | 27 ++++++++++++++----- Templates/miniExample.tadb.json | 16 ++++++++---- editor/editor.html | 46 ++++++++++++++++++--------------- textAdventure.js | 34 ++++++++++++++---------- 4 files changed, 77 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 33df825..b5b3dde 100644 --- a/README.md +++ b/README.md @@ -73,32 +73,43 @@ Now you can use the `objectReplaceInLocation` function in `chest`s `open` action To close the chest again, you can use `objectReplaceInLocation` again in `chest_opened`s `close` action. +#### Object specific failure texts +If the user 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. + ### Functions Functions can be used in actions to modify the current location or the plazers inventory. +#### 'this' in function parameters +If the function should affect the object that the action is defined on, you can refer to it using `this` instead of its 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} +objectReplaceInLocation {objectNameToRemove} {objectNameToAdd} +objectReplaceInLocation this {objectNameToAdd} ``` -Removes `{objectIdToRemove}` and adds `{objectIdToAdd}`. Shorthand for sequentially calling `objectRemoveFromLocation` and `objectAddToLocation`. +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 @@ -110,13 +121,15 @@ Automatically shows the current location description, as if the user typed 'look #### inventoryAdd ``` -inventoryAdd {objectId} +inventoryAdd {objectName} +inventoryAdd this ``` Adds the item to users inventory. The user can have multiple items in his inventory, the location descriptions will be listed below each other. #### inventoryRemove ``` -inventoryRemove {objectId} +inventoryRemove {objectName} +inventoryRemove this ``` Removes the item from users inventory \ No newline at end of file diff --git a/Templates/miniExample.tadb.json b/Templates/miniExample.tadb.json index 4ffdde2..323430e 100644 --- a/Templates/miniExample.tadb.json +++ b/Templates/miniExample.tadb.json @@ -12,9 +12,17 @@ }, "ignored_words": ["to", "through", "on", "off", "from", "around", "at"], "verbs": { + "look": { + "failure": "Sorry you can't see that.", + "words": [ "look", "view", "watch", "read", "search" ] + }, "pickup": { "failure": "Sorry you can't see that.", "words": ["pick", "lift", "take", "get"] + }, + "drop": { + "failure": "How do you want to drop that?", + "words": [ "drop", "let go" ] } }, "objects": { @@ -25,9 +33,8 @@ "pickup": { "text": ["okay got it"], "action": [ - "objectRemoveFromLocation template_object", - "objectState pickedUp", - "inventoryAdd template_object" + "objectRemoveFromLocation this", + "inventoryAdd template_object_pickedUp" ] }, "look": { @@ -45,8 +52,7 @@ "text": ["okay dropped it"], "action": [ "objectAddToLocation template_object", - "objectState default", - "inventoryRemove template_object" + "inventoryRemove this" ] }, "look": { diff --git a/editor/editor.html b/editor/editor.html index ba14bd4..0a59a99 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -42,64 +42,68 @@ "title": "TextAdventureJS Database Mini Example", "author": "Daniel Korgel", "version": "0.1", - "request": [ "", "What do you do?" ], + "request": ["", "What do you do?"], "start": { "text": ["Welcome to the textAdventureJS Mini Example"], - "action": [ "gotoLocation template_room" ] + "action": ["gotoLocation template_room"] } }, - "ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ], + "ignored_words": ["to", "through", "on", "off", "from", "around", "at"], "verbs": { + "look": { + "failure": "Sorry you can't see that.", + "words": [ "look", "view", "watch", "read", "search" ] + }, "pickup": { "failure": "Sorry you can't see that.", - "words": [ "pick", "lift", "take", "get" ] + "words": ["pick", "lift", "take", "get"] + }, + "drop": { + "failure": "How do you want to drop that?", + "words": [ "drop", "let go" ] } }, "objects": { "template_object": { - "words": [ "pillow", "pill" ], + "words": ["pillow", "pill"], "locationDescription": "A pillow is lying on the floor", "actions": { "pickup": { - "text": [ "okay got it" ], + "text": ["okay got it"], "action": [ - "objectRemoveFromLocation template_object", - "objectState pickedUp", - "inventoryAdd template_object" + "objectRemoveFromLocation this", + "inventoryAdd template_object_pickedUp" ] }, "look": { - "text": [ "soft and comfy" ], + "text": ["soft and comfy"], "action": [] } }, - "useableObjects": { } + "useableObjects": {} }, "template_object_pickedUp": { - "words": [ "pillow", "pill" ], + "words": ["pillow", "pill"], "locationDescription": "You are holding pillow in your hand.", "actions": { "drop": { - "text": [ "okay dropped it" ], + "text": ["okay dropped it"], "action": [ "objectAddToLocation template_object", - "objectState default", - "inventoryRemove template_object" + "inventoryRemove this" ] }, "look": { - "text": [ "soft and comfy" ], + "text": ["soft and comfy"], "action": [] } }, - "useableObjects": { } + "useableObjects": {} } }, "locations": { "template_room": { - "objects": [ - "template_object" - ] + "objects": ["template_object"] } } } @@ -120,7 +124,7 @@

DRAG & DROP *.tadb.json HERE

diff --git a/textAdventure.js b/textAdventure.js index 711efeb..4159deb 100644 --- a/textAdventure.js +++ b/textAdventure.js @@ -133,7 +133,7 @@ class textAdventureEngine { //no action if(verb == undefined && object != undefined){ - this.#writeOutputLines("Unknown verb, please try to rephrase your command."); //TODO: Improve + this.#writeOutputLines("Unknown verb, please try to rephrase your command."); //TODO: Move to Game Database this.#showRequest(); return; } @@ -166,16 +166,16 @@ class textAdventureEngine { } if(result != undefined){ - let objectStateVerbDefinition = object.actions[verbName]; - this.#writeOutputLines(objectStateVerbDefinition.text); - this.#runActions(object, objectStateVerbDefinition.action); + let objectVerbAction = object.actions[verbName]; + this.#writeOutputLines(objectVerbAction.text); + this.#runActions(objectName, objectVerbAction.action); }else{ - this.#writeOutputLines(verb.failure); //TODO: Could be improved, verb doesn't work with object + this.#writeOutputLines(verb.failure); } this.#showRequest(); return; } - this.#writeOutputLines("Please try to rephrase your command."); //TODO: Replace with something more immersive + this.#writeOutputLines("Please try to rephrase your command."); //TODO: Move to Game Database } this.#showRequest(); } @@ -203,27 +203,35 @@ class textAdventureEngine { } } - #runActions(callingObject, actions){ + #runActions(callingObjectName, actions){ if(actions === undefined){ return; } if($.isArray(actions)) { for(var i=0; i -1) { From 789ffaf9db222404d1c79ad1adffa7ec518afccc Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 21:46:15 +0100 Subject: [PATCH 34/80] Added improved Functions Editor --- editor/editor-style.css | 9 +++ editor/tba_editor.js | 161 ++++++++++++++++++++++++++++++++++------ 2 files changed, 148 insertions(+), 22 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index 985e9b3..e9e2638 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -204,6 +204,15 @@ html { .object-list .btn-group-inline { display:flex; gap:8px; align-items:center; } .object-list td { vertical-align: middle; } .object-list td:first-child { width:25%; max-width:25%; white-space: normal; overflow-wrap: break-word; word-break: break-word; } + + /* Functions list: render as a two-column table (function text + buttons) */ + .function-list-table { width: 100%; border-collapse: separate; border-spacing: 0; } + .function-list-table td { padding:8px 10px; vertical-align: middle; border-bottom:1px solid rgba(255,255,255,0.03); } + .function-list-table td:first-child { width: 75%; max-width: 75%; white-space: normal; overflow-wrap: break-word; word-break: break-word; } + .function-list-table .func-text { display:block; } + .function-list-table .btn-group-inline { display:flex; gap:8px; align-items:center; justify-content:flex-end; } + .function-list-table tr:first-child td { padding-top:4px; } + .function-list-table tr:last-child td { padding-bottom:4px; } /* Generic left column class for other tables */ .left-col { width:25%; max-width:25%; white-space: normal; overflow-wrap: break-word; word-break: break-word; } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 6cdf9d4..f49350a 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -14,6 +14,16 @@ var previewReloadButton = undefined; const NEWLINE = "\n"; //" "; +const FUNCTIONS = { + showLocationDescription: [ ], + gotoLocation: [ "location" ], + objectRemoveFromLocation: [ "object" ], + objectAddToLocation: [ "object" ], + objectReplaceInLocation: [ "object", "object"], + inventoryAdd: [ "object" ], + inventoryRemove: [ "object" ], +} + var type; $( document ).ready(function() { @@ -395,9 +405,7 @@ function generateUiForObjectElement(objectName, object) { removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); editorGui.append(tableRow2(name, removeActionButton)); editorGui.append(generateTextArea("Text", action.text.join(NEWLINE), function(value){ action.text = value.split(NEWLINE); })); - editorGui.append(generateTextArea("Functions", action.action.join(NEWLINE), function(value){ - action.action = value.split(NEWLINE).map(function(item) { return item.trim(); }).filter(e => e); - })); + editorGui.append(generateFunctionsUI(action.action)); }); editorGui.append(tableRow2("

Add Action

", generateNewActionButton(object.actions, function(verb){ if(object.actions[name]!==undefined){ @@ -458,25 +466,28 @@ function generateUiForLocationElement(locationName, location) { tr.append($('
').text(objectName)); let btnsTd = $(''); - let moveUpButton = button('Move Up'); - moveUpButton.click(function() { - if(index > 0) { - moveArrayElement(location.objects, index, index-1); - onElementChanged(); - } - }); - if(index === 0) { moveUpButton.prop('disabled', true); } - - let moveDownButton = button('Move Down'); - moveDownButton.click(function() { - if(index < location.objects.length - 1) { - moveArrayElement(location.objects, index, index+1); - onElementChanged(); - } - }); - if(index === location.objects.length - 1) { moveDownButton.prop('disabled', true); } +let moveUpButton = button('▲', 'btn-default small-btn'); + moveUpButton.attr('title', 'Move Up').attr('aria-label', 'Move up'); + moveUpButton.click(function() { + if(index > 0) { + moveArrayElement(location.objects, index, index-1); + onElementChanged(); + } + }); + if(index === 0) { moveUpButton.prop('disabled', true); } + + let moveDownButton = button('▼', 'btn-default small-btn'); + moveDownButton.attr('title', 'Move Down').attr('aria-label', 'Move down'); + moveDownButton.click(function() { + if(index < location.objects.length - 1) { + moveArrayElement(location.objects, index, index+1); + onElementChanged(); + } + }); + if(index === location.objects.length - 1) { moveDownButton.prop('disabled', true); } - let removeObjectButton = button('Remove', 'btn-error btn-ghost'); + let removeObjectButton = button('✖', 'btn-error btn-ghost small-btn'); + removeObjectButton.attr('title','Remove').attr('aria-label','Remove'); removeObjectButton.click(function() { if(confirm('Remove "'+objectName+'"?')) { location.objects.splice(index, 1); @@ -508,7 +519,7 @@ function generateUiForLocationElement(locationName, location) { } function button(text, btnClasses = 'btn-default') { - return $(''); + return $(''); } function paragraph(element) { @@ -628,6 +639,112 @@ function generateNewObjectForLocationButton(existingObjects, onClick) { return editorGui; } +function generateFunctionsUI(actions) { + const editorGui = $('
Functions'); + editorGui.append(col1); + editorGui.append(col2); + + const existingFunctionsTable = $(''); + if (!actions || actions.length === 0) { + const tr = $(''); + tr.append($('')); + existingFunctionsTable.append(tr); + } else { + $.each(actions, function(index, actionString) { + const tr = $(''); + const tdText = $(''); inputFieldArea.append(''); From 4a3b63c560acc64916168fe48efb5e7b0bf1d67b Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 22:08:02 +0100 Subject: [PATCH 35/80] Improved debugger ui --- editor/tba_editor.js | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index f49350a..b073614 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -237,7 +237,7 @@ function generateUiForPreview() { let buttonBar = $('

'); previewRestartButton = button('Restart Game'); - previewReloadButton = button('Reload Current Room'); + previewReloadButton = button('Reset Current Room'); buttonBar.append(previewReloadButton); buttonBar.append(' '); buttonBar.append(previewRestartButton); @@ -307,17 +307,31 @@ function readUserInput(){ function updatePreviewSideBar() { let gameState = textAdv.devGetGameState(); $("#elementSelection").html(""); - let currentLocation = $('

Current Location: '+gameState.currentLocation+'

'); - $("#elementSelection").append(currentLocation); let inventoryList = $('
    '); - $.each(gameState.inventory, function( objectName ) { - inventoryList.append($('
  • '+objectName+'
  • ')); - }); - $("#elementSelection").append($('

    Inventory

    ')); + const inv = gameState.inventory; + if (!inv || (Array.isArray(inv) ? inv.length === 0 : Object.keys(inv).length === 0)) { + inventoryList.append($('
  • (empty)
  • ')); + } else { + if (Array.isArray(inv)) { + $.each(inv, function(index, objectName) { + inventoryList.append($('
  • '+objectName+'
  • ')); + }); + } else { + $.each(Object.keys(inv), function(i, objectName) { + inventoryList.append($('
  • '+objectName+'
  • ')); + }); + } + } + $("#elementSelection").append($('

    Inventory

    ')); $("#elementSelection").append(inventoryList); let locations = $('
      '); $.each(gameState.locations, function( locationName, locationObj ) { - let location = $('
    • '+locationName+'
    • '); + let location = $('
    • '); + if(locationName == gameState.currentLocation) { + location.append(''+locationName+' (current)'); + }else{ + location.append(''+locationName+''); + } let locationObjs = $('
        '); $.each(locationObj.objects, function( index, objectName ) { locationObjs.append($('
      • '+objectName+'
      • ')); @@ -325,7 +339,7 @@ function updatePreviewSideBar() { location.append(locationObjs); locations.append(location); }); - $("#elementSelection").append($('

        Locations

        ')); + $("#elementSelection").append($('

        Location States

        ')); $("#elementSelection").append(locations); } From e91ade1593559e8af87f9248092d3929e0ab1339 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 22:15:19 +0100 Subject: [PATCH 36/80] Improved button font colors --- editor/editor-style.css | 12 ++++++++++-- editor/tba_editor.js | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index e9e2638..e690a98 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -228,10 +228,18 @@ html { /* Buttons */ .btn { background: transparent; color: var(--font-color); border: 1px solid rgba(255,255,255,0.08); padding:8px 12px; border-radius:6px; cursor:pointer; } .btn:hover { opacity:0.95; } - .btn-primary { background: var(--primary-color); color: var(--invert-font-color); border: none; } - .btn-error { background: var(--error-color); color: var(--invert-font-color); border: none; } + .btn-primary { background: var(--primary-color); color: var(--font-color); border: none; } + .btn-error { background: var(--error-color); color: var(--font-color); border: none; } .btn-default { background: rgba(255,255,255,0.03); } + /* Prominent action buttons (Save / Close) */ + .large-action { padding: 10px 16px; font-weight:700; font-size:1rem; border-radius:8px; box-shadow: 0 6px 18px rgba(0,0,0,0.25); transition: transform 0.08s ease, box-shadow 0.08s ease; } + #btn-save.large-action { background: var(--primary-color); color: var(--font-color); border: none; } + #btn-close.large-action { background: var(--error-color); color: var(--font-color); border: none; } + #btn-save.large-action:hover, #btn-close.large-action:hover { transform: translateY(-1px); box-shadow: 0 10px 24px rgba(0,0,0,0.28); } + /* Slight spacing so they don't blend into the menu */ + #btn-save, #btn-close { margin-left: 8px; } + /* Tabs */ .editor-tab { color: var(--secondary-color); cursor: pointer; text-decoration: none; padding: 4px 8px; border-radius:6px; transition: background 0.12s ease, color 0.12s ease; } .editor-tab:hover { color: var(--font-color); background: rgba(255,255,255,0.03); } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index b073614..b59df2a 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -57,6 +57,10 @@ $( document ).ready(function() { deleteDatabaseFromStorage(); updateEditorState(); }); + // Make Save / Close buttons more prominent for quick access + $('#btn-save').addClass('btn-primary large-action'); + $('#btn-close').addClass('btn-error large-action'); + loadToDatabaseFromStorage(); updateEditorState(); if (TBA_DATABASE != undefined) { From 8050e11c6fcc433f6f061344264f0ce21c97fd02 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 22:23:41 +0100 Subject: [PATCH 37/80] Improved drag and drop --- editor/editor-style.css | 29 +++++++++++++++++++++++++++++ editor/editor.html | 12 +++++++----- editor/tba_editor.js | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index e690a98..f9b006f 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -156,6 +156,35 @@ html { border-right: 1px solid rgba(255,255,255,0.04); } + /* Drag & drop area */ + .file-drop-area { + margin: 18px 0; + padding: 36px 24px; + border-radius: 12px; + border: 2px dashed rgba(255,255,255,0.06); + background: linear-gradient(180deg, rgba(255,255,255,0.01), rgba(255,255,255,0.00)); + text-align: center; + transition: box-shadow 0.12s ease, transform 0.06s ease, border-color 0.12s ease, background 0.12s ease; + cursor: pointer; + } + .file-drop-area h1 { margin: 0 0 12px 0; font-size: 1.05rem; color: var(--primary-color); letter-spacing: 1px; } + .file-drop-area .muted { color: var(--secondary-color); font-weight:600; font-size:0.95rem; } + .file-drop-area p { margin: 0; color: var(--secondary-color); } + .file-drop-area .btn { margin-top: 12px; } + + .file-drop-area.drag-active { + box-shadow: 0 10px 40px rgba(98,196,255,0.06); + border-color: rgba(98,196,255,0.9); + background: linear-gradient(180deg, rgba(98,196,255,0.03), rgba(98,196,255,0.01)); + transform: translateY(-2px); + } + .file-drop-area:hover { box-shadow: 0 8px 32px rgba(0,0,0,0.06); border-color: rgba(255,255,255,0.08); transform: translateY(-1px); } + + /* Small helper text for the drop area */ + .file-drop-area .hint { display:block; margin-top:8px; color:var(--secondary-color); font-size:0.95rem; } + .file-drop-area:focus { outline: none; box-shadow: 0 10px 40px rgba(98,196,255,0.06); } + + #elementEditor { padding: 20px; grid-area: main; diff --git a/editor/editor.html b/editor/editor.html index 0a59a99..633afd3 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -115,11 +115,13 @@

        textAdventureJS Game Database Editor

        -
        -

        DRAG & DROP *.tadb.json HERE

        - - -
        +
        + +
        +

        DRAG & DROP *.tadb.json HERE

        +

        or click to browse files

        +
        +
        diff --git a/editor/tba_editor.js b/editor/tba_editor.js index b59df2a..05dab8c 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -26,19 +26,46 @@ const FUNCTIONS = { var type; -$( document ).ready(function() { - $(".file-drop-area").on('dragover', (e) => { - // Prevent navigation. +$( document ).ready(function() { // Create a hidden file input to support click-to-open + if ($('#fileInput').length === 0) { + const hiddenFileInput = $(''); + $('body').append(hiddenFileInput); + hiddenFileInput.on('change', function() { const file = this.files && this.files[0]; if (file) importFile(file); this.value = null; }); + } $(".file-drop-area").on('dragenter', (e) => { + // highlight e.preventDefault(); + $(".file-drop-area").addClass('drag-active'); }); + + $(".file-drop-area").on('dragover', (e) => { + // Prevent navigation and keep highlight + e.preventDefault(); + $(".file-drop-area").addClass('drag-active'); + }); + + $(".file-drop-area").on('dragleave', (e) => { + // remove highlight + $(".file-drop-area").removeClass('drag-active'); + }); $(".file-drop-area").on('drop', async (e) => { e.preventDefault(); + $(".file-drop-area").removeClass('drag-active'); var file = e.originalEvent.dataTransfer.files[0]; importFile(file); }); + + // allow clicking the area to open a file picker (hidden input appended below) + $('.file-drop-area').on('click', function() { $('#fileInput').click(); }); + // keyboard support: Enter or Space opens file picker when area is focused + $('.file-drop-area').on('keypress', function(e) { + if (e.key === 'Enter' || e.key === ' ' || e.keyCode === 13 || e.keyCode === 32) { + e.preventDefault(); + $('#fileInput').click(); + } + }); $("#btn-new").click(() => { // Load the inlined default database JSON const defaultJson = getDefaultProjectJson(); From 4a9157d5789c201f72e0ba5e4bea48770d068157 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 22:30:56 +0100 Subject: [PATCH 38/80] Improved new project template --- Templates/miniExample.tadb.json | 71 ------------- Templates/new_project.json | 181 ++++++++++++++++++++++++++++++++ editor/editor.html | 146 ++++++++++++++++++++++---- editor/tba_editor.js | 2 +- 4 files changed, 310 insertions(+), 90 deletions(-) delete mode 100644 Templates/miniExample.tadb.json create mode 100644 Templates/new_project.json diff --git a/Templates/miniExample.tadb.json b/Templates/miniExample.tadb.json deleted file mode 100644 index 323430e..0000000 --- a/Templates/miniExample.tadb.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "$schema": "../textAdventureDatabase.schema.json", - "general": { - "title": "TextAdventureJS Database Mini Example", - "author": "Daniel Korgel", - "version": "0.1", - "request": ["", "What do you do?"], - "start": { - "text": ["Welcome to the textAdventureJS Mini Example"], - "action": ["gotoLocation template_room"] - } - }, - "ignored_words": ["to", "through", "on", "off", "from", "around", "at"], - "verbs": { - "look": { - "failure": "Sorry you can't see that.", - "words": [ "look", "view", "watch", "read", "search" ] - }, - "pickup": { - "failure": "Sorry you can't see that.", - "words": ["pick", "lift", "take", "get"] - }, - "drop": { - "failure": "How do you want to drop that?", - "words": [ "drop", "let go" ] - } - }, - "objects": { - "template_object": { - "words": ["pillow", "pill"], - "locationDescription": "A pillow is lying on the floor", - "actions": { - "pickup": { - "text": ["okay got it"], - "action": [ - "objectRemoveFromLocation this", - "inventoryAdd template_object_pickedUp" - ] - }, - "look": { - "text": ["soft and comfy"], - "action": [] - } - }, - "useableObjects": {} - }, - "template_object_pickedUp": { - "words": ["pillow", "pill"], - "locationDescription": "You are holding pillow in your hand.", - "actions": { - "drop": { - "text": ["okay dropped it"], - "action": [ - "objectAddToLocation template_object", - "inventoryRemove this" - ] - }, - "look": { - "text": ["soft and comfy"], - "action": [] - } - }, - "useableObjects": {} - } - }, - "locations": { - "template_room": { - "objects": ["template_object"] - } - } -} diff --git a/Templates/new_project.json b/Templates/new_project.json new file mode 100644 index 0000000..be28e09 --- /dev/null +++ b/Templates/new_project.json @@ -0,0 +1,181 @@ +{ + "$schema": "../textAdventureDatabase.schema.json", + "general": { + "title": "New TextAdventureJS Game", + "author": "Your Name", + "version": "0.1", + "request": [ + "", + "What do you do?" + ], + "start": { + "text": [ + "Welcome to the textAdventureJS Mini Example" + ], + "action": [ + "gotoLocation template_room" + ] + } + }, + "ignored_words": [ + "to", + "through", + "on", + "off", + "from", + "around", + "at" + ], + "verbs": { + "look": { + "failure": "Sorry you can't see that.", + "words": [ + "look", + "view", + "watch", + "read", + "search" + ] + }, + "pickup": { + "failure": "Sorry you can't see that.", + "words": [ + "pick", + "pickup", + "lift", + "take", + "get", + "reach" + ] + }, + "drop": { + "failure": "How do you want to drop that?", + "words": [ + "drop", + "let go" + ] + }, + "activate": { + "failure": "Sorry you can't do that.", + "words": [ + "turn", + "power", + "switch" + ] + }, + "go": { + "failure": "Sorry you can't go there.", + "words": [ + "go", + "walk", + "run", + "goto" + ] + }, + "open": { + "failure": "Sorry you can't open that.", + "words": [ + "open", + "break" + ] + }, + "close": { + "failure": "Sorry you can't close that.", + "words": [ + "close", + "shut" + ] + }, + "jump": { + "failure": "Sorry this is not possible.", + "words": [ + "jump" + ] + }, + "use": { + "failure": "Well.. this does not work.", + "words": [ + "use", + "combine", + "throw", + "attack" + ] + }, + "light": { + "failure": "Well.. this does not work.", + "words": [ + "light", + "burn", + "fire" + ] + }, + "remove": { + "failure": "Well.. this does not work.", + "words": [ + "remove", + "break", + "split", + "destroy" + ] + } + }, + "objects": { + "template_object": { + "words": [ + "pillow", + "pill" + ], + "locationDescription": "An object is lying on the floor.", + "actions": { + "pickup": { + "text": [ + "Okay got it." + ], + "action": [ + "objectRemoveFromLocation this", + "inventoryAdd template_object_pickedUp" + ] + }, + "look": { + "text": [ + "A mysterious object." + ], + "action": [] + } + }, + "useableObjects": {} + }, + "template_object_pickedUp": { + "words": [ + "pillow", + "pill" + ], + "locationDescription": "You are holding pillow in your hand.", + "actions": { + "drop": { + "text": [ + "Okay dropped it." + ], + "action": [ + "objectAddToLocation template_object", + "inventoryRemove this" + ] + }, + "look": { + "text": [ + "A mysterious object." + ], + "action": [] + } + }, + "useableObjects": {} + } + }, + "locations": { + "first_room": { + "objects": [ + "template_object" + ] + } + } +} \ No newline at end of file diff --git a/editor/editor.html b/editor/editor.html index 633afd3..f991393 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -39,62 +39,170 @@ { "$schema": "../textAdventureDatabase.schema.json", "general": { - "title": "TextAdventureJS Database Mini Example", - "author": "Daniel Korgel", + "title": "New TextAdventureJS Game", + "author": "Your Name", "version": "0.1", - "request": ["", "What do you do?"], + "request": [ + "", + "What do you do?" + ], "start": { - "text": ["Welcome to the textAdventureJS Mini Example"], - "action": ["gotoLocation template_room"] + "text": [ + "Welcome to the textAdventureJS Mini Example" + ], + "action": [ + "gotoLocation template_room" + ] } }, - "ignored_words": ["to", "through", "on", "off", "from", "around", "at"], + "ignored_words": [ + "to", + "through", + "on", + "off", + "from", + "around", + "at" + ], "verbs": { "look": { "failure": "Sorry you can't see that.", - "words": [ "look", "view", "watch", "read", "search" ] + "words": [ + "look", + "view", + "watch", + "read", + "search" + ] }, "pickup": { "failure": "Sorry you can't see that.", - "words": ["pick", "lift", "take", "get"] + "words": [ + "pick", + "pickup", + "lift", + "take", + "get", + "reach" + ] }, "drop": { "failure": "How do you want to drop that?", - "words": [ "drop", "let go" ] + "words": [ + "drop", + "let go" + ] + }, + "activate": { + "failure": "Sorry you can't do that.", + "words": [ + "turn", + "power", + "switch" + ] + }, + "go": { + "failure": "Sorry you can't go there.", + "words": [ + "go", + "walk", + "run", + "goto" + ] + }, + "open": { + "failure": "Sorry you can't open that.", + "words": [ + "open", + "break" + ] + }, + "close": { + "failure": "Sorry you can't close that.", + "words": [ + "close", + "shut" + ] + }, + "jump": { + "failure": "Sorry this is not possible.", + "words": [ + "jump" + ] + }, + "use": { + "failure": "Well.. this does not work.", + "words": [ + "use", + "combine", + "throw", + "attack" + ] + }, + "light": { + "failure": "Well.. this does not work.", + "words": [ + "light", + "burn", + "fire" + ] + }, + "remove": { + "failure": "Well.. this does not work.", + "words": [ + "remove", + "break", + "split", + "destroy" + ] } }, "objects": { "template_object": { - "words": ["pillow", "pill"], - "locationDescription": "A pillow is lying on the floor", + "words": [ + "pillow", + "pill" + ], + "locationDescription": "An object is lying on the floor.", "actions": { "pickup": { - "text": ["okay got it"], + "text": [ + "Okay got it." + ], "action": [ "objectRemoveFromLocation this", "inventoryAdd template_object_pickedUp" ] }, "look": { - "text": ["soft and comfy"], + "text": [ + "A mysterious object." + ], "action": [] } }, "useableObjects": {} }, "template_object_pickedUp": { - "words": ["pillow", "pill"], + "words": [ + "pillow", + "pill" + ], "locationDescription": "You are holding pillow in your hand.", "actions": { "drop": { - "text": ["okay dropped it"], + "text": [ + "Okay dropped it." + ], "action": [ "objectAddToLocation template_object", "inventoryRemove this" ] }, "look": { - "text": ["soft and comfy"], + "text": [ + "A mysterious object." + ], "action": [] } }, @@ -102,8 +210,10 @@ } }, "locations": { - "template_room": { - "objects": ["template_object"] + "first_room": { + "objects": [ + "template_object" + ] } } } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 05dab8c..288b48d 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -19,7 +19,7 @@ const FUNCTIONS = { gotoLocation: [ "location" ], objectRemoveFromLocation: [ "object" ], objectAddToLocation: [ "object" ], - objectReplaceInLocation: [ "object", "object"], + objectReplaceInLocation: [ "object", "object" ], inventoryAdd: [ "object" ], inventoryRemove: [ "object" ], } From 7e425e3cab6bd9adaa99a548a45f751230199022 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 22:37:43 +0100 Subject: [PATCH 39/80] Added parser ignored words to editor --- Templates/empty.tadb.json | 4 ++-- Templates/new_project.json | 20 ++++++++++---------- editor/editor.html | 20 ++++++++++---------- editor/tba_editor.js | 1 + lonesurvivor.tadb.json | 4 ++-- textAdventure.js | 2 +- textAdventureDatabase.schema.json | 18 +++++++++--------- 7 files changed, 35 insertions(+), 34 deletions(-) diff --git a/Templates/empty.tadb.json b/Templates/empty.tadb.json index 2357201..dc6391f 100644 --- a/Templates/empty.tadb.json +++ b/Templates/empty.tadb.json @@ -10,9 +10,9 @@ "text": ["Welcome to the Empty Template"], "inventory": "", "action": ["gotoLocation first_room"] - } + }, + "ignored_words": [] }, - "ignored_words": [], "verbs": {}, "objects": {}, "locations": { diff --git a/Templates/new_project.json b/Templates/new_project.json index be28e09..c06a923 100644 --- a/Templates/new_project.json +++ b/Templates/new_project.json @@ -15,17 +15,17 @@ "action": [ "gotoLocation template_room" ] - } + }, + "ignored_words": [ + "to", + "through", + "on", + "off", + "from", + "around", + "at" + ] }, - "ignored_words": [ - "to", - "through", - "on", - "off", - "from", - "around", - "at" - ], "verbs": { "look": { "failure": "Sorry you can't see that.", diff --git a/editor/editor.html b/editor/editor.html index f991393..47d0015 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -53,17 +53,17 @@ "action": [ "gotoLocation template_room" ] - } + }, + "ignored_words": [ + "to", + "through", + "on", + "off", + "from", + "around", + "at" + ] }, - "ignored_words": [ - "to", - "through", - "on", - "off", - "from", - "around", - "at" - ], "verbs": { "look": { "failure": "Sorry you can't see that.", diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 288b48d..31f4f85 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -385,6 +385,7 @@ function generateUiForGeneral(general) { table.append(generateInput("Version", general.version, function(value){ general.version = value; })); table.append(tableH3('Game Settings')); table.append(generateTextArea("Request", general.request.join(NEWLINE), function(value){ general.request = value.split(NEWLINE); })); + table.append(generateInput("Parser Ignored Words", general.ignored_words.join(", "), function(value){ general.ignored_words = value.split(",").map(function(item) { return item.trim(); }); })); table.append(tableH3('Game Start')); table.append(generateTextArea("Introduction", general.start.text.join(NEWLINE), function(value){ general.start.text = value.split(NEWLINE); })); table.append(generateTextArea("Functions", general.start.action.join(NEWLINE), function(value){ diff --git a/lonesurvivor.tadb.json b/lonesurvivor.tadb.json index 3e91715..796254f 100644 --- a/lonesurvivor.tadb.json +++ b/lonesurvivor.tadb.json @@ -8,9 +8,9 @@ "start": { "text": [ "", "", "", "You wake up with a headache..." ], "action": [ "gotoLocation start_chamber" ] - } + }, + "ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ] }, - "ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ], "verbs": { "pickup": { "failure": "Sorry you can't see that.", diff --git a/textAdventure.js b/textAdventure.js index 4159deb..ce74271 100644 --- a/textAdventure.js +++ b/textAdventure.js @@ -89,7 +89,7 @@ class textAdventureEngine { cmd = cmd.toLowerCase(); // remove ignored words from command - cmd = this.#removeFromString(this.#database.ignored_words, cmd); + cmd = this.#removeFromString(this.#database.general.ignored_words, cmd); cmd = cmd.trim(); console.log("Stripped command of parser: '"+cmd+"'"); diff --git a/textAdventureDatabase.schema.json b/textAdventureDatabase.schema.json index 3d50f12..7e9a552 100644 --- a/textAdventureDatabase.schema.json +++ b/textAdventureDatabase.schema.json @@ -58,14 +58,14 @@ "$ref": "#/definitions/action_definition" } }, - "required": ["title", "author", "version", "request", "start"] - }, - "ignored_words": { - "description": "Words that will be ignored when parsing an user input. This prevent that they get interpreted as verbs or objects (Note: Thus objects and names can't have this as on of their 'words')", - "type": "array", - "items": { - "type": "string" - } + "ignored_words": { + "description": "Words that will be ignored when parsing an user input. This prevent that they get interpreted as verbs or objects (Note: Thus objects and names can't have this as on of their 'words')", + "type": "array", + "items": { + "type": "string" + } + }, + "required": ["title", "author", "version", "request", "start", "ignored_words"] }, "verbs": { "description": "List of verbs that are available throughout the game", @@ -141,5 +141,5 @@ } } }, - "required": ["general", "ignored_words", "verbs", "objects", "locations"] + "required": ["general", "verbs", "objects", "locations"] } From f31873ff0371cd45a9afd9ce29618d237e10790b Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 22:52:31 +0100 Subject: [PATCH 40/80] Added parsing errors to game database --- Templates/empty.tadb.json | 6 ++++-- Templates/new_project.json | 18 ++++++++++-------- editor/editor.html | 18 ++++++++++-------- editor/tba_editor.js | 8 ++++---- lonesurvivor.tadb.json | 4 +++- textAdventure.js | 7 +++---- textAdventureDatabase.schema.json | 10 ++++++++-- 7 files changed, 42 insertions(+), 29 deletions(-) diff --git a/Templates/empty.tadb.json b/Templates/empty.tadb.json index dc6391f..37b526b 100644 --- a/Templates/empty.tadb.json +++ b/Templates/empty.tadb.json @@ -9,9 +9,11 @@ "start": { "text": ["Welcome to the Empty Template"], "inventory": "", - "action": ["gotoLocation first_room"] + "action": [] }, - "ignored_words": [] + "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": {}, diff --git a/Templates/new_project.json b/Templates/new_project.json index c06a923..57ab6db 100644 --- a/Templates/new_project.json +++ b/Templates/new_project.json @@ -13,10 +13,10 @@ "Welcome to the textAdventureJS Mini Example" ], "action": [ - "gotoLocation template_room" + "gotoLocation first_room" ] }, - "ignored_words": [ + "parser_ignored_words": [ "to", "through", "on", @@ -24,7 +24,9 @@ "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": { @@ -122,8 +124,8 @@ "objects": { "template_object": { "words": [ - "pillow", - "pill" + "object", + "obj" ], "locationDescription": "An object is lying on the floor.", "actions": { @@ -147,10 +149,10 @@ }, "template_object_pickedUp": { "words": [ - "pillow", - "pill" + "object", + "obj" ], - "locationDescription": "You are holding pillow in your hand.", + "locationDescription": "An object is lying on the floor.", "actions": { "drop": { "text": [ diff --git a/editor/editor.html b/editor/editor.html index 47d0015..7a1ad13 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -51,10 +51,10 @@ "Welcome to the textAdventureJS Mini Example" ], "action": [ - "gotoLocation template_room" + "gotoLocation first_room" ] }, - "ignored_words": [ + "parser_ignored_words": [ "to", "through", "on", @@ -62,7 +62,9 @@ "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": { @@ -160,8 +162,8 @@ "objects": { "template_object": { "words": [ - "pillow", - "pill" + "object", + "obj" ], "locationDescription": "An object is lying on the floor.", "actions": { @@ -185,10 +187,10 @@ }, "template_object_pickedUp": { "words": [ - "pillow", - "pill" + "object", + "obj" ], - "locationDescription": "You are holding pillow in your hand.", + "locationDescription": "An object is lying on the floor.", "actions": { "drop": { "text": [ diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 31f4f85..9ad16a1 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -385,12 +385,12 @@ function generateUiForGeneral(general) { table.append(generateInput("Version", general.version, function(value){ general.version = value; })); table.append(tableH3('Game Settings')); table.append(generateTextArea("Request", general.request.join(NEWLINE), function(value){ general.request = value.split(NEWLINE); })); - table.append(generateInput("Parser Ignored Words", general.ignored_words.join(", "), function(value){ general.ignored_words = value.split(",").map(function(item) { return item.trim(); }); })); + table.append(generateInput("Parser Ignored Words", general.parser_ignored_words.join(", "), function(value){ general.parser_ignored_words = value.split(",").map(function(item) { return item.trim(); }); })); + table.append(generateInput("Parser Unknown Verb", general.parser_unknown_verb_text, function(value){ general.parser_unknown_verb_text = value; })); + table.append(generateInput("Parser Error Text", general.parser_error_text, function(value){ general.parser_error_text = value; })); table.append(tableH3('Game Start')); table.append(generateTextArea("Introduction", general.start.text.join(NEWLINE), function(value){ general.start.text = value.split(NEWLINE); })); - table.append(generateTextArea("Functions", general.start.action.join(NEWLINE), function(value){ - general.start.action = value.split(NEWLINE).map(function(item) { return item.trim(); }).filter(e => e); - })); + table.append(generateFunctionsUI(general.start.action)); return editorGui; } diff --git a/lonesurvivor.tadb.json b/lonesurvivor.tadb.json index 796254f..6631970 100644 --- a/lonesurvivor.tadb.json +++ b/lonesurvivor.tadb.json @@ -9,7 +9,9 @@ "text": [ "", "", "", "You wake up with a headache..." ], "action": [ "gotoLocation start_chamber" ] }, - "ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ] + "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": { "pickup": { diff --git a/textAdventure.js b/textAdventure.js index ce74271..647b1c3 100644 --- a/textAdventure.js +++ b/textAdventure.js @@ -89,7 +89,7 @@ class textAdventureEngine { cmd = cmd.toLowerCase(); // remove ignored words from command - cmd = this.#removeFromString(this.#database.general.ignored_words, cmd); + cmd = this.#removeFromString(this.#database.general.parser_ignored_words, cmd); cmd = cmd.trim(); console.log("Stripped command of parser: '"+cmd+"'"); @@ -133,8 +133,7 @@ class textAdventureEngine { //no action if(verb == undefined && object != undefined){ - this.#writeOutputLines("Unknown verb, please try to rephrase your command."); //TODO: Move to Game Database - this.#showRequest(); + this.#writeOutputLines(this.#database.general.parser_unknown_verb_text); return; } @@ -175,7 +174,7 @@ class textAdventureEngine { this.#showRequest(); return; } - this.#writeOutputLines("Please try to rephrase your command."); //TODO: Move to Game Database + this.#writeOutputLines(this.#database.general.parser_error_text); } this.#showRequest(); } diff --git a/textAdventureDatabase.schema.json b/textAdventureDatabase.schema.json index 7e9a552..342b7a0 100644 --- a/textAdventureDatabase.schema.json +++ b/textAdventureDatabase.schema.json @@ -58,14 +58,20 @@ "$ref": "#/definitions/action_definition" } }, - "ignored_words": { + "parser_parser_ignored_words": { "description": "Words that will be ignored when parsing an user input. This prevent that they get interpreted as verbs or objects (Note: Thus objects and names can't have this as on of their 'words')", "type": "array", "items": { "type": "string" } }, - "required": ["title", "author", "version", "request", "start", "ignored_words"] + "parser_error_text": { + "type": "string" + }, + "parser_unknown_verb_text": { + "type": "string" + }, + "required": ["title", "author", "version", "request", "start", "parser_ignored_words", "parser_error_text", "parser_unknown_verb_text"] }, "verbs": { "description": "List of verbs that are available throughout the game", From 5468cfcca734ba9c572c3d3685209715e3d41be7 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 23:35:29 +0100 Subject: [PATCH 41/80] Improved Delete and Remove wording --- editor/tba_editor.js | 83 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 9ad16a1..46c7a9a 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -401,10 +401,26 @@ function generateUiForVerbElement(verbName, verb) { let nameOptions = $(''); - let removeButton = button('Remove', 'btn-error'); + let removeButton = button('Delete', 'btn-error'); nameOptions.append(''+verbName+''); nameOptions.append(' '); - removeButton.click(function() { delete TBA_DATABASE.verbs[verbName]; onTypeChanged(); }); //TODO: Also delete from all Objects + removeButton.click(function() { + if (!TBA_DATABASE.verbs || Object.keys(TBA_DATABASE.verbs).length <= 1) { + alert('Cannot remove the only verb.'); + return; + } + if(confirm('Delete verb "'+verbName+' and also all usages"?')) { + delete TBA_DATABASE.verbs[verbName]; + $.each(TBA_DATABASE.objects, function(objectName, object) { + $.each(object.actions, function(action_name, action) { + if(action_name === verbName) { + delete TBA_DATABASE.objects[objectName].actions[action_name]; + } + }); + }); + onTypeChanged(); + } + }); nameOptions.append(removeButton); nameOptions.append(' '); let duplicateButton = button('Duplicate'); @@ -427,10 +443,41 @@ function generateUiForObjectElement(objectName, object) { let title = $('

        Object

        '); let nameOptions = $(''); - let removeButton = button('Remove', 'btn-error'); + let removeButton = button('Delete', 'btn-error'); nameOptions.append(''+objectName+''); nameOptions.append(' '); - removeButton.click(function() { delete TBA_DATABASE.objects[objectName]; onTypeChanged(); }); //TODO: Also delete from all locations + removeButton.click(function() { + if (!TBA_DATABASE.objects || Object.keys(TBA_DATABASE.objects).length <= 1) { + alert('Cannot remove the only object.'); + return; + } + if(confirm('Delete object "'+objectName+' and also all usages"?')) { + delete TBA_DATABASE.objects[objectName]; + // delete object from all locations + $.each(TBA_DATABASE.locations, function( locationName, location ) { + let index = location.objects.indexOf(objectName); + if(index !== -1){ + TBA_DATABASE.locations[locationName].objects.splice(index, 1); + } + }); + // delete all actions that reference this object + $.each(TBA_DATABASE.general.start.action, function(index, action) { + if (action && action.includes(objectName)) { + TBA_DATABASE.general.start.action.splice(index, 1); + } + }); + $.each(TBA_DATABASE.objects, function(dbObjectName, object) { + $.each(object.actions, function(action_name, action_info) { + $.each(action_info.action, function(index, action_string) { + if (action_string && action_string.includes(objectName)) { + TBA_DATABASE.objects[dbObjectName].actions[action_name].action.splice(index, 1); + } + }); + }); + }); + onTypeChanged(); + } + }); nameOptions.append(removeButton); nameOptions.append(' '); let duplicateButton = button('Duplicate'); @@ -471,10 +518,34 @@ function generateUiForLocationElement(locationName, location) { let title = $('

        Location

        '); let nameOptions = $(''); - let removeButton = button('Remove', 'btn-error'); + let removeButton = button('Delete', 'btn-error'); nameOptions.append(''+locationName+''); nameOptions.append(' '); - removeButton.click(function() { delete TBA_DATABASE.locations[locationName]; onTypeChanged(); }); + removeButton.click(function() { + if (!TBA_DATABASE.locations || Object.keys(TBA_DATABASE.locations).length <= 1) { + alert('Cannot remove the only location.'); + return; + } + if(confirm('Delete location "'+locationName+' and also all usages"?')) { + delete TBA_DATABASE.locations[locationName]; + // delete all actions that reference this location + $.each(TBA_DATABASE.general.start.action, function(index, action) { + if (action && action.includes(locationName)) { + TBA_DATABASE.general.start.action.splice(index, 1); + } + }); + $.each(TBA_DATABASE.objects, function(objectName, object) { + $.each(object.actions, function(action_name, action_info) { + $.each(action_info.action, function(index, action_string) { + if (action_string && action_string.includes(locationName)) { + TBA_DATABASE.objects[objectName].actions[action_name].action.splice(index, 1); + } + }); + }); + }); + onTypeChanged(); + } + }); nameOptions.append(removeButton); nameOptions.append(' '); let duplicateButton = button('Duplicate'); From 891385f7518b4be73057430171bcddc48b6d819f Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 23:38:47 +0100 Subject: [PATCH 42/80] Improved new element placeholder --- editor/tba_editor.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 46c7a9a..64de088 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -197,7 +197,7 @@ function onTypeChanged(typeParam){ var newArea = $('
        '); $("#elementSelection").append(newArea); if(type==="verbs") { - newArea.append(generateNewButton(function(name){ + newArea.append(generateNewButton("Verb", function(name){ if(TBA_DATABASE.verbs[name]!==undefined){ alert("A verb with this name already exists."); return; @@ -207,7 +207,7 @@ function onTypeChanged(typeParam){ onTypeChanged(); })); }else if(type==="objects"){ - newArea.append(generateNewButton(function(name){ + newArea.append(generateNewButton("Object", function(name){ if(TBA_DATABASE.objects[name]!==undefined){ alert("An object with this name already exists."); return; @@ -216,7 +216,7 @@ function onTypeChanged(typeParam){ onTypeChanged(); })); }else if(type==="locations"){ - newArea.append(generateNewButton(function(name){ + newArea.append(generateNewButton("Location", function(name){ if(TBA_DATABASE.locations[name]!==undefined){ alert("A location with this name already exists."); return; @@ -706,9 +706,9 @@ function getAvailableVerbName(verbName) { return testName; } -function generateNewButton(onClick) { +function generateNewButton(name, onClick) { let editorGui = $('
        '); - let elementNameInput = $(''); + let elementNameInput = $(''); let addButton = button('Add'); addButton.click(function() { From cc6662f27807ca9d47541ce3f0e2fef5539121fd Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 23:48:45 +0100 Subject: [PATCH 43/80] Added option to edit objects form location screen --- editor/editor-style.css | 7 +++++++ editor/tba_editor.js | 38 ++++++++++++++++++++++++++++---------- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/editor/editor-style.css b/editor/editor-style.css index f9b006f..0194b03 100644 --- a/editor/editor-style.css +++ b/editor/editor-style.css @@ -209,6 +209,13 @@ html { padding:6px 8px; } + /* Ensure selected option is clearly highlighted even when select is not focused */ + #elementSelection select option:checked, + #elementSelection select option[selected] { + background: var(--primary-color); + color: #fff; + } + select::-ms-expand { display: none; } .modal-action-row { padding:8px 0; border-bottom:1px solid rgba(255,255,255,0.03); } diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 64de088..fed1766 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -583,7 +583,7 @@ function generateUiForLocationElement(locationName, location) { tr.append($('
'); - const col1 = $(''); + const col1 = $(''); const col2 = $('
(no functions)
'); + const span = $('').text(actionString); + tdText.append(span); + const tdBtns = $(''); + const btnGroup = $('
'); + + const moveUpButton = button('▲', 'btn-default small-btn'); + moveUpButton.attr('title', 'Move Up').attr('aria-label', 'Move up'); + moveUpButton.click(function() { + if (index > 0) { + moveArrayElement(actions, index, index - 1); + onElementChanged(); + } + }); + if (index === 0) { moveUpButton.prop('disabled', true); } + + const moveDownButton = button('▼', 'btn-default small-btn'); + moveDownButton.attr('title', 'Move Down').attr('aria-label', 'Move down'); + moveDownButton.click(function() { + if (index < actions.length - 1) { + moveArrayElement(actions, index, index + 1); + onElementChanged(); + } + }); + if (index === actions.length - 1) { moveDownButton.prop('disabled', true); } + + const removeButton = button('✖', 'btn-error btn-ghost small-btn'); + removeButton.attr('title','Remove').attr('aria-label','Remove'); + removeButton.click(function() { + if (confirm('Remove "'+actionString+'"?')) { + actions.splice(index, 1); + onElementChanged(); + } + }); + + btnGroup.append(moveUpButton); + btnGroup.append(moveDownButton); + btnGroup.append(removeButton); + tdBtns.append(btnGroup); + + tr.append(tdText); + tr.append(tdBtns); + existingFunctionsTable.append(tr); + }); + } + col2.append(existingFunctionsTable); + + const container = $('
'); + const paramsContainer = $('
'); + const selectedFunction = $(''); + if(paramName === "location") { + $.each(TBA_DATABASE.locations, function( locName, loc ) { + parameter.append($('
').text(objectName)); let btnsTd = $(''); -let moveUpButton = button('▲', 'btn-default small-btn'); + let moveUpButton = button('▲', 'btn-default small-btn'); moveUpButton.attr('title', 'Move Up').attr('aria-label', 'Move up'); moveUpButton.click(function() { if(index > 0) { @@ -603,8 +603,25 @@ let moveUpButton = button('▲', 'btn-default small-btn'); }); if(index === location.objects.length - 1) { moveDownButton.prop('disabled', true); } + let editObjectButton = button('Edit', 'btn-default small-btn'); + editObjectButton.attr('title','Edit object').attr('aria-label','Edit object'); + editObjectButton.click(function() { + // Switch to Objects tab and select this object + onTypeChanged('objects'); + // Ensure DOM is updated, then select the element, focus it, and scroll into view + setTimeout(function(){ + var sel = $('#element'); + sel.val(objectName); + onElementChanged(); + // Bring the selected option into view and focus the select for accessibility + sel.focus(); + var opt = sel.find('option[value="'+objectName+'"]')[0]; + if(opt && sel[0]) { sel[0].scrollTop = opt.offsetTop - (sel.height() / 2); } + }, 0); + }); + let removeObjectButton = button('✖', 'btn-error btn-ghost small-btn'); - removeObjectButton.attr('title','Remove').attr('aria-label','Remove'); + removeObjectButton.attr('title','Remove').attr('aria-label','Remove'); removeObjectButton.click(function() { if(confirm('Remove "'+objectName+'"?')) { location.objects.splice(index, 1); @@ -612,14 +629,15 @@ let moveUpButton = button('▲', 'btn-default small-btn'); } }); - // Put buttons inline in a small button group - let btnGroup = $('
'); - btnGroup.append(moveUpButton); - btnGroup.append(moveDownButton); - btnGroup.append(removeObjectButton); - btnsTd.append(btnGroup); - tr.append(btnsTd); - objList.append(tr); + // Put buttons inline in a small button group + let btnGroup = $('
'); + btnGroup.append(moveUpButton); + btnGroup.append(moveDownButton); + btnGroup.append(editObjectButton); + btnGroup.append(removeObjectButton); + btnsTd.append(btnGroup); + tr.append(btnsTd); + objList.append(tr); }); leftCellSelector.append(objList); From d134ae9f9ca69ae76b706692bd1346f8751a25df Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Wed, 17 Dec 2025 23:50:04 +0100 Subject: [PATCH 44/80] Changed icon to remove wording for locations --- editor/tba_editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index fed1766..89937a6 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -620,7 +620,7 @@ function generateUiForLocationElement(locationName, location) { }, 0); }); - let removeObjectButton = button('✖', 'btn-error btn-ghost small-btn'); + let removeObjectButton = button('Remove', 'btn-error btn-ghost small-btn'); removeObjectButton.attr('title','Remove').attr('aria-label','Remove'); removeObjectButton.click(function() { if(confirm('Remove "'+objectName+'"?')) { From 519d4705df07ee8465b1059abed544e538125838 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Thu, 18 Dec 2025 00:14:20 +0100 Subject: [PATCH 45/80] Renamed action to commands to reduce ambiguity --- README.md | 6 +-- Templates/empty.tadb.json | 2 +- Templates/new_project.json | 10 ++-- editor/editor.html | 10 ++-- editor/tba_editor.js | 32 ++++++------- lonesurvivor.tadb.json | 76 +++++++++++++++---------------- textAdventure.js | 9 ++-- textAdventureDatabase.schema.json | 4 +- 8 files changed, 75 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index b5b3dde..b0abd33 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ Each object has... - 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) + - 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. @@ -78,8 +78,8 @@ If the user tries to do soemthing with an object and the action is not defined, 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. -### Functions -Functions can be used in actions to modify the current location or the plazers inventory. +### Commands +Commands can be used in actions to modify the current location or the plazers inventory. #### 'this' in function parameters If the function should affect the object that the action is defined on, you can refer to it using `this` instead of its nanme. diff --git a/Templates/empty.tadb.json b/Templates/empty.tadb.json index 37b526b..5f8a362 100644 --- a/Templates/empty.tadb.json +++ b/Templates/empty.tadb.json @@ -9,7 +9,7 @@ "start": { "text": ["Welcome to the Empty Template"], "inventory": "", - "action": [] + "commands": [] }, "parser_ignored_words": [], "parser_error_text": "Sorry, I didn't understand that.", diff --git a/Templates/new_project.json b/Templates/new_project.json index 57ab6db..a7478af 100644 --- a/Templates/new_project.json +++ b/Templates/new_project.json @@ -12,7 +12,7 @@ "text": [ "Welcome to the textAdventureJS Mini Example" ], - "action": [ + "commands": [ "gotoLocation first_room" ] }, @@ -133,7 +133,7 @@ "text": [ "Okay got it." ], - "action": [ + "commands": [ "objectRemoveFromLocation this", "inventoryAdd template_object_pickedUp" ] @@ -142,7 +142,7 @@ "text": [ "A mysterious object." ], - "action": [] + "commands": [] } }, "useableObjects": {} @@ -158,7 +158,7 @@ "text": [ "Okay dropped it." ], - "action": [ + "commands": [ "objectAddToLocation template_object", "inventoryRemove this" ] @@ -167,7 +167,7 @@ "text": [ "A mysterious object." ], - "action": [] + "commands": [] } }, "useableObjects": {} diff --git a/editor/editor.html b/editor/editor.html index 7a1ad13..272441f 100644 --- a/editor/editor.html +++ b/editor/editor.html @@ -50,7 +50,7 @@ "text": [ "Welcome to the textAdventureJS Mini Example" ], - "action": [ + "commands": [ "gotoLocation first_room" ] }, @@ -171,7 +171,7 @@ "text": [ "Okay got it." ], - "action": [ + "commands": [ "objectRemoveFromLocation this", "inventoryAdd template_object_pickedUp" ] @@ -180,7 +180,7 @@ "text": [ "A mysterious object." ], - "action": [] + "commands": [] } }, "useableObjects": {} @@ -196,7 +196,7 @@ "text": [ "Okay dropped it." ], - "action": [ + "commands": [ "objectAddToLocation template_object", "inventoryRemove this" ] @@ -205,7 +205,7 @@ "text": [ "A mysterious object." ], - "action": [] + "commands": [] } }, "useableObjects": {} diff --git a/editor/tba_editor.js b/editor/tba_editor.js index 89937a6..f14ce51 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -390,7 +390,7 @@ function generateUiForGeneral(general) { table.append(generateInput("Parser Error Text", general.parser_error_text, function(value){ general.parser_error_text = value; })); table.append(tableH3('Game Start')); table.append(generateTextArea("Introduction", general.start.text.join(NEWLINE), function(value){ general.start.text = value.split(NEWLINE); })); - table.append(generateFunctionsUI(general.start.action)); + table.append(generateFunctionsUI(general.start.commands)); return editorGui; } @@ -461,16 +461,16 @@ function generateUiForObjectElement(objectName, object) { } }); // delete all actions that reference this object - $.each(TBA_DATABASE.general.start.action, function(index, action) { - if (action && action.includes(objectName)) { - TBA_DATABASE.general.start.action.splice(index, 1); + $.each(TBA_DATABASE.general.start.commands, function(index, call) { + if (call.includes(objectName)) { + TBA_DATABASE.general.start.commands.splice(index, 1); } }); $.each(TBA_DATABASE.objects, function(dbObjectName, object) { $.each(object.actions, function(action_name, action_info) { - $.each(action_info.action, function(index, action_string) { - if (action_string && action_string.includes(objectName)) { - TBA_DATABASE.objects[dbObjectName].actions[action_name].action.splice(index, 1); + $.each(action_info.commands, function(index, call) { + if (call.includes(objectName)) { + TBA_DATABASE.objects[dbObjectName].actions[action_name].commands.splice(index, 1); } }); }); @@ -498,7 +498,7 @@ function generateUiForObjectElement(objectName, object) { removeActionButton.click(function() { delete object.actions[verb]; onElementChanged(); }); editorGui.append(tableRow2(name, removeActionButton)); editorGui.append(generateTextArea("Text", action.text.join(NEWLINE), function(value){ action.text = value.split(NEWLINE); })); - editorGui.append(generateFunctionsUI(action.action)); + editorGui.append(generateFunctionsUI(action.commands)); }); editorGui.append(tableRow2("

Add Action

", generateNewActionButton(object.actions, function(verb){ if(object.actions[name]!==undefined){ @@ -529,16 +529,16 @@ function generateUiForLocationElement(locationName, location) { if(confirm('Delete location "'+locationName+' and also all usages"?')) { delete TBA_DATABASE.locations[locationName]; // delete all actions that reference this location - $.each(TBA_DATABASE.general.start.action, function(index, action) { - if (action && action.includes(locationName)) { - TBA_DATABASE.general.start.action.splice(index, 1); + $.each(TBA_DATABASE.general.start.commands, function(index, call) { + if (call.includes(locationName)) { + TBA_DATABASE.general.start.commands.splice(index, 1); } }); $.each(TBA_DATABASE.objects, function(objectName, object) { $.each(object.actions, function(action_name, action_info) { - $.each(action_info.action, function(index, action_string) { - if (action_string && action_string.includes(locationName)) { - TBA_DATABASE.objects[objectName].actions[action_name].action.splice(index, 1); + $.each(action_info.commands, function(index, call) { + if (call.includes(locationName)) { + TBA_DATABASE.objects[objectName].actions[action_name].commands.splice(index, 1); } }); }); @@ -776,7 +776,7 @@ function generateNewObjectForLocationButton(existingObjects, onClick) { function generateFunctionsUI(actions) { const editorGui = $('
FunctionsCommands'); editorGui.append(col1); editorGui.append(col2); @@ -945,7 +945,7 @@ function getNewObject(name){ function getNewObjectAction(){ var newAction = {}; newAction["text"] = "That worked!"; - newAction["action"] = []; + newAction["commands"] = []; return newAction; } diff --git a/lonesurvivor.tadb.json b/lonesurvivor.tadb.json index 6631970..1ac0d23 100644 --- a/lonesurvivor.tadb.json +++ b/lonesurvivor.tadb.json @@ -7,7 +7,7 @@ "request": [ "", "What do you do?" ], "start": { "text": [ "", "", "", "You wake up with a headache..." ], - "action": [ "gotoLocation start_chamber" ] + "commands": [ "gotoLocation start_chamber" ] }, "parser_ignored_words": [ "to", "through", "on", "off", "from", "around", "at" ], "parser_error_text": "Sorry, I didn't understand that.", @@ -71,21 +71,21 @@ "actions": { "pickup": { "text": [ "okay got it" ], - "action": [ "inventoryAdd template_object" ] + "commands": [ "inventoryAdd template_object" ] }, "look": { "text": [ "soft and comfy" ], - "action": [] + "commands": [] } }, "useableObjects": { "bedroom_desk": { "text": [ "soft and comfy" ], - "action": [] + "commands": [] }, "test": { "text": [ "works" ], - "action": [] + "commands": [] } } }, @@ -95,15 +95,15 @@ "actions": { "look": { "text": [ "Plaster is crumbling from the walls. Something seems off, but it's too dark to have a closer look." ], - "action": [] + "commands": [] }, "touch": { "text": [ "The plaster feels wet and is crumbling in your hands as you touch it." ], - "action": [] + "commands": [] }, "break": { "text": [ "Why would you do that?" ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -114,11 +114,11 @@ "actions": { "look": { "text": [ "You notice some rusty metal emerging behind the crumbling PLASTER of one wall." ], - "action": [] + "commands": [] }, "remove": { "text": [ "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR." ], - "action": [ + "commands": [ "objectReplaceInLocation plaster_wall_door_unidentified plaster_wall_door_door_found", "objectRemoveFromLocation metal_behind_plaster" ] @@ -132,15 +132,15 @@ "actions": { "look": { "text": [ "A heavy metal door that was hidden under the plaster." ], - "action": [] + "commands": [] }, "go": { "text": [ "You open the rusty door and enter a hallway." ], - "action": [ "gotoLocation long_hallway" ] + "commands": [ "gotoLocation long_hallway" ] }, "open": { "text": [ "You open the rusty door and enter a hallway." ], - "action": [ "gotoLocation long_hallway" ] + "commands": [ "gotoLocation long_hallway" ] } }, "useableObjects": { } @@ -151,15 +151,15 @@ "actions": { "look": { "text": [ "It looks like a rusty metal object is hidden behind the crumbling plaster." ], - "action": [] + "commands": [] }, "touch": { "text": [ "The plaster feels loose, you might be able to remove it with your hands." ], - "action": [] + "commands": [] }, "remove": { "text": [ "You break the loose plaster of the wall. Piece by piece it reveals an old RUSTY METAL DOOR." ], - "action": [ + "commands": [ "objectReplaceInLocation plaster_wall_door_door_visible plaster_wall_door_door_found", "objectRemoveFromLocation metal_behind_plaster" ] @@ -175,17 +175,17 @@ "text": [ "You wake up with a headache." ], - "action": [] + "commands": [] }, "look": { "text": [ "You look around..." ], - "action": [ "showLocationDescription" ] + "commands": [ "showLocationDescription" ] }, "light": { "text": [ "If only you'd had something to enlighten the room with..." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -198,11 +198,11 @@ "text": [ "You look at each wall..." ], - "action": [ "showLocationDescription" ] + "commands": [ "showLocationDescription" ] }, "light": { "text": [ "The room is already slightly illuminated." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -215,14 +215,14 @@ "actions": { "pickup": { "text": [ "You got it. It's a box of matches!" ], - "action": [ + "commands": [ "objectRemoveFromLocation box_matches_unidentified", "inventoryAdd box_matches_pickedUp" ] }, "look": { "text": [ "It's too dark to see the small box properly. You could probably reach it." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -233,7 +233,7 @@ "actions": { "use": { "text": [ "You light the last match. The room is now slightly illumanted." ], - "action": [ + "commands": [ "objectReplaceInLocation plaster_wall_door_unidentified plaster_wall_door_door_visible", "objectReplaceInLocation room_start_chamber_dark room_start_chamber_enlighted", "objectAddToLocation metal_behind_plaster", @@ -242,7 +242,7 @@ }, "light": { "text": [ "You light the last match. The room is now slightly illumanted." ], - "action": [ + "commands": [ "objectReplaceInLocation plaster_wall_door_unidentified plaster_wall_door_door_visible", "objectReplaceInLocation room_start_chamber_dark room_start_chamber_enlighted", "objectAddToLocation metal_behind_plaster", @@ -251,14 +251,14 @@ }, "drop": { "text": [ "You dropped the box of matches" ], - "action": [ + "commands": [ "objectAddToLocation box_matches_dropped", "inventoryRemove box_matches_pickedUp" ] }, "look": { "text": [ "An almost empty box of matches." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -269,14 +269,14 @@ "actions": { "pickup": { "text": [ "You picked up the Box of Matches again!" ], - "action": [ + "commands": [ "objectRemoveFromLocation box_matches_dropped", "inventoryAdd box_matches_pickedUp" ] }, "look": { "text": [ "A small box of matches, that you dropped here..." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -287,7 +287,7 @@ "actions": { "look": { "text": [ "" ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -298,11 +298,11 @@ "actions": { "look": { "text": [ "It seems to be sunlight that enlightens the end of the hallway." ], - "action": [] + "commands": [] }, "go": { "text": [ "You walk towards the light, but you don't seem to get any closer. A gust of wind blows the LEAFLET to you." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -313,11 +313,11 @@ "actions": { "look": { "text": [ "It seems to be sunlight that enlightens the end of the hallway." ], - "action": [] + "commands": [] }, "go": { "text": [ "You walk towards the light, but you don't seem to get any closer." ], - "action": [] + "commands": [] } }, "useableObjects": { } @@ -328,11 +328,11 @@ "actions": { "look": { "text": [ "The text is too small to read the LEAFLET, while it's on the ground." ], - "action": [] + "commands": [] }, "pickup": { "text": [ "You take the leaflet." ], - "action": [ + "commands": [ "objectReplaceInLocation exit_light exit_light_without_leaflet", "objectRemoveFromLocation dev_leaflet_on_ground", "inventoryAdd dev_leaflet_pickedUp" @@ -350,11 +350,11 @@ "\"Dear Player,", "Wow, you actually played this :-) I'm afraid your adventure ends here, already. This Text Based Adventure Engine was just a quick project on a rainy weekend. I hope you liked it, feel free to contact me if you did. -Daniel.\"" ], - "action": [] + "commands": [] }, "drop": { "text": [ "You dropped the leaflet." ], - "action": [ + "commands": [ "objectReplaceInLocation exit_light_without_leaflet exit_light", "objectAddToLocation dev_leaflet_on_ground", "inventoryRemove dev_leaflet_pickedUp" diff --git a/textAdventure.js b/textAdventure.js index 647b1c3..0d9ef81 100644 --- a/textAdventure.js +++ b/textAdventure.js @@ -66,9 +66,10 @@ class textAdventureEngine { } if(showGameName){ this.outputClear(); - this.#writeOutputLines(["", "", + this.#writeOutputLines([ "'"+this.#database.general.title+"' by "+this.#database.general.author, - "Version: "+this.#database.general.version]); + "Version: "+this.#database.general.version, + ""]); }else{ this.outputClear(); } @@ -98,7 +99,7 @@ class textAdventureEngine { if(this.#database.general.start.text.length > 0){ this.#writeOutputLines(this.#database.general.start.text); } - this.#runActions(undefined, this.#database.general.start.action); + this.#runActions(undefined, this.#database.general.start.commands); }else if(cmd == "debug"){ if(this.TBA_DEBUG==true){ this.TBA_DEBUG = true; @@ -167,7 +168,7 @@ class textAdventureEngine { if(result != undefined){ let objectVerbAction = object.actions[verbName]; this.#writeOutputLines(objectVerbAction.text); - this.#runActions(objectName, objectVerbAction.action); + this.#runActions(objectName, objectVerbAction.commands); }else{ this.#writeOutputLines(verb.failure); } diff --git a/textAdventureDatabase.schema.json b/textAdventureDatabase.schema.json index 342b7a0..8d07bb0 100644 --- a/textAdventureDatabase.schema.json +++ b/textAdventureDatabase.schema.json @@ -7,7 +7,7 @@ "action_definition": { "description": "Defines what happens if a verb is used (with this object / in this location)", "type": "object", - "required": ["text", "action"], + "required": ["text", "commands"], "properties": { "text": { "type": "array", @@ -16,7 +16,7 @@ "type": "string" } }, - "action": { + "commands": { "type": "array", "items": { "type": "string" From 85883d6940a419db9cad217a301fab09a1a1cfd8 Mon Sep 17 00:00:00 2001 From: Daniel Korgel Date: Thu, 18 Dec 2025 00:27:39 +0100 Subject: [PATCH 46/80] Fixed let usages --- editor/tba_editor.js | 152 ++++++++++++++++++++++--------------------- 1 file changed, 78 insertions(+), 74 deletions(-) diff --git a/editor/tba_editor.js b/editor/tba_editor.js index f14ce51..9836f99 100644 --- a/editor/tba_editor.js +++ b/editor/tba_editor.js @@ -183,7 +183,7 @@ function onTypeChanged(typeParam){ // Highlight the active tab $('.editor-tab').removeClass('active'); - let tabId = 'tab' + type.charAt(0).toUpperCase() + type.slice(1); + const tabId = 'tab' + type.charAt(0).toUpperCase() + type.slice(1); $('#' + tabId).addClass('active'); $("#elementSelection").html(""); @@ -202,7 +202,7 @@ function onTypeChanged(typeParam){ alert("A verb with this name already exists."); return; } - let newVerb = getNewVerb(name); + const newVerb = getNewVerb(name); TBA_DATABASE.verbs[name]=newVerb; onTypeChanged(); })); @@ -226,7 +226,7 @@ function onTypeChanged(typeParam){ })); } - let elementSelector = $(''); + const elementSelector = $(''); $.each( TBA_DATABASE[type], function( key, val ) { elementSelector.append($('')); }); @@ -241,7 +241,10 @@ function onElementChanged(){ onDatabaseChanged(); let gui = undefined; let element = $('#element').val(); - if(element===null){ element=$("#element option:first").val(); $('#element').val(element);} + if(element===null){ + element = $("#element option:first").val(); + $('#element').val(element); + } if(type=="verbs"){ gui = generateUiForVerbElement(element, TBA_DATABASE.verbs[element]); @@ -266,7 +269,7 @@ function generateUiForPreview() { previewInputText = $(''); previewInputButton = $(''); - let buttonBar = $('

'); + const buttonBar = $('

'); previewRestartButton = button('Restart Game'); previewReloadButton = button('Reset Current Room'); buttonBar.append(previewReloadButton); @@ -328,7 +331,7 @@ function clearArea(){ function readUserInput(){ previewInputButton.prop("disabled",true); previewInputText.prop('readonly', true); - let input = previewInputText.val(); + const input = previewInputText.val(); witeLine("> "+input); textAdv.input(input); previewInputText.val(""); @@ -336,9 +339,9 @@ function readUserInput(){ } function updatePreviewSideBar() { - let gameState = textAdv.devGetGameState(); + const gameState = textAdv.devGetGameState(); $("#elementSelection").html(""); - let inventoryList = $('