From 09d325dcf5e779eab5550d3fd3377bde50101428 Mon Sep 17 00:00:00 2001 From: historia <[not public]> Date: Wed, 8 Jul 2026 19:59:14 -0400 Subject: feat: unify on use, on look, and on kill. all support same conditions/actions now. --- internal/admin/static/objecteditor.js | 183 ++++++++++++++-------------------- 1 file changed, 73 insertions(+), 110 deletions(-) (limited to 'internal/admin/static/objecteditor.js') diff --git a/internal/admin/static/objecteditor.js b/internal/admin/static/objecteditor.js index 6abec3e..ecb3ced 100644 --- a/internal/admin/static/objecteditor.js +++ b/internal/admin/static/objecteditor.js @@ -86,26 +86,23 @@ var SECTIONS = [ ] }, { - id: 'use_interactions', label: 'Use Interactions', labelHint: '(what happens when you use items on this)', path: 'use_interactions', isArray: true, fullWidth: true, - detect: function(d) { return d.use_interactions && Array.isArray(d.use_interactions); }, + id: 'on_use', label: 'On 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', '', null, 'items'], + ['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_flags":{"my_flag":true},"message":"You activate it.","give_item":"gem"}'], + ['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...'], ] }, { - id: 'on_look', label: 'On Look', labelHint: '(what happens when you "look ")', path: 'on_look', - detect: function(d) { return d.on_look; }, + id: 'on_look', label: 'On Look', labelHint: '(what happens when you "look ")', path: 'on_look', isArray: true, fullWidth: true, interactionStyle: true, + detect: function(d) { return d.on_look && Array.isArray(d.on_look); }, fields: [ - ['set_flags', 'Set Global Flags', 'json', '{"flag":"value"}'], - ['set_player_flags', 'Set Player Flags', 'json', '{"pflag":"value"}'], - ['give_item', 'Give Item', 'search', 'e.g. keycard', '', null, 'items'], - ['take_item', 'Take Item', 'search', 'e.g. bomb', '', null, 'items'], - ['teleport', 'Teleport', 'number', '5', 'narrow'], - ['heal', 'Heal', 'number', '10', 'narrow'], - ['credits', 'Credits', 'number', '100', 'narrow'], + ['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...'], ] }, ]; @@ -191,7 +188,7 @@ function cardPath(sec) { function getVal(data, sec, key) { var p = cardPath(sec); - if (p === 'on_look' || sec.isArray) { + if (sec.isArray) { return data[p] && data[p][key] !== undefined ? data[p][key] : ''; } var fp = p ? p + '.' + key : key; @@ -234,8 +231,6 @@ function renderCard(sec, data) { h += renderCoreCard(data); } else if (sec.id === 'steal') { h += renderStealCard(data); - } else if (sec.id === 'on_look') { - h += renderOnLookCard(data); } else { h += '
'; sec.fields.forEach(function(f) { @@ -507,56 +502,20 @@ function renderStealCard(data) { return h; } -function renderOnLookCard(data) { - var sec = SECTIONS.find(function(s) { return s.id === 'on_look'; }); - var h = '
'; - h += renderField(sec, sec.fields[0], data, -1, null, 'flex:1'); - h += renderField(sec, sec.fields[1], data, -1, null, 'flex:1'); - h += '
'; - h += '
'; - h += renderField(sec, sec.fields[2], data, -1, null, 'flex:1'); - h += renderField(sec, sec.fields[3], data, -1, null, 'flex:1'); - h += '
'; - h += '
'; - h += renderField(sec, sec.fields[4], data, -1); - h += renderField(sec, sec.fields[5], data, -1); - h += renderField(sec, sec.fields[6], data, -1); - h += '
'; - var helpCollapsed = window._onLookHelpCollapsed === undefined ? true : window._onLookHelpCollapsed; - h += '
'; - h += '
'; - h += '' + (helpCollapsed ? '▶' : '▼') + ''; - h += 'How Set Global Flags & Set Player Flags Work'; - h += '
'; - if (!helpCollapsed) { - h += '
'; - h += 'When a player looks at this object, these fields apply effects.

'; - h += 'Set Global Flags — Sets world flags shared by all players. JSON object mapping flag names to values:
'; - h += '  {"gate_open":true,"boss_summoned":false}
'; - h += '  Flags persist until changed by another on_look, room script, or interact action.

'; - h += 'Set Player Flags — Sets per-character flags saved to the player\'s YAML. JSON object mapping flag names to values:
'; - h += '  {"has_seen_cave":true,"dialog_spoke":1}
'; - h += '  These flags can be used in conditions (player_flag) to track player progress.

'; - h += 'Other FieldsGive Item grants an item, Take Item removes one, '; - h += 'Teleport sends player to a room, Heal restores HP, Credits adds/removes credits (use negative for cost).

'; - h += 'All effects fire simultaneously when the player looks at this object.'; - h += '
'; - } - h += '
'; - return h; -} - function renderArraySection(sec, data) { var arr = data[cardPath(sec)] || []; var h = ''; - var isUseInter = sec.id === 'use_interactions'; - if (isUseInter) { - window._useInterVis = window._useInterVis || {}; + var isInter = !!sec.interactionStyle; + if (isInter) { + window._interVis = window._interVis || {}; + if (!window._interVis[sec.id]) window._interVis[sec.id] = {}; } arr.forEach(function(item, idx) { - if (isUseInter) { - var vis = window._useInterVis[idx] || {}; - window._useInterVis[idx] = vis; + 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 !== ''); @@ -566,32 +525,39 @@ function renderArraySection(sec, data) { h += ''; h += '
'; - h += renderField(sec, sec.fields[0], data, idx, null, 'max-width:260px'); - h += '
'; + if (!showItem) { + h += ''; + h += '
'; + } if (!showCond) { - h += ''; + h += ''; } if (!showAct) { - h += ''; + h += ''; } if (!showMsg) { - h += ''; + h += ''; } h += '
'; + h += '
'; + h += renderField(sec, sec.fields[0], data, idx, null, 'flex:1;min-width:0'); + h += ''; + h += '
'; + h += '
'; h += renderField(sec, sec.fields[1], data, idx, null, 'flex:1;min-width:0'); - h += ''; + h += ''; h += '
'; h += '
'; h += renderField(sec, sec.fields[2], data, idx, null, 'flex:1;min-width:0'); - h += ''; + h += ''; h += '
'; h += '
'; h += renderField(sec, sec.fields[3], data, idx, null, 'flex:1;min-width:0'); - h += ''; + h += ''; h += '
'; h += '
'; @@ -606,32 +572,37 @@ function renderArraySection(sec, data) { h += ''; } }); - h += ''; - if (isUseInter) { - var helpCollapsed = window._useInterHelpCollapsed === undefined ? true : window._useInterHelpCollapsed; + h += ''; + if (isInter) { + var helpKey = sec.id + '_helpCollapsed'; + var helpCollapsed = window[helpKey] === undefined ? true : window[helpKey]; h += '
'; - h += '
'; + h += '
'; h += '' + (helpCollapsed ? '▶' : '▼') + ''; h += 'How Conditions & Actions Work'; h += '
'; if (!helpCollapsed) { h += '
'; - h += 'Entries checked top-to-bottom, first match wins.

Item ID: required for use <item> on <object>; omit for plain use <object>.
'; - h += 'Condition: JSON. When this interaction is available:
'; - h += '  {"flag":"gate_open","not":true} — world flag is NOT set
'; + h += 'Entries checked top-to-bottom, first match wins (one fires per use/look/kill).

'; + h += 'Item ID: on_use requires use <item> on <object>; empty = bare use <object>. on_look = only fires if you carry this item. on_kill = only fires if you wield this weapon when the mob is defeated.
'; + h += 'Condition: JSON. Available gates:
'; + h += '  {"global_flag":"gate_open","not":true} — world flag is NOT set
'; h += '  {"player_flag":"has_key","value":1} — player flag matches value
'; h += '  {"has_item":"silver_bar"} — player carries item
'; - h += '  {"all_of":[{"flag":"a"},{"has_item":"b"}]} — ALL sub-conditions
'; - h += '  {"any_of":[...]} — ANY sub-condition
'; + h += '  {"min_credits":50} — minimum credits
'; + h += '  {"all_of":[{"global_flag":"a"},{"has_item":"b"}]} — ALL
'; + h += '  {"any_of":[...]} — ANY
'; h += '  Omit for an unconditional interaction.
'; - h += 'Action: JSON. What happens when the interaction fires:
'; - h += '  {"set_flags":{"gate_open":true}} — set world flags
'; + h += 'Action: JSON. Effects that fire when the interaction runs:
'; + h += '  {"set_global_flags":{"gate_open":true}} — set world flags
'; h += '  {"set_player_flags":{"spoke":true}} — set player flags
'; - h += '  {"give_item":"keycard","teleport":5} — give item + teleport
'; - h += '  {"take_item":"bomb","heal":10} — take item + heal
'; - h += '  {"credits":-50} — deduct credits
'; - h += '  {"reputation_cost":1,"aps_node":true} — rep cost + mark APS
'; - h += 'Message: Sent to the player when the interaction fires (1-tick action).'; + h += '  {"give_item":"keycard","take_item":"bomb"} — give/take item
'; + h += '  {"teleport":5,"heal":10,"credits":100} — move, heal, give credits
'; + h += '  {"aps_node":true} — mark current room as APS node
'; + h += '  {"spawn_mob":"rat","despawn_mob":"rat"} — spawn/despawn transient mob
'; + h += '  {"broadcast":"%p activates it.","broadcast_global":"%p did it!"} — announce (%p = player, %v = flag value)
'; + h += '  {"message":"You feel energized.","delay":3} — only meaningful inside on_enter steps / triggers (delay in ticks)
'; + h += 'Message: Sent to the player when the interaction fires (one-tick action).'; h += '
'; } h += '
'; @@ -906,8 +877,6 @@ function addSection() { if (sec.path) { if (sec.isArray) { objectData[sec.path] = []; - } else if (sec.id === 'on_look') { - objectData[sec.path] = {}; } else if (sec.id === 'gather') { objectData[sec.path] = {skill:'', tools:[], success:{base:0, per_level:0, cap:1}, drops:[], gather_message:'', fail_message:'', respawn_timer:0, respawn_broadcast:'', deplete_timer:0, nest_chance:0}; } else if (sec.id === 'safespot') { @@ -1009,20 +978,22 @@ function renderCurrent() { renderObjectEditor(objectID, objectData); } -function showUseInterField(idx, key) { - window._useInterVis = window._useInterVis || {}; - if (!window._useInterVis[idx]) window._useInterVis[idx] = {}; - window._useInterVis[idx][key] = true; +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; renderCurrent(); } -function hideUseInterField(idx, key) { - window._useInterVis = window._useInterVis || {}; - if (!window._useInterVis[idx]) window._useInterVis[idx] = {}; - window._useInterVis[idx][key] = false; +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; ced_syncDOMToData(objectData); - if (objectData.use_interactions && objectData.use_interactions[idx]) { - objectData.use_interactions[idx][key] = ''; + if (objectData[secId] && objectData[secId][idx]) { + objectData[secId][idx][key] = ''; } renderObjectEditor(objectID, objectData); } @@ -1061,20 +1032,12 @@ function hideGuardMob() { renderObjectEditor(objectID, objectData); } -function toggleUseInterHelp() { - if (window._useInterHelpCollapsed === undefined) { - window._useInterHelpCollapsed = false; - } else { - window._useInterHelpCollapsed = !window._useInterHelpCollapsed; - } - renderCurrent(); -} - -function toggleOnLookHelp() { - if (window._onLookHelpCollapsed === undefined) { - window._onLookHelpCollapsed = false; +function toggleInterHelp(secId) { + var key = secId + '_helpCollapsed'; + if (window[key] === undefined) { + window[key] = false; } else { - window._onLookHelpCollapsed = !window._onLookHelpCollapsed; + window[key] = !window[key]; } renderCurrent(); } -- cgit v1.2.3