Rework backend #1

Merged
robert merged 86 commits from rework-backend into main 2026-07-01 19:29:34 -04:00
Showing only changes of commit 7866dec83b - Show all commits
+37 -29
View File
@@ -18,8 +18,8 @@ const { createWsStorage } = require('../src/storage/ws');
const BACKEND = process.env.BACKEND_URL || 'http://127.0.0.1:4001';
const WS_URL = process.env.BACKEND_WS || BACKEND.replace(/^http/, 'ws') + '/ws';
const ROUNDS = parseInt(process.argv[2], 10) || 100;
const DELAY = parseInt(process.argv[3], 10) || 800;
const ROUNDS = parseInt(process.argv[2], 10) || 10;
const DELAY = parseInt(process.argv[3], 10) || 200;
const APP_ID = process.env.REACT_APP_TRACKER_APP_ID || 'ttrpg-initiative-tracker-default';
const PUB = `artifacts/${APP_ID}/public/data`;
@@ -110,44 +110,52 @@ async function main() {
console.log(`combat started: round ${enc.round}, first=${firstActiveName(enc)}`);
await sleep(DELAY);
// main loop
for (let r = 1; r <= ROUNDS; r++) {
// main loop: ROUNDS = full initiative cycles (each round = all participants act).
const DAMAGERS = ['Fighter', 'Cleric', 'Rogue', 'Wolf', 'Goblin1', 'Goblin2', 'OrcBoss'];
const TARGETS = ['Goblin1', 'Goblin2', 'Wolf', 'OrcBoss', 'Fighter', 'Cleric', 'Rogue', 'Merchant'];
let turnInRound = 0;
let prevRound = enc.round;
let totalTurns = 0;
for (let roundN = 1; roundN <= ROUNDS; roundN++) {
// advance initiative until round counter ticks (full cycle done).
const cap = (enc.participants.length + 1) * 2;
let guard = 0;
while (enc.round < roundN + 1 && guard < cap) {
enc = await storage.getDoc(encounterPath);
const t = nextTurn(enc);
await storage.updateDoc(encounterPath, t.patch);
enc = { ...enc, ...t.patch };
totalTurns++;
turnInRound++;
if (r % 2 === 0) {
enc = await storage.getDoc(encounterPath);
const orc = enc.participants.find(p => p.name === 'OrcBoss' && p.currentHp > 0);
if (orc) {
const h = applyHpChange(enc, orc.id, 'damage', 5);
if (h.patch) { await storage.updateDoc(encounterPath, h.patch); enc = { ...enc, ...h.patch }; }
}
}
if (r % 3 === 0) {
enc = await storage.getDoc(encounterPath);
const cleric = enc.participants.find(p => p.name === 'Cleric' && p.currentHp > 0);
if (cleric) {
const h = applyHpChange(enc, cleric.id, 'heal', 3);
if (h.patch) { await storage.updateDoc(encounterPath, h.patch); enc = { ...enc, ...h.patch }; }
}
}
if (r % 5 === 0) {
enc = await storage.getDoc(encounterPath);
const fighter = enc.participants.find(p => p.name === 'Fighter' && p.currentHp > 0);
if (fighter) {
const c = toggleCondition(enc, fighter.id, 'stunned');
if (c.patch) { await storage.updateDoc(encounterPath, c.patch); enc = { ...enc, ...c.patch }; }
// visible action: current turn actor damages a random living target.
const actorName = firstActiveName(enc);
const livingTargets = enc.participants.filter(
p => p.currentHp > 0 && p.name !== actorName && TARGETS.includes(p.name)
);
if (livingTargets.length > 0 && DAMAGERS.includes(actorName)) {
const tgt = livingTargets[Math.floor(Math.random() * livingTargets.length)];
const dmg = 3 + Math.floor(Math.random() * 8); // 3-10
const h = applyHpChange(enc, tgt.id, 'damage', dmg);
if (h.patch) {
await storage.updateDoc(encounterPath, h.patch);
enc = { ...enc, ...h.patch };
console.log(` ${actorName}${tgt.name} (-${dmg}, hp=${tgt.currentHp - dmg})`);
}
}
enc = await storage.getDoc(encounterPath);
console.log(`round ${r}: current=${firstActiveName(enc)} | round=${enc.round}`);
console.log(` turn ${turnInRound} (round ${enc.round}): ${actorName}`);
await sleep(DELAY);
guard++;
if (!enc.isStarted) { console.log('combat auto-ended'); break; }
}
if (!enc.isStarted) { console.log('combat auto-ended'); break; }
console.log(`--- round ${roundN} complete (${turnInRound} turns total) ---`);
turnInRound = 0;
}
console.log(`replay: ${totalTurns} total turns across ${ROUNDS} rounds`);
// end
enc = await storage.getDoc(encounterPath);