aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/static')
-rw-r--r--internal/admin/static/admin.css3
-rw-r--r--internal/admin/static/cardeditor.js74
-rw-r--r--internal/admin/static/hazardeditor.js98
-rw-r--r--internal/admin/static/mobeditor.js162
4 files changed, 246 insertions, 91 deletions
diff --git a/internal/admin/static/admin.css b/internal/admin/static/admin.css
index 0ee66bb..798a2a2 100644
--- a/internal/admin/static/admin.css
+++ b/internal/admin/static/admin.css
@@ -290,6 +290,9 @@ g.ud-hover:hover text{font-weight:bold}
.seg-pill.seg-pill-3.seg-idx-0::before{transform:translateX(0)}
.seg-pill.seg-pill-3.seg-idx-1::before{transform:translateX(100%)}
.seg-pill.seg-pill-3.seg-idx-2::before{transform:translateX(200%)}
+.seg-pill.seg-pill-2::before{width:calc(100% / 2)}
+.seg-pill.seg-pill-2.seg-idx-0::before{transform:translateX(0)}
+.seg-pill.seg-pill-2.seg-idx-1::before{transform:translateX(100%)}
.seg-pill .seg-opt:focus-visible{outline:2px solid var(--accent);outline-offset:-1px;border-radius:3px;z-index:2}
.obj-color-row{display:flex;align-items:center;gap:4px}
.obj-color-row .color-swatch{flex-shrink:0}
diff --git a/internal/admin/static/cardeditor.js b/internal/admin/static/cardeditor.js
index 1b2b76b..f32ea7e 100644
--- a/internal/admin/static/cardeditor.js
+++ b/internal/admin/static/cardeditor.js
@@ -584,3 +584,77 @@ function ced_cleanOutput(obj) {
}
}
}
+
+function ced_unflattenObj(obj) {
+ var result = {};
+ Object.keys(obj).forEach(function(key) {
+ var parts = key.split('.');
+ var current = result;
+ for (var i = 0; i < parts.length - 1; i++) {
+ if (!current[parts[i]]) current[parts[i]] = {};
+ current = current[parts[i]];
+ }
+ current[parts[parts.length - 1]] = obj[key];
+ });
+ return result;
+}
+
+function ced_normalizeAtkTypes(v) {
+ if (Array.isArray(v)) return v.slice();
+ if (typeof v === 'string' && v) return [v];
+ return [];
+}
+
+function ced_renderAtkTypeWidget(data, widgetID, selectFnName) {
+ var combat = data.combat || {};
+ var types = ced_normalizeAtkTypes(combat.attack_types);
+ var melee = types.filter(function(t) { return t === 'stab' || t === 'slash' || t === 'crush'; })[0] || 'crush';
+ var hasRanged = types.indexOf('ranged') >= 0;
+ var hasScience = types.indexOf('science') >= 0;
+ var meleeOpts = ['stab','slash','crush'];
+ var activeIdx = meleeOpts.indexOf(melee);
+ if (activeIdx < 0) activeIdx = 2;
+
+ var h = '<div class="obj-inline-group ced-atktype" id="' + widgetID + '">';
+ h += '<span class="obj-inline-label">Atk Type</span>';
+ h += '<div class="seg-pill seg-pill-3 seg-idx-' + activeIdx + ' ced-atktype-pill" style="margin-top:4px">';
+ meleeOpts.forEach(function(t, i) {
+ h += '<button type="button" class="seg-opt' + (i === activeIdx ? ' seg-active' : '') + '" data-v="' + t + '" onclick="' + selectFnName + '(\'' + t + '\',this)">' + t + '</button>';
+ });
+ h += '</div>';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ h += '<label class="obj-field obj-check obj-narrow"><input type="checkbox" class="ced-atktype-ranged"' + (hasRanged ? ' checked' : '') + '> <span>ranged</span></label>';
+ h += '<label class="obj-field obj-check obj-narrow"><input type="checkbox" class="ced-atktype-science"' + (hasScience ? ' checked' : '') + '> <span>science</span></label>';
+ h += '</div>';
+ h += '</div>';
+ return h;
+}
+
+function ced_atkPillSelect(val, btn) {
+ var pill = btn.closest('.ced-atktype-pill');
+ if (!pill) return;
+ var opts = pill.querySelectorAll('.seg-opt');
+ var idx = -1;
+ opts.forEach(function(o, i) {
+ if (o.getAttribute('data-v') === val) {
+ o.classList.add('seg-active');
+ idx = i;
+ } else {
+ o.classList.remove('seg-active');
+ }
+ });
+ pill.className = pill.className.replace(/seg-idx-\d/g, 'seg-idx-' + idx);
+}
+
+function ced_collectAtkType(widgetID) {
+ var widget = document.getElementById(widgetID);
+ if (!widget) return ['crush'];
+ var active = widget.querySelector('.ced-atktype-pill .seg-opt.seg-active');
+ var melee = active ? active.getAttribute('data-v') : 'crush';
+ var out = [melee];
+ var rng = widget.querySelector('.ced-atktype-ranged');
+ var sci = widget.querySelector('.ced-atktype-science');
+ if (rng && rng.checked) out.push('ranged');
+ if (sci && sci.checked) out.push('science');
+ return out;
+}
diff --git a/internal/admin/static/hazardeditor.js b/internal/admin/static/hazardeditor.js
index e849512..89586ac 100644
--- a/internal/admin/static/hazardeditor.js
+++ b/internal/admin/static/hazardeditor.js
@@ -14,17 +14,26 @@ var HAZARD_SECTIONS = [
['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'],
- ['speed', 'Speed', 'number', '10', 'narrow'],
]
},
{
- id: 'combat', label: 'Combat',
- detect: function(d) { return d.attack_type || d.attack || d.attack_bonus || d.max_hit; },
+ id: 'combat', label: 'Combat', path: 'combat',
+ detect: function(d) { return d.combat; },
fields: [
- ['attack_type', 'Attack Type', 'select', 'stab|slash|crush|ranged|science'],
- ['attack', 'Attack', 'number', '5', 'narrow'],
- ['attack_bonus', 'Attack Bonus', 'number', '0', 'narrow'],
- ['max_hit', 'Max Hit', 'number', '3', 'narrow'],
+ ['stats.attack', 'Attack', 'number', '5', 'narrow'],
+ ['stats.strength', 'Strength', 'number', '5', 'narrow'],
+ ['stats.ranged', 'Ranged', 'number', '1', 'narrow'],
+ ['stats.science', 'Science', 'number', '1', 'narrow'],
+ ['stats.speed', 'Speed', 'number', '5', 'narrow'],
+ ['stats.max_melee_hit', 'Max Melee Hit', 'number', '2', 'narrow'],
+ ['stats.max_ranged_hit', 'Max Ranged Hit', 'number', '0', 'narrow'],
+ ['stats.max_science_hit', 'Max Science Hit', 'number', '0', 'narrow'],
+ ['stats.bonuses.attack_bonus', 'Atk Bonus', 'number', '0', 'narrow'],
+ ['stats.bonuses.strength_bonus', 'Str Bonus', 'number', '0', 'narrow'],
+ ['stats.bonuses.ranged_bonus', 'Rng Bonus', 'number', '0', 'narrow'],
+ ['stats.bonuses.ranged_strength_bonus', 'Rng Str Bonus', 'number', '0', 'narrow'],
+ ['stats.bonuses.science_bonus', 'Sci Bonus', 'number', '0', 'narrow'],
+ ['stats.bonuses.science_percent_bonus', 'Sci % Bonus', 'number', '0', 'narrow'],
]
}
];
@@ -129,11 +138,15 @@ function renderCard(sec, data) {
h += '</div>';
if (!collapsed) {
h += '<div class="obj-card-body">';
- h += '<div class="obj-card-grid">';
- sec.fields.forEach(function(f) {
- h += renderField(sec, f, data, -1);
- });
- h += '</div>';
+ if (sec.id === 'combat') {
+ h += renderHazardCombatCard(data);
+ } else {
+ h += '<div class="obj-card-grid">';
+ sec.fields.forEach(function(f) {
+ h += renderField(sec, f, data, -1);
+ });
+ h += '</div>';
+ }
h += '</div>';
}
h += '</div>';
@@ -158,7 +171,9 @@ function removeSection(id) {
var sec = HAZARD_SECTIONS.find(function(s) { return s.id === id; });
if (!sec) return;
ced_syncDOMToData(hazardData);
- if (sec.fields) sec.fields.forEach(function(f) { delete hazardData[f[0]]; });
+ if (sec.path) {
+ delete hazardData[sec.path];
+ }
delete addedSections[id];
renderHazardEditor(hazardID, hazardData);
}
@@ -171,10 +186,15 @@ function addSection() {
if (!sec) return;
if (id === 'combat') {
- hazardData.attack_type = '';
- hazardData.attack = 0;
- hazardData.attack_bonus = 0;
- hazardData.max_hit = 0;
+ hazardData.combat = {
+ attack_types: ['crush'],
+ stats: {
+ attack: 1, strength: 0, ranged: 0, science: 0,
+ speed: 5,
+ max_melee_hit: 0, max_ranged_hit: 0, max_science_hit: 0,
+ bonuses: {attack_bonus:0, strength_bonus:0, ranged_bonus:0, ranged_strength_bonus:0, science_bonus:0, science_percent_bonus:0}
+ }
+ };
}
addedSections[id] = true;
expandedCards[id] = true;
@@ -200,9 +220,16 @@ function saveHazard() {
});
}
+ if (sec.id === 'combat' && document.getElementById('hz_atktype')) {
+ sectionObj['attack_types'] = ced_collectAtkType('hz_atktype');
+ hasValues = true;
+ }
+
if (sec.always) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
- } else if (hasValues) {
+ } else if (hasValues && sec.path) {
+ out[sec.path] = ced_unflattenObj(sectionObj);
+ } else if (hasValues && !sec.path) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
}
});
@@ -271,3 +298,38 @@ function duplicateHazard() {
loadHazardEditor(newID);
}).catch(function(e) { notify('Duplicate failed: ' + e.message, 'error'); });
}
+
+function renderHazardCombatCard(data) {
+ var sec = HAZARD_SECTIONS.find(function(s) { return s.id === 'combat'; });
+ if (!sec) return '';
+ var byKey = {};
+ sec.fields.forEach(function(f) { byKey[f[0]] = f; });
+
+ var h = ced_renderAtkTypeWidget(data, 'hz_atktype', 'ced_atkPillSelect');
+
+ h += '<div class="obj-inline-group">';
+ h += '<span class="obj-inline-label">Stats</span>';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ var statKeys = ['stats.attack','stats.strength','stats.ranged','stats.science'];
+ statKeys.forEach(function(k) { h += renderField(sec, byKey[k], data, -1); });
+ h += '</div>';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ h += renderField(sec, byKey['stats.speed'], data, -1);
+ h += '</div>';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ var maxKeys = ['stats.max_melee_hit','stats.max_ranged_hit','stats.max_science_hit'];
+ maxKeys.forEach(function(k) { h += renderField(sec, byKey[k], data, -1); });
+ h += '</div>';
+ h += '</div>';
+
+ h += '<div class="obj-inline-group">';
+ h += '<span class="obj-inline-label">Bonuses</span>';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ var bonusKeys = ['stats.bonuses.attack_bonus','stats.bonuses.strength_bonus','stats.bonuses.ranged_bonus',
+ 'stats.bonuses.ranged_strength_bonus','stats.bonuses.science_bonus','stats.bonuses.science_percent_bonus'];
+ bonusKeys.forEach(function(k) { h += renderField(sec, byKey[k], data, -1); });
+ h += '</div>';
+ h += '</div>';
+
+ return h;
+}
diff --git a/internal/admin/static/mobeditor.js b/internal/admin/static/mobeditor.js
index 3934fcd..10b256e 100644
--- a/internal/admin/static/mobeditor.js
+++ b/internal/admin/static/mobeditor.js
@@ -22,7 +22,6 @@ var MOB_SECTIONS = [
id: 'combat', label: 'Combat Stats', path: 'combat',
detect: function(d) { return d.combat; },
fields: [
- ['kind', 'Kind', 'select', 'combat|task'],
['aggressive', 'Aggressive', 'checkbox'],
['respawn_ticks', 'Respawn Ticks', 'number', '30', 'narrow'],
['stats.hp', 'HP', 'number', '10', 'narrow'],
@@ -46,7 +45,7 @@ var MOB_SECTIONS = [
['stats.defenses.crush_defense', 'Crush Def', 'number', '0', 'narrow'],
['stats.defenses.science_defense', 'Sci Def', 'number', '0', 'narrow'],
['stats.defenses.ranged_defense', 'Rng Def', 'number', '0', 'narrow'],
- ['stats.defenses.weakness', 'Weakness', 'select', '|bio|eco|hydro|solar|chaos'],
+ ['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'],
@@ -211,6 +210,7 @@ function renderMobEditor(id, data) {
$('#editorMain').innerHTML = html;
ced_setupSearchFields();
setupMobProtectedToggle();
+ applyTaskVisibility();
MOB_SECTIONS.forEach(function(sec) {
if (sec.id === 'talk' && data.talk && data.talk.nodes) {
@@ -248,6 +248,8 @@ function renderMobCard(sec, data) {
h += renderMobCoreCard(data);
} else if (sec.id === 'combat') {
h += renderMobCombatCard(data);
+ } else if (sec.id === 'task') {
+ h += renderMobTaskCard(data);
} else if (sec.id === 'drops') {
h += renderMobDropsCard(data);
} else if (sec.isArray) {
@@ -305,43 +307,21 @@ function renderMobCoreCard(data) {
return h;
}
-// normalizeAttackTypes coerces a mob attack_types value (array) into an array of
-// strings, tolerating a legacy scalar string for display only.
-function normalizeAttackTypes(v) {
- if (Array.isArray(v)) return v.slice();
- if (typeof v === 'string' && v) return [v];
- return [];
-}
-
-// renderMobAttackTypeWidget renders the Atk Type selector: one required melee
-// type (pill: stab/slash/crush) plus optional ranged/science (checkboxes).
-function renderMobAttackTypeWidget(data) {
+function renderMobKindToggle(data) {
var combat = data.combat || {};
- var types = normalizeAttackTypes(combat.attack_types);
- var melee = types.filter(function(t) { return t === 'stab' || t === 'slash' || t === 'crush'; })[0] || 'crush';
- var hasRanged = types.indexOf('ranged') >= 0;
- var hasScience = types.indexOf('science') >= 0;
- var meleeOpts = ['stab','slash','crush'];
- var activeIdx = meleeOpts.indexOf(melee);
- if (activeIdx < 0) activeIdx = 2;
-
+ var kind = combat.kind === 'task' ? 'task' : 'combat';
+ var activeC = kind === 'combat';
var h = '<div class="obj-inline-group">';
- h += '<span class="obj-inline-label">Atk Type</span>';
- h += '<div class="seg-pill seg-pill-3 seg-idx-' + activeIdx + '" id="mob_atktype_pill" style="margin-top:4px">';
- meleeOpts.forEach(function(t, i) {
- h += '<button type="button" class="seg-opt' + (i === activeIdx ? ' seg-active' : '') + '" data-v="' + t + '" onclick="mobAtkPillSelect(\'' + t + '\',this)">' + t + '</button>';
- });
- h += '</div>';
- h += '<div class="obj-card-grid" style="margin-top:4px">';
- h += '<label class="obj-field obj-check obj-narrow"><input type="checkbox" id="mob_atktype_ranged"' + (hasRanged ? ' checked' : '') + '> <span>ranged</span></label>';
- h += '<label class="obj-field obj-check obj-narrow"><input type="checkbox" id="mob_atktype_science"' + (hasScience ? ' checked' : '') + '> <span>science</span></label>';
- h += '</div>';
- h += '</div>';
+ h += '<span class="obj-inline-label">Kind</span>';
+ h += '<div class="seg-pill seg-pill-2 seg-idx-' + (activeC ? 0 : 1) + '" id="mob_kind_pill" style="margin-top:4px">';
+ h += '<button type="button" class="seg-opt' + (activeC ? ' seg-active' : '') + '" data-v="combat" onclick="mobKindPillSelect(\'combat\',this)">Combat</button>';
+ h += '<button type="button" class="seg-opt' + (activeC ? '' : ' seg-active') + '" data-v="task" onclick="mobKindPillSelect(\'task\',this)">Task</button>';
+ h += '</div></div>';
return h;
}
-function mobAtkPillSelect(val, btn) {
- var pill = document.getElementById('mob_atktype_pill');
+function mobKindPillSelect(val, btn) {
+ var pill = document.getElementById('mob_kind_pill');
if (!pill) return;
var opts = pill.querySelectorAll('.seg-opt');
var idx = -1;
@@ -354,23 +334,25 @@ function mobAtkPillSelect(val, btn) {
}
});
pill.className = pill.className.replace(/seg-idx-\d/g, 'seg-idx-' + idx);
+ if (val === 'task') {
+ if (!mobData.combat) mobData.combat = {};
+ mobData.combat.kind = 'task';
+ if (!mobData.task) mobData.task = {verb:'work', progress_noun:'construction', complete_message:'The work is finished.'};
+ addedSections.task = true;
+ expandedCards.task = true;
+ } else {
+ if (mobData.combat) mobData.combat.kind = 'combat';
+ delete mobData.task;
+ delete addedSections.task;
+ }
+ renderCurrent();
}
-// collectMobAttackType reads the Atk Type widget into an array: the selected
-// melee type first, then any optional ranged/science types.
-function collectMobAttackType() {
- var melee = 'crush';
- var pill = document.getElementById('mob_atktype_pill');
- if (pill) {
- var active = pill.querySelector('.seg-opt.seg-active');
- if (active) melee = active.getAttribute('data-v');
- }
- var out = [melee];
- var rng = document.getElementById('mob_atktype_ranged');
- var sci = document.getElementById('mob_atktype_science');
- if (rng && rng.checked) out.push('ranged');
- if (sci && sci.checked) out.push('science');
- return out;
+function collectMobKind() {
+ var pill = document.getElementById('mob_kind_pill');
+ if (!pill) return 'combat';
+ var active = pill.querySelector('.seg-opt.seg-active');
+ return active ? active.getAttribute('data-v') : 'combat';
}
function renderMobCombatCard(data) {
@@ -379,28 +361,43 @@ function renderMobCombatCard(data) {
var byKey = {};
sec.fields.forEach(function(f) { byKey[f[0]] = f; });
var h = '<div class="obj-card-grid" style="margin-top:6px">';
- h += renderMobField(sec, byKey['kind'], data, -1);
- h += renderMobField(sec, byKey['aggressive'], data, -1);
+ h += renderMobKindToggle(data);
h += renderMobField(sec, byKey['respawn_ticks'], data, -1);
+ h += '<div class="mob-task-hide" style="display:contents">';
+ h += renderMobField(sec, byKey['aggressive'], data, -1);
+ h += '</div>';
h += '</div>';
- h += renderMobAttackTypeWidget(data);
+ h += '<div class="mob-task-hide" id="mob_atktype_wrap">';
+ h += ced_renderAtkTypeWidget(data, 'mob_atktype', 'ced_atkPillSelect');
+ h += '</div>';
h += '<div class="obj-inline-group">';
h += '<span class="obj-inline-label">Stats</span>';
h += '<div class="obj-card-grid" style="margin-top:4px">';
- var statKeys = ['stats.hp','stats.attack','stats.strength','stats.defense','stats.ranged','stats.science'];
- statKeys.forEach(function(k) { h += renderMobField(sec, byKey[k], data, -1); });
+ h += renderMobField(sec, byKey['stats.hp'], data, -1);
+ h += renderMobField(sec, byKey['stats.defense'], data, -1);
h += '</div>';
+ h += '<div class="mob-task-hide" style="display:contents">';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ var atkStatKeys = ['stats.attack','stats.strength','stats.ranged','stats.science'];
+ atkStatKeys.forEach(function(k) { h += renderMobField(sec, byKey[k], data, -1); });
+ h += '</div>';
+ h += '</div>';
+ h += '<div class="mob-task-hide" style="display:contents">';
h += '<div class="obj-card-grid" style="margin-top:4px">';
h += renderMobField(sec, byKey['stats.speed'], data, -1);
h += '</div>';
+ h += '</div>';
+ h += '<div class="mob-task-hide" style="display:contents">';
h += '<div class="obj-card-grid" style="margin-top:4px">';
var statKeys3 = ['stats.max_melee_hit','stats.max_ranged_hit','stats.max_science_hit'];
statKeys3.forEach(function(k) { h += renderMobField(sec, byKey[k], data, -1); });
h += '</div>';
h += '</div>';
+ h += '</div>';
+ h += '<div class="mob-task-hide" id="mob_bonuses_wrap">';
h += '<div class="obj-inline-group">';
h += '<span class="obj-inline-label">Bonuses</span>';
h += '<div class="obj-card-grid" style="margin-top:4px">';
@@ -409,6 +406,7 @@ function renderMobCombatCard(data) {
bonusKeys.forEach(function(k) { h += renderMobField(sec, byKey[k], data, -1); });
h += '</div>';
h += '</div>';
+ h += '</div>';
h += '<div class="obj-inline-group">';
h += '<span class="obj-inline-label">Defenses</span>';
@@ -438,6 +436,20 @@ function renderMobCombatCard(data) {
return h;
}
+function renderMobTaskCard(data) {
+ var sec = MOB_SECTIONS.find(function(s) { return s.id === 'task'; });
+ if (!sec) return '';
+ var byKey = {};
+ sec.fields.forEach(function(f) { byKey[f[0]] = f; });
+ var h = '<p style="color:#888;font-size:11px;margin:0 0 8px 0;line-height:1.5">Task mobs can be attacked but do not fight back. The Verb and Progress Noun appear in combat messages. Complete Message prints when the task is finished.</p>';
+ h += '<div class="obj-card-grid" style="margin-top:6px">';
+ h += renderMobField(sec, byKey['verb'], data, -1);
+ h += renderMobField(sec, byKey['progress_noun'], data, -1);
+ h += '</div>';
+ h += renderMobField(sec, byKey['complete_message'], data, -1, null, 'width:100%');
+ return h;
+}
+
// setupMobProtectedToggle hides the entire Combat card when Protected is checked.
function setupMobProtectedToggle() {
var sec = MOB_SECTIONS.find(function(s) { return s.id === 'core'; });
@@ -457,6 +469,12 @@ function setupMobProtectedToggle() {
apply();
}
+function applyTaskVisibility() {
+ var isTask = mobData && mobData.combat && mobData.combat.kind === 'task';
+ var hidden = document.querySelectorAll('.mob-task-hide');
+ hidden.forEach(function(el) { el.style.display = isTask ? 'none' : ''; });
+}
+
function renderMobField(sec, f, data, idx, subPath, optStyle) {
return ced_renderField(sec, f, data, idx, subPath, optStyle, cardPath, fieldID, getVal);
}
@@ -728,6 +746,9 @@ function removeMobSection(id) {
if (sec.inline) sec.inline.forEach(function(il) { if (il.key) delete mobData[il.key]; });
if (sec.subtables) sec.subtables.forEach(function(st) { delete mobData[st.key]; });
}
+ if (id === 'task' && mobData.combat && mobData.combat.kind === 'task') {
+ mobData.combat.kind = 'combat';
+ }
delete addedSections[id];
renderMobEditor(mobID, mobData);
}
@@ -805,22 +826,6 @@ function addMobLootRow(cardID, subKey, kind) {
renderCurrent();
}
-// ---- Nested object helpers ----
-
-function unflattenObj(obj) {
- var result = {};
- Object.keys(obj).forEach(function(key) {
- var parts = key.split('.');
- var current = result;
- for (var i = 0; i < parts.length - 1; i++) {
- if (!current[parts[i]]) current[parts[i]] = {};
- current = current[parts[i]];
- }
- current[parts[parts.length - 1]] = obj[key];
- });
- return result;
-}
-
// ---- Save ----
function saveMob() {
@@ -874,9 +879,20 @@ function saveMob() {
hasValues = ced_saveSectionFields(sec, sectionObj, cardPath, fieldID) || hasValues;
}
- if (sec.id === 'combat' && document.getElementById('mob_atktype_pill')) {
- sectionObj['attack_types'] = collectMobAttackType();
+ if (sec.id === 'combat') {
+ sectionObj['kind'] = collectMobKind();
hasValues = true;
+ if (sectionObj['kind'] !== 'task' && document.getElementById('mob_atktype')) {
+ sectionObj['attack_types'] = ced_collectAtkType('mob_atktype');
+ }
+ if (sectionObj['kind'] === 'task') {
+ var taskStrip = ['aggressive',
+ 'stats.attack','stats.strength','stats.ranged','stats.science',
+ 'stats.max_melee_hit','stats.max_ranged_hit','stats.max_science_hit',
+ 'stats.bonuses.attack_bonus','stats.bonuses.strength_bonus','stats.bonuses.science_bonus',
+ 'stats.bonuses.science_percent_bonus','stats.bonuses.ranged_bonus','stats.bonuses.ranged_strength_bonus'];
+ taskStrip.forEach(function(k) { delete sectionObj[k]; });
+ }
}
if (sec.subtables) {
@@ -901,7 +917,7 @@ function saveMob() {
if (sec.always) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
} else if (hasValues && sec.path) {
- out[sec.path] = unflattenObj(sectionObj);
+ out[sec.path] = ced_unflattenObj(sectionObj);
} else if (hasValues && !sec.path) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
}