';
html += '';
html += '';
html += '';
html += '';
html += '
';
$('#editorMain').innerHTML = html;
document.querySelectorAll('details.obj-card').forEach(function(d) {
d.addEventListener('toggle', function() { expandedCards[d.getAttribute('data-card')] = d.open; });
});
setupSearchFields();
}
function renderCurrent() {
ced_syncDOMToData(techData);
if (!techData || !techID) return;
renderTechEditor(techID, techData);
}
function renderCard(sec, data) {
var openAttr = expandedCards[sec.id] === false ? '' : ' open';
var isFull = cardWidths[sec.id] !== undefined ? cardWidths[sec.id] : (sec.fullWidth || false);
var fullClass = isFull ? ' obj-card-full' : '';
var h = '';
h += '';
h += '';
h += '' + sec.label + '';
h += '';
h += '';
h += '
';
if (sec.id === 'core') {
h += renderTechCoreCard(data);
} else if (sec.id === 'effects') {
h += renderTechEffectsCard(data);
} else {
h += '
';
sec.fields.forEach(function(f) {
h += renderField(sec, f, data, -1);
});
h += '
';
}
h += '
';
h += '';
return h;
}
function renderField(sec, f, data, idx, subPath, optStyle) {
return ced_renderField(sec, f, data, idx, subPath, optStyle, cardPath, fieldID, getVal);
}
function toggleCardWidth(id) {
cardWidths[id] = !cardWidths[id];
renderCurrent();
}
// ---- Custom Core card ----
function renderTechCoreCard(data) {
var sec = TECH_SECTIONS.find(function(s) { return s.id === 'core'; });
var fields = sec.fields;
var h = '';
h += '
';
h += renderField(sec, fields[0], data, -1, null, 'flex:1');
h += renderField(sec, fields[1], data, -1);
h += renderField(sec, fields[2], data, -1);
h += '
';
h += '
';
var groupExists = data && data.group !== undefined;
if (groupExists) {
h += '
';
h += renderField(sec, fields[3], data, -1);
h += '';
h += '
';
} else {
h += '
';
h += '';
h += '
';
}
h += '
';
h += '
Only one tech per Group can be active at a time.
';
h += '
Drain rate is applied per tick.
';
return h;
}
function addTechGroup() {
ced_syncDOMToData(techData);
techData.group = '';
renderTechEditor(techID, techData);
}
function removeTechGroup() {
ced_syncDOMToData(techData);
delete techData.group;
renderTechEditor(techID, techData);
}
// ---- Custom Effects card ----
function renderTechEffectsCard(data) {
var sec = TECH_SECTIONS.find(function(s) { return s.id === 'effects'; });
var eff = data.effects || {};
var h = '';
var hasActive = false;
var protectType = null;
if (eff.protect_melee) protectType = 'melee';
else if (eff.protect_ranged) protectType = 'ranged';
else if (eff.protect_science) protectType = 'science';
if (protectType) {
hasActive = true;
var protectIdx = protectType === 'melee' ? 0 : (protectType === 'ranged' ? 1 : 2);
h += '
';
h += '
';
h += '
';
h += '
';
h += 'Protection';
h += '
';
['melee', 'ranged', 'science'].forEach(function(t, i) {
h += '';
});
h += '
';
h += '
';
h += '
';
h += '';
h += '
';
h += '
';
}
sec.fields.forEach(function(f) {
var key = f[0], label = f[1];
var val = eff[key];
if (val === undefined || val === null) return;
if (f[2] === 'checkbox' && !val) return;
if (val === '' || val === 0) return;
hasActive = true;
h += '
';
h += '
';
h += '
';
h += renderField(sec, f, data, -1);
h += '
';
h += '';
h += '
';
h += '
';
});
var inactiveFields = [];
sec.fields.forEach(function(f) {
var key = f[0];
var val = eff[key];
var isSet = val !== undefined && val !== null;
if (f[2] === 'checkbox' && !val) isSet = false;
if (val === '' || val === 0) isSet = false;
if (!isSet) inactiveFields.push(f);
});
if (inactiveFields.length > 0 || !protectType) {
if (hasActive) h += '';
h += '
';
inactiveFields.forEach(function(f) {
var key = f[0], label = f[1], type = f[2];
var dflt = type === 'checkbox' ? true : (parseFloat(f[3]) || 0);
h += '';
});
if (!protectType) {
h += '';
}
h += '
';
}
return h;
}
function addTechEffect(key, dflt) {
ced_syncDOMToData(techData);
if (!techData.effects) techData.effects = {};
techData.effects[key] = dflt;
renderTechEditor(techID, techData);
}
function removeTechEffect(key) {
ced_syncDOMToData(techData);
if (techData.effects) delete techData.effects[key];
renderTechEditor(techID, techData);
}
function addTechProtection() {
ced_syncDOMToData(techData);
if (!techData.effects) techData.effects = {};
techData.effects.protect_melee = true;
techData.effects.damage_reduction = 0.4;
renderTechEditor(techID, techData);
}
function removeTechProtection() {
ced_syncDOMToData(techData);
if (techData.effects) {
delete techData.effects.protect_melee;
delete techData.effects.protect_ranged;
delete techData.effects.protect_science;
}
renderTechEditor(techID, techData);
}
function techProtectPillSelect(val, btn) {
ced_syncDOMToData(techData);
if (!techData.effects) techData.effects = {};
delete techData.effects.protect_melee;
delete techData.effects.protect_ranged;
delete techData.effects.protect_science;
techData.effects['protect_' + val] = true;
var pill = document.getElementById('tech-protect-pill');
if (pill) {
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);
}
}
// ---- Save / Delete / Duplicate ----
function saveTech() {
if (!ced_validateFields(TECH_SECTIONS, fieldID, null)) return;
ced_syncDOMToData(techData);
var out = {};
TECH_SECTIONS.forEach(function(sec) {
var sectionObj = {};
var hasValues = sec.always;
if (sec.fields) {
sec.fields.forEach(function(f) {
var fid = fieldID(sec, f[0]);
var el = document.getElementById(fid);
if (!el) return;
var val = collectFieldValue(el, f[2]);
if (val !== '' && val !== false && val !== 0 && val !== null) hasValues = true;
sectionObj[f[0]] = val;
});
}
if (sec.always && sec.path) {
out[sec.path] = sectionObj;
} else if (sec.always) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
} else if (hasValues && sec.path) {
out[sec.path] = sectionObj;
} else if (hasValues) {
Object.keys(sectionObj).forEach(function(k) { out[k] = sectionObj[k]; });
}
});
if (techData.effects) {
if (techData.effects.protect_melee || techData.effects.protect_ranged || techData.effects.protect_science) {
if (!out.effects) out.effects = {};
if (techData.effects.protect_melee) out.effects.protect_melee = true;
if (techData.effects.protect_ranged) out.effects.protect_ranged = true;
if (techData.effects.protect_science) out.effects.protect_science = true;
}
}
ced_cleanOutput(out);
out.id = techID;
if (out.effects && Object.keys(out.effects).length === 0) delete out.effects;
API.put('/api/techs/' + encodeURIComponent(techID), out).then(function(resp) {
notify('Tech ' + techID + ' saved', 'success');
updateUndoBar();
if (resp && resp._raw) techData._raw = resp._raw;
}).catch(function(e) { notify('Save failed: ' + e.message, 'error'); });
}
function deleteTech() {
if (!confirm('Delete tech "' + techID + '"?')) return;
API.del('/api/techs/' + encodeURIComponent(techID)).then(function() {
notify('Tech ' + techID + ' deleted', 'success');
updateUndoBar();
techID = null;
currentID = null;
techData = null;
$('#editorMain').innerHTML = '
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'); });
}