aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/static/mobeditor.js
diff options
context:
space:
mode:
Diffstat (limited to 'internal/admin/static/mobeditor.js')
-rw-r--r--internal/admin/static/mobeditor.js81
1 files changed, 73 insertions, 8 deletions
diff --git a/internal/admin/static/mobeditor.js b/internal/admin/static/mobeditor.js
index 3d6f4d4..4895c6f 100644
--- a/internal/admin/static/mobeditor.js
+++ b/internal/admin/static/mobeditor.js
@@ -22,16 +22,18 @@ var MOB_SECTIONS = [
detect: function(d) { return d.combat; },
fields: [
['kind', 'Kind', 'select', 'combat|task'],
+ ['aggressive', 'Aggressive', 'checkbox'],
+ ['respawn_ticks', 'Respawn Ticks', 'number', '', 'narrow'],
['stats.hp', 'HP', 'number', '', 'narrow'],
['stats.attack', 'Attack', 'number', '', 'narrow'],
['stats.strength', 'Strength', 'number', '', 'narrow'],
['stats.defense', 'Defense', 'number', '', 'narrow'],
['stats.ranged', 'Ranged', 'number', '', 'narrow'],
['stats.science', 'Science', 'number', '', 'narrow'],
- ['stats.attack_type', 'Atk Type', 'select', 'stab|slash|crush|ranged|science'],
['stats.speed', 'Speed', 'number', '', 'narrow'],
- ['stats.aggressive', 'Aggressive', 'checkbox'],
- ['stats.respawn_ticks', 'Respawn Ticks', 'number', '', 'narrow'],
+ ['stats.max_melee_hit', 'Max Melee Hit', 'number', '', 'narrow'],
+ ['stats.max_ranged_hit', 'Max Ranged Hit', 'number', '', 'narrow'],
+ ['stats.max_science_hit', 'Max Science Hit', 'number', '', 'narrow'],
['stats.bonuses.attack_bonus', 'Atk Bonus', 'number', '', 'narrow'],
['stats.bonuses.strength_bonus', 'Str Bonus', 'number', '', 'narrow'],
['stats.bonuses.science_bonus', 'Sci Bonus', 'number', '', 'narrow'],
@@ -44,6 +46,7 @@ var MOB_SECTIONS = [
['stats.defenses.science_defense', 'Sci Def', 'number', '', 'narrow'],
['stats.defenses.ranged_defense', 'Rng Def', 'number', '', 'narrow'],
['stats.defenses.weakness', 'Weakness', 'text'],
+ ['stats.defenses.weakness_percent', 'Weakness %', 'number', '', 'narrow'],
['assassin_level', 'Assassin Lvl', 'number', '', 'narrow'],
['finishing_blow', 'Finishing Blow', 'search', '', '', null, 'items'],
['damage_without', 'Damage Without', 'search', '', '', null, 'items'],
@@ -271,6 +274,52 @@ 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 (radio: stab/slash/crush) plus optional ranged/science (checkboxes).
+function renderMobAttackTypeWidget(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 h = '<div class="obj-inline-group">';
+ h += '<span class="obj-inline-label">Atk Type</span>';
+ h += '<div class="obj-card-grid" style="margin-top:4px">';
+ ['stab','slash','crush'].forEach(function(m) {
+ h += '<label class="obj-field obj-check obj-narrow"><input type="radio" name="mob_atktype_melee" value="' + m + '"' + (melee === m ? ' checked' : '') + '> <span>' + m + '</span></label>';
+ });
+ 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>';
+ return h;
+}
+
+// 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 r = document.querySelector('input[name="mob_atktype_melee"]:checked');
+ if (r) melee = r.value;
+ 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 renderMobCombatCard(data) {
var sec = MOB_SECTIONS.find(function(s) { return s.id === 'combat'; });
if (!sec) return '';
@@ -278,8 +327,12 @@ function renderMobCombatCard(data) {
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 += renderMobField(sec, byKey['respawn_ticks'], data, -1);
h += '</div>';
+ h += renderMobAttackTypeWidget(data);
+
h += '<div class="obj-inline-group">';
h += '<span class="obj-inline-label">Stats</span>';
h += '<div class="obj-card-grid" style="margin-top:4px">';
@@ -287,8 +340,11 @@ function renderMobCombatCard(data) {
statKeys.forEach(function(k) { h += renderMobField(sec, byKey[k], data, -1); });
h += '</div>';
h += '<div class="obj-card-grid" style="margin-top:4px">';
- var statKeys2 = ['stats.attack_type','stats.speed','stats.aggressive','stats.respawn_ticks'];
- statKeys2.forEach(function(k) { h += renderMobField(sec, byKey[k], data, -1); });
+ h += renderMobField(sec, byKey['stats.speed'], data, -1);
+ h += '</div>';
+ 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>';
@@ -310,6 +366,7 @@ function renderMobCombatCard(data) {
h += '</div>';
h += '<div class="obj-card-grid" style="margin-top:4px">';
h += renderMobField(sec, byKey['stats.defenses.weakness'], data, -1);
+ h += renderMobField(sec, byKey['stats.defenses.weakness_percent'], data, -1);
h += '</div>';
h += '</div>';
@@ -523,12 +580,15 @@ function mobAddSection() {
if (id === 'combat') {
mobData[sec.path] = {
kind: 'combat',
+ aggressive: false,
+ attack_types: ['crush'],
+ respawn_ticks: 30,
stats: {
hp: 1, attack: 1, strength: 1, defense: 1,
- attack_type: 'crush', speed: 5,
- aggressive: false, respawn_ticks: 30,
+ speed: 5,
+ max_melee_hit: 0, max_ranged_hit: 0, max_science_hit: 0,
bonuses: {attack_bonus:0, strength_bonus:0, science_bonus:0, science_percent_bonus:0, ranged_bonus:0, ranged_strength_bonus:0},
- defenses: {stab_defense:0, slash_defense:0, crush_defense:0, science_defense:0, ranged_defense:0}
+ defenses: {stab_defense:0, slash_defense:0, crush_defense:0, science_defense:0, ranged_defense:0, weakness_percent:0}
},
size: 'small'
};
@@ -610,6 +670,11 @@ function saveMob() {
hasValues = ced_saveSectionFields(sec, sectionObj, mobCardPath, mobFieldID) || hasValues;
}
+ if (sec.id === 'combat' && document.querySelector('input[name="mob_atktype_melee"]')) {
+ sectionObj['attack_types'] = collectMobAttackType();
+ hasValues = true;
+ }
+
if (sec.subtables) {
sec.subtables.forEach(function(st) {
if (ced_saveSubtable(sec, st, sectionObj, mobCardPath, mobFieldIDSub)) hasValues = true;