From 3274b700a6f655b8ecc3505e814ac5d782ae6ffe Mon Sep 17 00:00:00 2001
From: historia <[not public]>
Date: Mon, 13 Jul 2026 16:10:40 -0400
Subject: feat(admin): reminder text for color tags and item variables, improve
placeholder text
---
internal/admin/static/cardeditor.js | 37 +++++++++++++++++++++++++++++------
internal/admin/static/dropeditor.js | 4 ++--
internal/admin/static/hazardeditor.js | 5 ++++-
internal/admin/static/itemeditor.js | 23 +++++++++++++---------
internal/admin/static/map.js | 6 +++---
internal/admin/static/mobeditor.js | 11 ++++++++---
internal/admin/static/moduleeditor.js | 2 +-
internal/admin/static/objecteditor.js | 33 +++++++++++++++++++------------
internal/admin/static/talktree.js | 2 +-
9 files changed, 84 insertions(+), 39 deletions(-)
(limited to 'internal/admin/static')
diff --git a/internal/admin/static/cardeditor.js b/internal/admin/static/cardeditor.js
index f32ea7e..6a8cda7 100644
--- a/internal/admin/static/cardeditor.js
+++ b/internal/admin/static/cardeditor.js
@@ -42,7 +42,7 @@ function ced_collectFieldValue(el, type) {
if (type === 'checkbox') return el.checked;
if (type === 'select') return el.value;
if (type === 'search') return el.value;
- if (type === 'number') { var n = parseFloat(el.value); return isNaN(n) ? 0 : n; }
+ if (type === 'number') { var n = parseFloat(el.value); return isNaN(n) ? '' : n; }
if (type === 'json') {
var raw = el.value.trim();
if (!raw) return null;
@@ -86,7 +86,7 @@ function ced_addKVRow(cardID, subKey) {
if (!el) return;
var row = document.createElement('div');
row.className = 'obj-kv-row';
- row.innerHTML = 'X ';
+ row.innerHTML = 'X ';
el.appendChild(row);
}
@@ -125,7 +125,7 @@ function ced_addKVSearchRow(cardID, subKey, entity) {
if (!el) return;
var row = document.createElement('div');
row.className = 'obj-kv-row';
- row.innerHTML = '
X ';
+ row.innerHTML = 'X ';
el.appendChild(row);
ced_setupSearchFields(row);
}
@@ -398,7 +398,7 @@ function ced_addSubRow(sec, subKey, dataRef, cardPathFn) {
var st = (sec.subtables || []).find(function(s) { return s.key === subKey; });
if (st) {
st.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
}
arr.push(empty);
@@ -579,8 +579,18 @@ function ced_cleanOutput(obj) {
} else if (typeof val === 'object' && val !== null && !Array.isArray(val)) {
ced_cleanOutput(val);
if (Object.keys(val).length === 0) delete obj[key];
- } else if (Array.isArray(val) && val.length === 0) {
- delete obj[key];
+ } else if (Array.isArray(val)) {
+ if (val.length === 0) {
+ delete obj[key];
+ } else {
+ for (var i = val.length - 1; i >= 0; i--) {
+ if (typeof val[i] === 'object' && val[i] !== null) {
+ ced_cleanOutput(val[i]);
+ if (Object.keys(val[i]).length === 0) val.splice(i, 1);
+ }
+ }
+ if (val.length === 0) delete obj[key];
+ }
}
}
}
@@ -658,3 +668,18 @@ function ced_collectAtkType(widgetID) {
if (sci && sci.checked) out.push('science');
return out;
}
+
+function ced_renderTagHelp(type) {
+ var h = '';
+ if (type === 'color') {
+ h += 'Name is displayed without an article (e.g. "John Smith" instead of "a John Smith") ';
+ h += 'Cannot be attacked by players. Combat level hidden ';
+ h += 'Text fields support color tags: {NN}text{/} where NN is a hex color index (00–FF).';
+ } else if (type === 'crafting') {
+ h += 'Message fields support template variables: %i1 = first ingredient name %i2 = second ingredient name %n = output item name. Color tags are also supported: {NN}text{/} where NN is a hex color index (00–FF).';
+ } else if (type === 'gather') {
+ h += 'Message fields support template variables: {name} = object name. Color tags are also supported: {NN}text{/} where NN is a hex color index (00–FF).';
+ }
+ h += '
';
+ return h;
+}
diff --git a/internal/admin/static/dropeditor.js b/internal/admin/static/dropeditor.js
index ac1df97..5900930 100644
--- a/internal/admin/static/dropeditor.js
+++ b/internal/admin/static/dropeditor.js
@@ -7,8 +7,8 @@ var DROP_SECTIONS = [
{
id: 'drops', label: 'Drops', always: true, path: 'drops', isArray: true,
fields: [
- ['item_id', 'Item ID', 'search', 'e.g. copper_ore', '', null, 'items'],
- ['table', 'Table', 'search', 'e.g. gem_table', '', null, 'drops'],
+ ['item_id', 'Item ID', 'search', 'copper_ore', '', null, 'items'],
+ ['table', 'Table', 'search', 'gem_table', '', null, 'drops'],
['weight', 'Weight', 'number', '10', 'narrow'],
['quantity', 'Quantity', 'number', '1', 'narrow'],
]
diff --git a/internal/admin/static/hazardeditor.js b/internal/admin/static/hazardeditor.js
index 89586ac..1f5fdf3 100644
--- a/internal/admin/static/hazardeditor.js
+++ b/internal/admin/static/hazardeditor.js
@@ -13,7 +13,7 @@ var HAZARD_SECTIONS = [
['warn_message', 'Warn Message', 'text', 'The air grows thick with toxic fumes...', 'wide'],
['hit_message', 'Hit Message', 'text', 'You cough and choke on the toxic gas!'],
['miss_message', 'Miss Message', 'text', 'You hold your breath and avoid the fumes.'],
- ['required_item', 'Required Item', 'search', 'e.g. gas_mask', '', null, 'items'],
+ ['required_item', 'Required Item', 'search', 'gas_mask', '', null, 'items'],
]
},
{
@@ -146,6 +146,9 @@ function renderCard(sec, data) {
h += renderField(sec, f, data, -1);
});
h += '';
+ if (sec.id === 'core') {
+ h += ced_renderTagHelp('color');
+ }
}
h += '';
}
diff --git a/internal/admin/static/itemeditor.js b/internal/admin/static/itemeditor.js
index d48d70e..6375c16 100644
--- a/internal/admin/static/itemeditor.js
+++ b/internal/admin/static/itemeditor.js
@@ -55,14 +55,14 @@ var SECTIONS = [
['output_qty', 'Output Qty', 'number', '', 'narrow'],
['station', 'Station', 'select', 'dyn:stations'],
['tool', 'Tool', 'select', 'dyn:tools'],
- ['fail', 'Fail Item', 'search', 'e.g. burnt_fish', '', null, 'items'],
+ ['fail', 'Fail Item', 'search', 'burnt_fish', '', null, 'items'],
['success_base', 'Base', 'number', '0.5', 'narrow'],
['success_per_level', 'Per Lvl', 'number', '0.01', 'narrow'],
['success_cap', 'Cap', 'number', '0.95', 'narrow'],
- ['start_message', 'Start Message', 'text', 'e.g. You begin smithing %i1.', 'wide'],
- ['success_message', 'Success Message', 'text', 'e.g. You smith a %n.', 'wide'],
- ['fail_message', 'Fail Message', 'text', 'e.g. You accidentally burn the %i1.', 'wide', function(item) { return item.type === 'cooking' || item.subtype === 'smelt'; }],
- ['end_message', 'End Message', 'text', 'e.g. You\'ve finished smithing.', 'wide'],
+ ['start_message', 'Start Message', 'text', 'You begin smithing %i1.', 'wide'],
+ ['success_message', 'Success Message', 'text', 'You smith a %n.', 'wide'],
+ ['fail_message', 'Fail Message', 'text', 'You accidentally burn the %i1.', 'wide', function(item) { return item.type === 'cooking' || item.subtype === 'smelt'; }],
+ ['end_message', 'End Message', 'text', 'You\'ve finished smithing.', 'wide'],
],
fieldGroups: [
['type', 'subtype', 'level', 'xp', 'ticks_per_cycle', 'output_qty'],
@@ -101,7 +101,7 @@ var SECTIONS = [
detect: function(d) { return d.farm_patch_type; },
fields: [
['farm_patch_type', 'Patch Type', 'select', 'herb|allotment|flower|bush|tree'],
- ['farm_product', 'Product', 'search', 'e.g. tomato', '', null, 'items'],
+ ['farm_product', 'Product', 'search', 'tomato', '', null, 'items'],
['farm_plant_xp', 'Plant XP', 'number', '5', 'narrow'],
['farm_harvest_xp', 'Harvest XP', 'number', '10', 'narrow'],
['farm_level', 'Farm Level', 'number', '1', 'narrow'],
@@ -307,6 +307,10 @@ function renderCard(sec, data) {
h += renderSubtable(sec, st, data);
});
}
+
+ if (sec.id === 'crafting') {
+ h += ced_renderTagHelp('crafting');
+ }
}
h += '';
}
@@ -334,6 +338,7 @@ function renderCoreCard(data) {
var descVal = getVal(itemData, sec, 'description');
var dstr = typeof descVal === 'object' ? (Array.isArray(descVal) ? descVal.map(function(v){return v.text||'';}).join('\n') : JSON.stringify(descVal)) : String(descVal);
h += 'Description ';
+ h += ced_renderTagHelp('color');
return h;
}
@@ -1009,7 +1014,7 @@ function addArrayItem(cardID) {
} else {
var empty = {};
sec.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
arr.push(empty);
}
@@ -1061,7 +1066,7 @@ function addSubRow(cardID, subKey) {
var st = (sec.subtables || []).find(function(s) { return s.key === subKey; });
if (st) {
st.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
}
arr.push(empty);
@@ -1110,7 +1115,7 @@ function addSubSubRow(cardID, subKey, rowIdx, subSubKey) {
var sst = st.subSubtables.find(function(ss) { return ss.key === subSubKey; });
if (sst) {
sst.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
}
}
diff --git a/internal/admin/static/map.js b/internal/admin/static/map.js
index 6d56097..390043e 100644
--- a/internal/admin/static/map.js
+++ b/internal/admin/static/map.js
@@ -1260,8 +1260,8 @@ function courseShowNew() {
menu.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);min-width:520px;max-width:90vw;max-height:85vh;overflow-y:auto;overflow-x:hidden;padding:14px;z-index:201';
var h = 'New Course (room #' + roomID + ' = step 1) ';
- h += 'Course ID (filename)
';
- h += 'Course Name
';
+ h += 'Course ID (filename)
';
+ h += 'Course Name
';
h += 'Required Level
';
h += 'Start Room
';
h += 'Completion XP
';
@@ -3382,7 +3382,7 @@ function renderTriggerListHTML(arr, secId, secPath, allowItem) {
interactionStyle: true,
itemIDAllowed: allowItem,
label: 'Trigger',
- fields: [['item_id', 'Item ID', 'search', 'e.g. keycard', '', null, 'items']]
+ fields: [['item_id', 'Item ID', 'search', 'keycard', '', null, 'items']]
};
var ctx = {
sec: sec,
diff --git a/internal/admin/static/mobeditor.js b/internal/admin/static/mobeditor.js
index 10b256e..4b136a3 100644
--- a/internal/admin/static/mobeditor.js
+++ b/internal/admin/static/mobeditor.js
@@ -48,8 +48,8 @@ var MOB_SECTIONS = [
['stats.defenses.weakness', 'Weakness', 'select', '(none)|bio|eco|hydro|solar|chaos'],
['stats.defenses.weakness_percent', 'Weakness %', 'number', '50', 'narrow'],
['assassin_level', 'Assassin Lvl', 'number', '1', 'narrow'],
- ['finishing_blow', 'Finishing Blow', 'search', 'e.g. stake', '', null, 'items'],
- ['damage_without', 'Damage Without', 'search', 'e.g. holy_symbol', '', null, 'items'],
+ ['finishing_blow', 'Finishing Blow', 'search', 'stake', '', null, 'items'],
+ ['damage_without', 'Damage Without', 'search', 'holy_symbol', '', null, 'items'],
['size', 'Size', 'text', 'small'],
],
inline: [
@@ -301,9 +301,14 @@ function renderMobCoreCard(data) {
h += ced_renderTags(sec, il, data);
});
h += '';
+ h += '
';
h += renderMobField(sec, byKey['unique'], data, -1);
+ h += '
';
+ h += '
';
h += renderMobField(sec, byKey['protected'], data, -1);
h += '
';
+ h += '
';
+ h += ced_renderTagHelp('color');
return h;
}
@@ -507,7 +512,7 @@ function mobAddArrayItem(cardID) {
var arr = mobData[sec.path] || [];
var empty = {};
sec.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
arr.push(empty);
mobData[sec.path] = arr;
diff --git a/internal/admin/static/moduleeditor.js b/internal/admin/static/moduleeditor.js
index fe71f88..b2eb79f 100644
--- a/internal/admin/static/moduleeditor.js
+++ b/internal/admin/static/moduleeditor.js
@@ -221,7 +221,7 @@ function addArrayItem(cardID) {
var arr = moduleData[sec.path] || [];
var empty = {};
sec.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
arr.push(empty);
moduleData[sec.path] = arr;
diff --git a/internal/admin/static/objecteditor.js b/internal/admin/static/objecteditor.js
index 88bc5b7..b4d8282 100644
--- a/internal/admin/static/objecteditor.js
+++ b/internal/admin/static/objecteditor.js
@@ -14,7 +14,7 @@ var SECTIONS = [
['hidden', 'Hidden', 'checkbox'],
['inroom_description', 'In-Room Description', 'text', 'A copper rock juts from the ground.'],
['description', 'Description', 'textarea', 'A vein of copper runs through this rock.'],
- ['removal_item', 'Removal Item ID', 'search', 'e.g. ashes', '', null, 'items'],
+ ['removal_item', 'Removal Item ID', 'search', 'ashes', '', null, 'items'],
]
},
{
@@ -73,10 +73,10 @@ var SECTIONS = [
['tier', 'Tier', 'number', '1', 'narrow'],
['max_block_size', 'Max Block Size', 'select', '|small|medium|large|massive'],
['max_occupants', 'Max Occupants', 'number', '1', 'narrow'],
- ['unsafe_chance', 'Unsafe Chance', 'number', '0 = never, e.g. 0.05', 'narrow'],
- ['decay_ticks', 'Decay Ticks', 'number', '0 = never, e.g. 100', 'narrow'],
- ['decay_chance', 'Decay Chance', 'number', '0 = never, e.g. 0.01', 'narrow'],
- ['respawn_ticks', 'Respawn Ticks', 'number', '0 = no respawn, e.g. 50', 'narrow'],
+ ['unsafe_chance', 'Unsafe Chance', 'number', '0.05', 'narrow'],
+ ['decay_ticks', 'Decay Ticks', 'number', '100', 'narrow'],
+ ['decay_chance', 'Decay Chance', 'number', '0.01', 'narrow'],
+ ['respawn_ticks', 'Respawn Ticks', 'number', '50', 'narrow'],
['respawn_on_hide', 'Respawn on hide', 'checkbox'],
],
subtables: [
@@ -89,7 +89,7 @@ var SECTIONS = [
id: 'on_use', label: 'Use', labelHint: '(what happens when you use items on this)', path: 'on_use', isArray: true, fullWidth: true, interactionStyle: true,
detect: function(d) { return d.on_use && Array.isArray(d.on_use); },
fields: [
- ['item_id', 'Item ID', 'search', 'e.g. keycard (empty = bare use)', '', null, 'items'],
+ ['item_id', 'Item ID', 'search', 'keycard', '', null, 'items'],
]
},
{
@@ -340,6 +340,10 @@ function renderCard(sec, data) {
}
h += '';
}
+
+ if (sec.id === 'gather') {
+ h += ced_renderTagHelp('gather');
+ }
}
h += '';
}
@@ -447,13 +451,15 @@ function renderCoreCard(data) {
}
if (showInRoom) {
h += '';
- h += '
' + renderField(sec, sec.fields[4], data, -1) + '
';
+ h += '
' + renderField(sec, sec.fields[4], data, -1);
+ h += '
Alternative way this object can appear with the \'look\' command
';
h += '
X ';
h += '
';
}
if (showRemoval) {
h += '';
- h += '
' + renderField(sec, sec.fields[6], data, -1) + '
';
+ h += '
' + renderField(sec, sec.fields[6], data, -1);
+ h += '
Item left behind when this object is removed
';
h += '
X ';
h += '
';
}
@@ -471,6 +477,8 @@ function renderCoreCard(data) {
}
h += '';
+ h += ced_renderTagHelp('color');
+
return h;
}
@@ -672,8 +680,7 @@ function renderToolsCheckbox(sec, il, data) {
return 'Loading tool types... ';
}
if (arr.length === 0) {
- var hint = il.hint ? '' + esc(il.hint) + '
' : '';
- return hint + '+ Add Tools ';
+ return '+ Add Tools ';
}
var h = '';
h += '' + esc(il.label) + (il.hint ? ' (' + esc(il.hint) + ') ' : '') + ' ';
@@ -822,7 +829,7 @@ function addArrayItem(cardID) {
} else {
empty = {};
sec.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
}
arr.push(empty);
@@ -848,7 +855,7 @@ function addSubRow(cardID, subKey) {
var st = (sec.subtables || []).find(function(s) { return s.key === subKey; });
if (st) {
st.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
}
arr.push(empty);
@@ -884,7 +891,7 @@ function addDropRow(cardID, subKey, dropType) {
var empty = { _type: (dropType === 'table' ? 't' : 'i') };
if (st) {
st.fields.forEach(function(f) {
- empty[f[0]] = f[2] === 'checkbox' ? false : (f[2] === 'number' ? 0 : '');
+ empty[f[0]] = f[2] === 'checkbox' ? false : '';
});
}
empty.weight = 10;
diff --git a/internal/admin/static/talktree.js b/internal/admin/static/talktree.js
index 8e35404..ff44ff1 100644
--- a/internal/admin/static/talktree.js
+++ b/internal/admin/static/talktree.js
@@ -204,7 +204,7 @@
if (tag === 'INPUT' || tag === 'TEXTAREA') {
var val;
if (type === 'checkbox') { val = el.checked; }
- else if (type === 'number') { var n = parseFloat(el.value); val = isNaN(n) ? 0 : n; }
+ else if (type === 'number') { var n = parseFloat(el.value); val = isNaN(n) ? '' : n; }
else { val = el.value; }
talkSyncPath(path, val);
if (path.endsWith('.goto') && e.type === 'change') renderTalkTree(window._talkData);
--
cgit v1.2.3