diff --git a/index.js b/index.js index 59179d8..f79e934 100644 --- a/index.js +++ b/index.js @@ -168,16 +168,55 @@ function copyToClipboard(text) { } } +function setPrestige(data, key, value) { + for (const [k, entry] of Object.entries(data.prestige || {})) { + if (k.toLowerCase() === key.toLowerCase()) { + const old = entry.count ?? 0; + entry.count = value; + return ` ${k}: ${old} -> ${value}`; + } + } + return null; +} + +function setResource(data, key, value) { + // Check prestige currencies first + const prestigeResult = setPrestige(data, key, value); + if (prestigeResult) return prestigeResult; + + const res = (data.resource || {})[key]; + if (!res) { + for (const [k, r] of Object.entries(data.resource || {})) { + if (k.toLowerCase() === key.toLowerCase() || (r.name || "").toLowerCase() === key.toLowerCase()) { + const old = r.amount ?? 0; + r.amount = value; + return ` ${r.name || k}: ${Math.floor(old)} -> ${value}`; + } + } + return null; + } + const old = res.amount ?? 0; + res.amount = value; + return ` ${res.name || key}: ${Math.floor(old)} -> ${value}`; +} + function main() { const args = process.argv.slice(2); const flags = new Set(); const positional = []; let craftedValue = null; let onlyFilter = null; + const setValues = []; // [{key, value}] for (const arg of args) { if (arg.startsWith("--set-crafted=")) { craftedValue = Number(arg.split("=")[1]); + } else if (arg.startsWith("--set=")) { + const parts = arg.slice("--set=".length); + const eqIdx = parts.lastIndexOf("="); + if (eqIdx > 0) { + setValues.push({ key: parts.slice(0, eqIdx), value: Number(parts.slice(eqIdx + 1)) }); + } } else if (arg.startsWith("--only=")) { onlyFilter = new Set(arg.slice("--only=".length).split(",").map(s => s.trim().toLowerCase())); } else if (arg.startsWith("--")) { @@ -187,7 +226,7 @@ function main() { } } - const hasAction = flags.has("--max-resources") || flags.has("--max-time") || flags.has("--max-geology") || flags.has("--max-soldiers") || flags.has("--list") || craftedValue !== null; + const hasAction = flags.has("--max-resources") || flags.has("--max-time") || flags.has("--max-geology") || flags.has("--max-soldiers") || flags.has("--list") || craftedValue !== null || setValues.length > 0; if (flags.has("--help")) { console.log(`Usage: node index.js [options] [save-string] @@ -197,6 +236,7 @@ Running with no flags launches interactive mode. Options: --list List all resources in the save with current values --max-resources Set all capped resources to their max + --set=key=N Set a specific resource to N (e.g. --set=Plasmid=100) --set-crafted=N Set all unlimited (crafted) resources to N --only=a,b,c Only affect listed resources (comma-separated names or keys) --max-soldiers Fill garrison to max and heal all wounded @@ -256,6 +296,21 @@ Save string can be passed as argument, piped via stdin, or read from clipboard.` } } + if (setValues.length > 0) { + for (const { key, value } of setValues) { + if (isNaN(value)) { + console.error(`Invalid value for ${key}. Must be a number.`); + continue; + } + const result = setResource(data, key, value); + if (result) { + console.log(`Set resource:\n${result}`); + } else { + console.error(`Resource "${key}" not found in save.`); + } + } + } + if (craftedValue !== null) { const changed = setCraftedResources(data, craftedValue, onlyFilter); if (changed.length > 0) { @@ -345,6 +400,7 @@ async function interactiveMode() { message: "What would you like to do?", choices: [ { value: "max-resources", name: "Max capped resources" }, + { value: "set-resource", name: "Set a specific resource" }, { value: "set-crafted", name: "Set crafted resources" }, { value: "max-soldiers", name: "Max soldiers & heal wounded" }, { value: "max-geology", name: "Max geology bonuses" }, @@ -427,6 +483,47 @@ async function interactiveMode() { continue; } + if (action === "set-resource") { + const prestige = Object.entries(data.prestige || {}) + .filter(([, p]) => (p.count ?? 0) > 0) + .map(([key, p]) => ({ + value: `prestige:${key}`, + name: `${key} (${p.count}) [prestige]`, + })); + const resources = Object.entries(data.resource || {}) + .filter(([, r]) => (r.amount ?? 0) > 0 || (r.max ?? 0) !== 0) + .map(([key, r]) => ({ + value: `resource:${key}`, + name: `${r.name || key} (${Math.floor(r.amount ?? 0)}${r.max > 0 ? ` / ${r.max}` : ""})`, + })); + const choices = [...prestige, ...resources]; + if (choices.length === 0) { + console.log("No resources found."); + continue; + } + const selected = await select({ + message: "Which resource?", + choices, + }); + const [type, resKey] = selected.split(":"); + const label = type === "prestige" ? resKey : (data.resource[resKey].name || resKey); + const value = await input({ + message: `Set ${label} to what value?`, + validate: (v) => { + const n = Number(v); + return !isNaN(n) && n >= 0 ? true : "Enter a non-negative number"; + }, + }); + const result = type === "prestige" + ? setPrestige(data, resKey, Number(value)) + : setResource(data, resKey, Number(value)); + if (result) { + console.log(`Set resource:\n${result}`); + modified = true; + } + continue; + } + if (action === "set-crafted") { const choices = getResourceChoices(data, "crafted"); if (choices.length === 0) {