var techData = null; var techID = null; var expandedCards = {}; var cardWidths = {}; var TECH_SECTIONS = [ { id: 'core', label: 'Core', always: true, fields: [ ['name', 'Name', 'text', 'Protect from Melee'], ['level', 'Level', 'number', '37', 'narrow'], ['drain_rate', 'Drain Rate', 'number', '0.5', 'narrow'], ['category', 'Category', 'select', '|accuracy|combo|defense|protection|ranged|science|strength|utility'], ['group', 'Group', 'select', '|accuracy_tier|defense_tier|protection|ranged_tier|regen_tier|science_tier|strength_tier'], ] }, { id: 'effects', label: 'Effects', always: true, path: 'effects', fields: [ ['accuracy_percent', 'Accuracy %', 'number', '5', 'narrow'], ['strength_percent', 'Strength %', 'number', '5', 'narrow'], ['defense_percent', 'Defense %', 'number', '5', 'narrow'], ['ranged_percent', 'Ranged %', 'number', '5', 'narrow'], ['science_percent', 'Science %', 'number', '5', 'narrow'], ['damage_reduction', 'Damage Reduction', 'number', '40', 'narrow'], ['hp_regen_multi', 'HP Regen Multi', 'number', '2', 'narrow'], ['preserve_drain', 'Preserve Drain', 'number', '1', 'narrow'], ['retribution_pct', 'Retribution %', 'number', '25', 'narrow'], ['protect_melee', 'Protect Melee', 'checkbox'], ['protect_ranged', 'Protect Ranged', 'checkbox'], ['protect_science', 'Protect Science', 'checkbox'], ] } ]; function initTechEditor() { editorType = 'techs'; editorFields = []; loadList(); if (window.location.hash) loadTechEditor(window.location.hash.substring(1)); } function cardPath(sec) { return sec.path || ''; } function getVal(data, sec, key) { return ced_getVal(data, sec, key); } function fieldID(sec, key, idx) { return ced_fieldID(sec, key, idx); } function setupSearchFields() { ced_setupSearchFields(); } function collectFieldValue(el, type) { return ced_collectFieldValue(el, type); } function loadTechEditor(id) { techID = id; currentID = id; renderList(''); window.location.hash = id; API.get('/api/techs/' + encodeURIComponent(id)).then(function(data) { techData = data; renderTechEditor(id, data); }).catch(function(e) { $('#editorMain').innerHTML = '
Failed to load: ' + esc(e.message) + '
'; }); } function loadItem(id) { loadTechEditor(id); } function renderTechEditor(id, data) { var html = renderRenameableHeader('Tech', id); html += 'Deleted
'; loadList(); }).catch(function(e) { notify('Delete failed: ' + e.message, 'error'); }); } function duplicateTech() { var baseID = techID + '_copy'; var newID = baseID; var counter = 2; while (true) { var exists = false; for (var i = 0; i < allIDs.length; i++) { if (allIDs[i] === newID) { exists = true; break; } } if (!exists) break; newID = baseID + '_' + counter; counter++; } var copy = JSON.parse(JSON.stringify(techData)); delete copy._raw; delete copy._path; copy.id = newID; var dir = ''; if (techData._path) { var parts = techData._path.split('/'); var parentDir = parts[parts.length - 2]; if (parentDir !== 'techs') dir = parentDir; } API.post('/api/techs', {id: newID}).then(function() { var putOp = API.put('/api/techs/' + encodeURIComponent(newID), copy); if (dir) { return putOp.then(function() { return API.post('/api/techs/move', {id: newID, dir: dir}); }); } return putOp; }).then(function() { notify('Duplicated as ' + newID, 'success'); updateUndoBar(); loadList(); loadTechEditor(newID); }).catch(function(e) { notify('Duplicate failed: ' + e.message, 'error'); }); }