aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static/objecteditor.js
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/static/objecteditor.js')
-rw-r--r--internal/admin/static/objecteditor.js190
1 files changed, 69 insertions, 121 deletions
diff --git a/internal/admin/static/objecteditor.js b/internal/admin/static/objecteditor.js
index ecb3ced..9c5a279 100644
--- a/internal/admin/static/objecteditor.js
+++ b/internal/admin/static/objecteditor.js
@@ -86,28 +86,29 @@ var SECTIONS = [
]
},
{
- id: 'on_use', label: 'On Use', labelHint: '(what happens when you use items on this)', path: 'on_use', isArray: true, fullWidth: true, interactionStyle: true,
+ id: 'on_use', label: 'On Use', labelHint: '(what happens when you use items on this)', path: 'on_use', isArray: true, fullWidth: true, interactionStyle: true, interScope: 'inline',
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'],
- ['condition', 'Condition', 'json', 'e.g. {"flag":"my_flag"} or {"player_flag":"x","value":1} or {"all_of":[{"flag":"a"},{"has_item":"key"}]}'],
- ['action', 'Action', 'json', 'e.g. {"set_global_flags":{"my_flag":true},"message":"You activate it.","give_item":"gem","teleport":5,"heal":10,"credits":100,"aps_node":true,"spawn_mob":"rat","despawn_mob":"rat","broadcast":"%p activates it.","broadcast_global":"%p did it!","delay":3}'],
- ['message', 'Message', 'text', 'You use the object...'],
+ ['condition', 'Condition', 'inter_cond'],
+ ['action', 'Action', 'inter_act'],
]
},
{
- id: 'on_look', label: 'On Look', labelHint: '(what happens when you "look <this>")', path: 'on_look', isArray: true, fullWidth: true, interactionStyle: true,
+ id: 'on_look', label: 'On Look', labelHint: '(what happens when you "look <this>")', path: 'on_look', isArray: true, fullWidth: true, interactionStyle: true, interScope: 'inline',
detect: function(d) { return d.on_look && Array.isArray(d.on_look); },
fields: [
['item_id', 'Item ID', 'search', '(optional — only fires if you carry this item)', '', null, 'items'],
- ['condition', 'Condition', 'json', 'e.g. {"player_flag":"read_sign","value":true}'],
- ['action', 'Action', 'json', 'e.g. {"set_player_flags":{"read_sign":true},"give_item":"gem"}'],
- ['message', 'Message', 'text', 'Shown to the player after the description...'],
+ ['condition', 'Condition', 'inter_cond'],
+ ['action', 'Action', 'inter_act'],
]
},
];
function initObjectEditor() {
+ window._ieRenderCurrent = renderCurrent;
+ window._ieRenderOnly = function() { if (objectID && objectData) renderObjectEditor(objectID, objectData); };
+ window._ieSyncAll = function(ed) { if (ed) ie_syncAllInteractions(ed, SECTIONS); };
editorType = 'objects';
editorFields = [];
loadList();
@@ -123,7 +124,7 @@ function loadObject(id) {
API.get('/api/objects/' + encodeURIComponent(id)).then(function(data) {
objectData = data;
window._editorData = objectData;
- window._useInterVis = {};
+ window._interVis = {};
window._useInterHelpCollapsed = undefined;
window._coreVis = {};
window._stealVis = {};
@@ -509,104 +510,30 @@ function renderArraySection(sec, data) {
if (isInter) {
window._interVis = window._interVis || {};
if (!window._interVis[sec.id]) window._interVis[sec.id] = {};
+ return ie_renderArraySection({
+ sec: sec,
+ data: data,
+ visMap: window._interVis[sec.id],
+ showRemove: function(idx) { return 'removeArrayItem(\'' + sec.id + '\',' + idx + ')'; },
+ showField: function(secId, idx, key) { return 'showInterField(\'' + secId + '\',' + idx + ',\'' + key + '\')'; },
+ hideField: function(secId, idx, key) { return 'hideInterField(\'' + secId + '\',' + idx + ',\'' + key + '\')'; },
+ addCondition: function(secId, idx) { return 'addInterRootCondition(\'' + secId + '\',' + idx + ')'; },
+ addEffect: function(secId, idx) { return 'addInterAction(\'' + secId + '\',' + idx + ')'; },
+ renderField: function(sec, f, data, idx, optStyle) { return renderField(sec, f, data, idx, null, optStyle); },
+ onAdd: function() { return 'addArrayItem(\'' + sec.id + '\')'; },
+ });
}
arr.forEach(function(item, idx) {
- if (isInter) {
- var visMap = window._interVis[sec.id];
- var vis = visMap[idx] || {};
- visMap[idx] = vis;
- var showItem = vis.item_id || (item.item_id && item.item_id !== '');
- var showCond = vis.condition || (item.condition && item.condition !== '');
- var showAct = vis.action || (item.action && item.action !== '');
- var showMsg = vis.message || (item.message && item.message !== '');
-
- h += '<div class="obj-sub-row" data-idx="' + idx + '" style="flex-direction:column;align-items:stretch;position:relative;gap:6px">';
-
- h += '<button class="btn btn-sm btn-danger" style="position:absolute;top:0;right:0;white-space:nowrap;z-index:1" onclick="removeArrayItem(\'' + sec.id + '\',' + idx + ')">Remove Interaction</button>';
-
- h += '<div style="display:flex;gap:4px;align-items:flex-end;flex-wrap:wrap;padding-right:125px">';
- if (!showItem) {
- h += '<button class="btn btn-sm" style="background:var(--accent);color:var(--text);border:1px solid #1a5a8e;align-self:flex-end;margin-bottom:3px;white-space:nowrap" onclick="showInterField(\'' + sec.id + '\',' + idx + ',\'item_id\')">+ Add Required Item</button>';
- h += '<div style="width:1px;background:var(--border);align-self:stretch;margin:2px 0;flex-shrink:0"></div>';
- }
- if (!showCond) {
- h += '<button class="btn btn-sm" style="background:var(--accent);color:var(--text);border:1px solid #1a5a8e;align-self:flex-end;margin-bottom:3px;white-space:nowrap" onclick="showInterField(\'' + sec.id + '\',' + idx + ',\'condition\')">+ Add Condition</button>';
- }
- if (!showAct) {
- h += '<button class="btn btn-sm" style="background:var(--accent);color:var(--text);border:1px solid #1a5a8e;align-self:flex-end;margin-bottom:3px;white-space:nowrap" onclick="showInterField(\'' + sec.id + '\',' + idx + ',\'action\')">+ Add Action</button>';
- }
- if (!showMsg) {
- h += '<button class="btn btn-sm" style="background:var(--accent);color:var(--text);border:1px solid #1a5a8e;align-self:flex-end;margin-bottom:3px;white-space:nowrap" onclick="showInterField(\'' + sec.id + '\',' + idx + ',\'message\')">+ Add Message</button>';
- }
- h += '</div>';
-
- h += '<div style="display:' + (showItem ? 'flex' : 'none') + ';gap:6px;align-items:flex-start">';
- h += renderField(sec, sec.fields[0], data, idx, null, 'flex:1;min-width:0');
- h += '<button class="btn btn-sm btn-danger" onclick="hideInterField(\'' + sec.id + '\',' + idx + ',\'item_id\')" style="margin-top:14px">X</button>';
- h += '</div>';
-
- h += '<div style="display:' + (showCond ? 'flex' : 'none') + ';gap:6px;align-items:flex-start">';
- h += renderField(sec, sec.fields[1], data, idx, null, 'flex:1;min-width:0');
- h += '<button class="btn btn-sm btn-danger" onclick="hideInterField(\'' + sec.id + '\',' + idx + ',\'condition\')" style="margin-top:14px">X</button>';
- h += '</div>';
-
- h += '<div style="display:' + (showAct ? 'flex' : 'none') + ';gap:6px;align-items:flex-start">';
- h += renderField(sec, sec.fields[2], data, idx, null, 'flex:1;min-width:0');
- h += '<button class="btn btn-sm btn-danger" onclick="hideInterField(\'' + sec.id + '\',' + idx + ',\'action\')" style="margin-top:14px">X</button>';
- h += '</div>';
-
- h += '<div style="display:' + (showMsg ? 'flex' : 'none') + ';gap:6px;align-items:flex-start">';
- h += renderField(sec, sec.fields[3], data, idx, null, 'flex:1;min-width:0');
- h += '<button class="btn btn-sm btn-danger" onclick="hideInterField(\'' + sec.id + '\',' + idx + ',\'message\')" style="margin-top:14px">X</button>';
- h += '</div>';
-
- h += '</div>';
- } else {
- h += '<div class="obj-sub-row" data-idx="' + idx + '">';
- h += '<div class="obj-card-grid">';
- sec.fields.forEach(function(f) {
- h += renderField(sec, f, data, idx);
- });
- h += '</div>';
- h += '<button class="btn btn-sm btn-danger obj-sub-remove" onclick="removeArrayItem(\'' + sec.id + '\',' + idx + ')">X</button>';
- h += '</div>';
- }
- });
- h += '<button class="btn btn-sm obj-sub-add" onclick="addArrayItem(\'' + sec.id + '\')">+ Add ' + esc(sec.label) + '</button>';
- if (isInter) {
- var helpKey = sec.id + '_helpCollapsed';
- var helpCollapsed = window[helpKey] === undefined ? true : window[helpKey];
- h += '<div style="margin-top:8px;border:1px solid rgba(100,160,255,.15);border-radius:4px;overflow:hidden">';
- h += '<div style="padding:6px 10px;background:rgba(100,160,255,.08);cursor:pointer;font-size:10px;color:#6af;font-weight:bold;text-transform:uppercase;letter-spacing:.5px" onclick="toggleInterHelp(\'' + sec.id + '\')">';
- h += '<span style="font-size:8px;margin-right:4px">' + (helpCollapsed ? '&#9654;' : '&#9660;') + '</span>';
- h += 'How Conditions &amp; Actions Work';
+ h += '<div class="obj-sub-row" data-idx="' + idx + '">';
+ h += '<div class="obj-card-grid">';
+ sec.fields.forEach(function(f) {
+ h += renderField(sec, f, data, idx);
+ });
h += '</div>';
- if (!helpCollapsed) {
- h += '<div style="padding:8px;background:rgba(100,160,255,.05);font-size:10px;color:#aaa;line-height:1.6">';
- h += 'Entries checked top-to-bottom, first match wins (one fires per use/look/kill).<br><br>';
- h += '<b>Item ID</b>: <b>on_use</b> requires <code>use &lt;item&gt; on &lt;object&gt;</code>; empty = bare <code>use &lt;object&gt;</code>. <b>on_look</b> = only fires if you carry this item. <b>on_kill</b> = only fires if you wield this weapon when the mob is defeated.<br>';
- h += '<b>Condition</b>: JSON. Available gates:<br>';
- h += '&nbsp;&nbsp;<code>{"global_flag":"gate_open","not":true}</code> — world flag is NOT set<br>';
- h += '&nbsp;&nbsp;<code>{"player_flag":"has_key","value":1}</code> — player flag matches value<br>';
- h += '&nbsp;&nbsp;<code>{"has_item":"silver_bar"}</code> — player carries item<br>';
- h += '&nbsp;&nbsp;<code>{"min_credits":50}</code> — minimum credits<br>';
- h += '&nbsp;&nbsp;<code>{"all_of":[{"global_flag":"a"},{"has_item":"b"}]}</code> — ALL<br>';
- h += '&nbsp;&nbsp;<code>{"any_of":[...]}</code> — ANY<br>';
- h += '&nbsp;&nbsp;Omit for an unconditional interaction.<br>';
- h += '<b>Action</b>: JSON. Effects that fire when the interaction runs:<br>';
- h += '&nbsp;&nbsp;<code>{"set_global_flags":{"gate_open":true}}</code> — set world flags<br>';
- h += '&nbsp;&nbsp;<code>{"set_player_flags":{"spoke":true}}</code> — set player flags<br>';
- h += '&nbsp;&nbsp;<code>{"give_item":"keycard","take_item":"bomb"}</code> — give/take item<br>';
- h += '&nbsp;&nbsp;<code>{"teleport":5,"heal":10,"credits":100}</code> — move, heal, give credits<br>';
- h += '&nbsp;&nbsp;<code>{"aps_node":true}</code> — mark current room as APS node<br>';
- h += '&nbsp;&nbsp;<code>{"spawn_mob":"rat","despawn_mob":"rat"}</code> — spawn/despawn transient mob<br>';
- h += '&nbsp;&nbsp;<code>{"broadcast":"%p activates it.","broadcast_global":"%p did it!"}</code> — announce (%p = player, %v = flag value)<br>';
- h += '&nbsp;&nbsp;<code>{"message":"You feel energized.","delay":3}</code> — only meaningful inside on_enter steps / triggers (delay in ticks)<br>';
- h += '<b>Message</b>: Sent to the player when the interaction fires (one-tick action).';
- h += '</div>';
- }
+ h += '<button class="btn btn-sm btn-danger obj-sub-remove" onclick="removeArrayItem(\'' + sec.id + '\',' + idx + ')">X</button>';
h += '</div>';
- }
+ });
+ h += '<button class="btn btn-sm obj-sub-add" onclick="addArrayItem(\'' + sec.id + '\')">+ Add ' + esc(sec.label) + '</button>';
return h;
}
@@ -973,6 +900,7 @@ function validateDropRow(idx) {
function renderCurrent() {
ced_syncDOMToData(objectData);
+ ie_syncAllInteractions(objectData, SECTIONS);
syncGatherToolsFromDOM();
if (!objectData || !objectID) return;
renderObjectEditor(objectID, objectData);
@@ -980,20 +908,35 @@ function renderCurrent() {
function showInterField(secId, idx, key) {
window._interVis = window._interVis || {};
- if (!window._interVis[secId]) window._interVis[secId] = {};
- if (!window._interVis[secId][idx]) window._interVis[secId][idx] = {};
- window._interVis[secId][idx][key] = true;
+ ie_showField(window._interVis, secId, idx, key);
renderCurrent();
}
+function addInterRootCondition(secId, idx) {
+ var sec = SECTIONS.find(function(s) { return s.id === secId; });
+ if (!sec) return;
+ ie_addRootConditionGroup(sec.path, idx);
+}
+
+function addInterAction(secId, idx) {
+ var sec = SECTIONS.find(function(s) { return s.id === secId; });
+ if (!sec) return;
+ ie_addEffectToInteraction(sec.path, idx);
+}
+
function hideInterField(secId, idx, key) {
window._interVis = window._interVis || {};
- if (!window._interVis[secId]) window._interVis[secId] = {};
- if (!window._interVis[secId][idx]) window._interVis[secId][idx] = {};
- window._interVis[secId][idx][key] = false;
+ ie_hideField(window._interVis, secId, idx, key);
+ var sec = SECTIONS.find(function(s) { return s.id === secId; });
+ var secPath = sec ? sec.path : secId;
ced_syncDOMToData(objectData);
- if (objectData[secId] && objectData[secId][idx]) {
- objectData[secId][idx][key] = '';
+ ie_syncAllInteractions(objectData, SECTIONS);
+ if (objectData[secPath] && objectData[secPath][idx]) {
+ if (key === 'condition' || key === 'action') {
+ delete objectData[secPath][idx][key];
+ } else {
+ objectData[secPath][idx][key] = '';
+ }
}
renderObjectEditor(objectID, objectData);
}
@@ -1032,16 +975,6 @@ function hideGuardMob() {
renderObjectEditor(objectID, objectData);
}
-function toggleInterHelp(secId) {
- var key = secId + '_helpCollapsed';
- if (window[key] === undefined) {
- window[key] = false;
- } else {
- window[key] = !window[key];
- }
- renderCurrent();
-}
-
function toggleGatherConditionals() {
var skillEl = document.getElementById('f_gather_skill');
var skill = skillEl ? skillEl.value : '';
@@ -1072,6 +1005,8 @@ function collectFieldValue(el, type) { return ced_collectFieldValue(el, type); }
function saveObject() {
if (!validateFields()) return;
+ ie_syncAllInteractions(objectData, SECTIONS);
+
var out = {};
SECTIONS.forEach(function(sec) {
@@ -1083,10 +1018,22 @@ function saveObject() {
rows.forEach(function(row, idx) {
var item = {};
sec.fields.forEach(function(f) {
+ if (f[2] === 'inter_cond' || f[2] === 'inter_act') return;
var fid = fieldID(sec, f[0], idx);
var el = document.getElementById(fid);
if (el) item[f[0]] = collectFieldValue(el, f[2]);
});
+ if (sec.interactionStyle) {
+ var dataArr = objectData[sec.path] || [];
+ var dataItem = dataArr[idx] || {};
+ if (dataItem.condition && typeof dataItem.condition === 'object') {
+ var cleanedCond = ie_cleanCondition(dataItem.condition);
+ if (cleanedCond) item.condition = cleanedCond;
+ }
+ if (dataItem.action && typeof dataItem.action === 'object') {
+ item.action = dataItem.action;
+ }
+ }
if (Object.keys(item).length > 0) arr.push(item);
});
if (arr.length > 0) out[sec.path] = arr;
@@ -1182,6 +1129,7 @@ function saveObject() {
}
});
+ ced_cleanOutput(out);
out.id = objectID;
API.put('/api/objects/' + encodeURIComponent(objectID), out).then(function(resp) {