Add --list command and --only filter for targeting specific resources

--list shows all resources grouped by type (capped, crafted, special, locked).
--only=a,b,c filters --max-resources and --set-crafted to named resources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Julian Tabel
2026-02-25 16:46:16 +01:00
parent ebbe5da281
commit 1d0404cd36
2 changed files with 82 additions and 5 deletions

View File

@@ -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 |

View File

@@ -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));