diff --git a/README.md b/README.md index 6bf28c9..3dcb99e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,9 @@ npm install The tool reads save data from your **clipboard** by default (or from stdin/argument), applies edits, and copies the result back to the clipboard. ```bash +# List all resources and their current values +node index.js --list + # Max all capped resources node index.js --max-resources @@ -24,6 +27,12 @@ node index.js --set-crafted=100000 # Combine both node index.js --max-resources --set-crafted=100000 +# Max only specific resources +node index.js --max-resources --only=food,stone,iron + +# Set specific crafted resources to 50,000 +node index.js --set-crafted=50000 --only=plywood,brick + # Read from stdin instead of clipboard node index.js --max-resources < save.txt @@ -35,8 +44,10 @@ node index.js --max-resources --no-copy | Flag | Description | |------|-------------| +| `--list` | List all resources in the save, grouped by type (capped, crafted, special, locked) | | `--max-resources` | Set all capped resources (`max > 0`) to their max | | `--set-crafted=N` | Set all unlimited/crafted resources (`max == -1`) to N | +| `--only=a,b,c` | Only affect listed resources (comma-separated, case-insensitive). Matches resource names (e.g. `Food`) or internal keys (e.g. `food`). Applies to `--max-resources` and `--set-crafted`. | | `--no-copy` | Print the edited save to stdout instead of clipboard | | `--help` | Show help | diff --git a/index.js b/index.js index 892f72e..7805ea0 100644 --- a/index.js +++ b/index.js @@ -14,9 +14,16 @@ function encodeSave(data) { return LZString.compressToBase64(JSON.stringify(data)); } -function maxResources(data) { +function matchesFilter(key, res, filter) { + if (!filter) return true; + const name = (res.name || key).toLowerCase(); + return filter.has(key.toLowerCase()) || filter.has(name); +} + +function maxResources(data, filter) { const changed = []; for (const [key, res] of Object.entries(data.resource || {})) { + if (!matchesFilter(key, res, filter)) continue; const max = res.max ?? 0; const amount = res.amount ?? 0; if (max > 0 && amount < max) { @@ -28,9 +35,10 @@ function maxResources(data) { return changed; } -function setCraftedResources(data, value) { +function setCraftedResources(data, value, filter) { const changed = []; for (const [key, res] of Object.entries(data.resource || {})) { + if (!matchesFilter(key, res, filter)) continue; if (res.max === -1 && (res.amount ?? 0) < value) { const old = res.amount ?? 0; res.amount = value; @@ -40,6 +48,52 @@ function setCraftedResources(data, value) { return changed; } +function listResources(data) { + const resources = Object.entries(data.resource || {}); + if (resources.length === 0) { + console.log("No resources found in save."); + return; + } + + const capped = []; + const crafted = []; + const special = []; + const locked = []; + + for (const [key, res] of resources) { + const name = res.name || key; + const amount = res.amount ?? 0; + const max = res.max ?? 0; + + if (max > 0) { + capped.push(` ${name} (${key}): ${Math.floor(amount)} / ${max}`); + } else if (max === -1) { + crafted.push(` ${name} (${key}): ${Math.floor(amount)}`); + } else if (max === -2) { + special.push(` ${name} (${key}): ${Math.floor(amount)}`); + } else { + locked.push(` ${name} (${key})`); + } + } + + if (capped.length > 0) { + console.log(`Capped resources (${capped.length}):`); + capped.forEach((l) => console.log(l)); + } + if (crafted.length > 0) { + console.log(`Crafted/unlimited resources (${crafted.length}):`); + crafted.forEach((l) => console.log(l)); + } + if (special.length > 0) { + console.log(`Special resources (${special.length}):`); + special.forEach((l) => console.log(l)); + } + if (locked.length > 0) { + console.log(`Locked/unavailable resources (${locked.length}):`); + locked.forEach((l) => console.log(l)); + } +} + function setGeology(data) { // Max bonus depends on White Hole achievement: top = 30 + level * 5 const whLevel = data.stats?.achieve?.whitehole?.l ?? 0; @@ -92,10 +146,13 @@ function main() { const flags = new Set(); const positional = []; let craftedValue = null; + let onlyFilter = null; for (const arg of args) { if (arg.startsWith("--set-crafted=")) { craftedValue = Number(arg.split("=")[1]); + } else if (arg.startsWith("--only=")) { + onlyFilter = new Set(arg.slice("--only=".length).split(",").map(s => s.trim().toLowerCase())); } else if (arg.startsWith("--")) { flags.add(arg); } else { @@ -103,14 +160,16 @@ function main() { } } - const hasAction = flags.has("--max-resources") || flags.has("--max-time") || flags.has("--max-geology") || craftedValue !== null; + const hasAction = flags.has("--max-resources") || flags.has("--max-time") || flags.has("--max-geology") || flags.has("--list") || craftedValue !== null; if (flags.has("--help") || !hasAction) { console.log(`Usage: node index.js [options] [save-string] Options: + --list List all resources in the save with current values --max-resources Set all capped resources to their max --set-crafted=N Set all unlimited (crafted) resources to N + --only=a,b,c Only affect listed resources (comma-separated names or keys) --max-geology Set 4 geology resource bonuses at max values --max-time Set accelerated time (AT) to 8 hours --no-copy Print result instead of copying to clipboard @@ -144,8 +203,15 @@ Save string can be passed as argument, piped via stdin, or read from clipboard.` const data = decodeSave(input); + if (flags.has("--list")) { + listResources(data); + if (!flags.has("--max-resources") && !flags.has("--max-geology") && !flags.has("--max-time") && craftedValue === null) { + process.exit(0); + } + } + if (flags.has("--max-resources")) { - const changed = maxResources(data); + const changed = maxResources(data, onlyFilter); if (changed.length > 0) { console.log(`Maxed ${changed.length} resources:`); changed.forEach((line) => console.log(line)); @@ -170,7 +236,7 @@ Save string can be passed as argument, piped via stdin, or read from clipboard.` } if (craftedValue !== null) { - const changed = setCraftedResources(data, craftedValue); + const changed = setCraftedResources(data, craftedValue, onlyFilter); if (changed.length > 0) { console.log(`Set ${changed.length} crafted resources to ${craftedValue}:`); changed.forEach((line) => console.log(line));