diff options
Diffstat (limited to 'internal/admin/static/objecteditor.js')
| -rw-r--r-- | internal/admin/static/objecteditor.js | 190 |
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 ? '▶' : '▼') + '</span>'; - h += 'How Conditions & 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 <item> on <object></code>; empty = bare <code>use <object></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 += ' <code>{"global_flag":"gate_open","not":true}</code> — world flag is NOT set<br>'; - h += ' <code>{"player_flag":"has_key","value":1}</code> — player flag matches value<br>'; - h += ' <code>{"has_item":"silver_bar"}</code> — player carries item<br>'; - h += ' <code>{"min_credits":50}</code> — minimum credits<br>'; - h += ' <code>{"all_of":[{"global_flag":"a"},{"has_item":"b"}]}</code> — ALL<br>'; - h += ' <code>{"any_of":[...]}</code> — ANY<br>'; - h += ' Omit for an unconditional interaction.<br>'; - h += '<b>Action</b>: JSON. Effects that fire when the interaction runs:<br>'; - h += ' <code>{"set_global_flags":{"gate_open":true}}</code> — set world flags<br>'; - h += ' <code>{"set_player_flags":{"spoke":true}}</code> — set player flags<br>'; - h += ' <code>{"give_item":"keycard","take_item":"bomb"}</code> — give/take item<br>'; - h += ' <code>{"teleport":5,"heal":10,"credits":100}</code> — move, heal, give credits<br>'; - h += ' <code>{"aps_node":true}</code> — mark current room as APS node<br>'; - h += ' <code>{"spawn_mob":"rat","despawn_mob":"rat"}</code> — spawn/despawn transient mob<br>'; - h += ' <code>{"broadcast":"%p activates it.","broadcast_global":"%p did it!"}</code> — announce (%p = player, %v = flag value)<br>'; - h += ' <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) { |
