diff options
| author | historia <[not public]> | 2026-07-09 04:03:00 -0400 |
|---|---|---|
| committer | historia <[not public]> | 2026-07-09 04:03:00 -0400 |
| commit | 74153c7814fc4cef988066ef04e38731a943bc12 (patch) | |
| tree | debd8229a1fd02daeb3059e9396008bb525ba4b9 /internal/admin/static/mobeditor.js | |
| parent | 09d325dcf5e779eab5550d3fd3377bde50101428 (diff) | |
| download | thehouseoficarus-74153c7814fc4cef988066ef04e38731a943bc12.tar.gz | |
feat(admin): nested condition/action buttons to manage complex YAML
Diffstat (limited to 'internal/admin/static/mobeditor.js')
| -rw-r--r-- | internal/admin/static/mobeditor.js | 150 |
1 files changed, 59 insertions, 91 deletions
diff --git a/internal/admin/static/mobeditor.js b/internal/admin/static/mobeditor.js index 7f8c0e3..c2364c8 100644 --- a/internal/admin/static/mobeditor.js +++ b/internal/admin/static/mobeditor.js @@ -121,13 +121,12 @@ var MOB_SECTIONS = [ ] }, { - id: 'on_kill', label: 'On Kill', labelHint: '(fired when this mob is defeated or its task completes — additive over drops)', path: 'on_kill', isArray: true, fullWidth: true, interactionStyle: true, + id: 'on_kill', label: 'On Kill', labelHint: '(fired when this mob is defeated or its task completes — additive over drops)', path: 'on_kill', isArray: true, fullWidth: true, interactionStyle: true, interScope: 'inline', detect: function(d) { return d.on_kill && Array.isArray(d.on_kill); }, fields: [ ['item_id', 'Item ID', 'search', '(optional — only fires if you wield this weapon when the mob is defeated)', '', null, 'items'], - ['condition', 'Condition', 'json', 'e.g. {"global_flag":"quest_active"}'], - ['action', 'Action', 'json', 'e.g. {"set_global_flags":{"boss_killed":true},"broadcast":"%p has slain the boss!","spawn_mob":"mini_boss"}'], - ['message', 'Message', 'text', 'Shown to the killer when this fires...'], + ['condition', 'Condition', 'inter_cond'], + ['action', 'Action', 'inter_act'], ] }, ]; @@ -138,6 +137,9 @@ function mobFieldID(sec, key, idx) { return ced_fieldID(sec, key, idx); } function mobFieldIDSub(sec, subKey, idx, fieldKey) { return ced_fieldIDSub(sec, subKey, idx, fieldKey); } function initMobEditor() { + window._ieRenderCurrent = renderCurrent; + window._ieRenderOnly = function() { if (mobID && mobData) renderMobEditor(mobID, mobData); }; + window._ieSyncAll = function(ed) { if (ed) ie_syncAllInteractions(ed, MOB_SECTIONS); }; editorType = 'mobs'; editorFields = []; loadList(); @@ -156,6 +158,7 @@ function loadMob(id) { API.get('/api/mobs/' + encodeURIComponent(id)).then(function(data) { mobData = data; window._editorData = mobData; + window._mobInterVis = {}; if (mobData.shop && mobData.shop.buys_anything === undefined) { mobData.shop.buys_anything = true; } @@ -220,6 +223,7 @@ function renderMobEditor(id, data) { function renderCurrent() { ced_syncDOMToData(mobData); + ie_syncAllInteractions(mobData, MOB_SECTIONS); if (!mobData || !mobID) return; renderMobEditor(mobID, mobData); } @@ -438,78 +442,23 @@ function renderMobField(sec, f, data, idx, subPath, optStyle) { // ---- Interaction-style array rendering (On Kill) ---- function renderMobArraySection(sec, data) { - var arr = data[mobCardPath(sec)] || []; - var h = ''; - var isInter = !!sec.interactionStyle; - if (isInter) { + if (sec.interactionStyle) { window._mobInterVis = window._mobInterVis || {}; if (!window._mobInterVis[sec.id]) window._mobInterVis[sec.id] = {}; + return ie_renderArraySection({ + sec: sec, + data: data, + visMap: window._mobInterVis[sec.id], + showRemove: function(idx) { return 'mobRemoveArrayItem(\'' + sec.id + '\',' + idx + ')'; }, + showField: function(secId, idx, key) { return 'mobShowInterField(\'' + secId + '\',' + idx + ',\'' + key + '\')'; }, + hideField: function(secId, idx, key) { return 'mobHideInterField(\'' + secId + '\',' + idx + ',\'' + key + '\')'; }, + addCondition: function(secId, idx) { return 'mobAddInterRootCondition(\'' + secId + '\',' + idx + ')'; }, + addEffect: function(secId, idx) { return 'mobAddInterAction(\'' + secId + '\',' + idx + ')'; }, + renderField: function(sec, f, data, idx, optStyle) { return renderMobField(sec, f, data, idx, null, optStyle); }, + onAdd: function() { return 'mobAddArrayItem(\'' + sec.id + '\')'; }, + }); } - arr.forEach(function(item, idx) { - var visMap = window._mobInterVis[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="mobRemoveArrayItem(\'' + sec.id + '\',' + idx + ')">Remove Interaction</button>'; - h += '<div style="display:flex;gap:4px;align-items:flex-end;flex-wrap:wrap;padding-right:135px">'; - 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="mobShowInterField(\'' + 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="mobShowInterField(\'' + 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="mobShowInterField(\'' + 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="mobShowInterField(\'' + sec.id + '\',' + idx + ',\'message\')">+ Add Message</button>'; - } - h += '</div>'; - h += '<div style="display:' + (showItem ? 'flex' : 'none') + ';gap:6px;align-items:flex-start">'; - h += renderMobField(sec, sec.fields[0], data, idx, null, 'flex:1;min-width:0'); - h += '<button class="btn btn-sm btn-danger" onclick="mobHideInterField(\'' + 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 += renderMobField(sec, sec.fields[1], data, idx, null, 'flex:1;min-width:0'); - h += '<button class="btn btn-sm btn-danger" onclick="mobHideInterField(\'' + 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 += renderMobField(sec, sec.fields[2], data, idx, null, 'flex:1;min-width:0'); - h += '<button class="btn btn-sm btn-danger" onclick="mobHideInterField(\'' + 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 += renderMobField(sec, sec.fields[3], data, idx, null, 'flex:1;min-width:0'); - h += '<button class="btn btn-sm btn-danger" onclick="mobHideInterField(\'' + sec.id + '\',' + idx + ',\'message\')" style="margin-top:14px">X</button>'; - h += '</div>'; - h += '</div>'; - }); - h += '<button class="btn btn-sm obj-sub-add" onclick="mobAddArrayItem(\'' + sec.id + '\')">+ Add ' + esc(sec.label) + '</button>'; - if (isInter) { - var helpKey = 'mob_' + 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="mobToggleInterHelp(\'' + sec.id + '\')">'; - h += '<span style="font-size:8px;margin-right:4px">' + (helpCollapsed ? '▶' : '▼') + '</span>'; - h += 'How Conditions & Actions Work'; - 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 kill; additive to standard loot).<br><br>'; - h += '<b>Item ID</b>: only fires if you wield this weapon (in main_hand or off_hand) when the mob is defeated. Leave empty to fire unconditionally.<br>'; - h += '<b>Condition</b>: JSON gate. <code>{"global_flag":"boss_quest"}</code>, <code>{"player_flag":"step","value":2}</code>, <code>{"has_item":"trophy"}</code>, <code>{"all_of":[...]}</code>, <code>{"any_of":[...]}</code>.<br>'; - h += '<b>Action</b>: JSON effects. <code>{"set_global_flags":{...}}</code>, <code>{"set_player_flags":{...}}</code>, <code>{"give_item":"gem"}</code>, <code>{"take_item":"key"}</code>, <code>{"teleport":5}</code>, <code>{"heal":10}</code>, <code>{"credits":100}</code>, <code>{"aps_node":true}</code>, <code>{"spawn_mob":"mini_boss"}</code>, <code>{"despawn_mob":"boss"}</code>, <code>{"broadcast":"%p vanquished the boss!"}</code>, <code>{"broadcast_global":"..."}</code>.<br>'; - h += '<b>Message</b>: shown to the killer when this interaction fires.'; - h += '</div>'; - } - h += '</div>'; - } - return h; + return ''; } function mobAddArrayItem(cardID) { @@ -536,34 +485,39 @@ function mobRemoveArrayItem(cardID, idx) { function mobShowInterField(secId, idx, key) { window._mobInterVis = window._mobInterVis || {}; - if (!window._mobInterVis[secId]) window._mobInterVis[secId] = {}; - if (!window._mobInterVis[secId][idx]) window._mobInterVis[secId][idx] = {}; - window._mobInterVis[secId][idx][key] = true; + ie_showField(window._mobInterVis, secId, idx, key); renderCurrent(); } +function mobAddInterRootCondition(secId, idx) { + var sec = MOB_SECTIONS.find(function(s) { return s.id === secId; }); + if (!sec) return; + ie_addRootConditionGroup(sec.path, idx); +} + +function mobAddInterAction(secId, idx) { + var sec = MOB_SECTIONS.find(function(s) { return s.id === secId; }); + if (!sec) return; + ie_addEffectToInteraction(sec.path, idx); +} + function mobHideInterField(secId, idx, key) { window._mobInterVis = window._mobInterVis || {}; - if (!window._mobInterVis[secId]) window._mobInterVis[secId] = {}; - if (!window._mobInterVis[secId][idx]) window._mobInterVis[secId][idx] = {}; - window._mobInterVis[secId][idx][key] = false; + ie_hideField(window._mobInterVis, secId, idx, key); + var sec = MOB_SECTIONS.find(function(s) { return s.id === secId; }); + var secPath = sec ? sec.path : secId; ced_syncDOMToData(mobData); - if (mobData[secId] && mobData[secId][idx]) { - mobData[secId][idx][key] = ''; + ie_syncAllInteractions(mobData, MOB_SECTIONS); + if (mobData[secPath] && mobData[secPath][idx]) { + if (key === 'condition' || key === 'action') { + delete mobData[secPath][idx][key]; + } else { + mobData[secPath][idx][key] = ''; + } } renderMobEditor(mobID, mobData); } -function mobToggleInterHelp(secId) { - var key = 'mob_' + secId + '_helpCollapsed'; - if (window[key] === undefined) { - window[key] = false; - } else { - window[key] = !window[key]; - } - renderCurrent(); -} - // ---- Subtable rendering ---- function renderMobSubField(sec, stKey, idx, f, val) { @@ -829,6 +783,8 @@ function unflattenObj(obj) { function saveMob() { if (!ced_validateFields(MOB_SECTIONS, mobFieldID, mobFieldIDSub)) return; + ie_syncAllInteractions(mobData, MOB_SECTIONS); + var out = {}; MOB_SECTIONS.forEach(function(sec) { @@ -845,10 +801,22 @@ function saveMob() { rows.forEach(function(row, idx) { var item = {}; sec.fields.forEach(function(f) { + if (f[2] === 'inter_cond' || f[2] === 'inter_act') return; var fid = mobFieldID(sec, f[0], idx); var el = document.getElementById(fid); if (el) item[f[0]] = ced_collectFieldValue(el, f[2]); }); + if (sec.interactionStyle) { + var dataArr = mobData[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; |
