feat: Doing more polishing (M8b)
This commit is contained in:
+58
-12
@@ -147,8 +147,8 @@ assert.equal(E.advanceDay(s, bal).blocked, "over");
|
||||
];
|
||||
g = fresh(3); E.confirmBudget(g);
|
||||
const op = g.indicators.opinion;
|
||||
for (let i = 0; i < 10 && g.pendingCard?.id !== "start"; i++) { if (g.pending.weeklyCard && !g.pendingCard) E.ensureCard(g, bal, [cards[0]]); if (!g.pendingCard) E.advanceDay(g, bal); }
|
||||
assert.equal(g.pendingCard.id, "start");
|
||||
for (let i = 0; i < 10 && g.inbox[0]?.id !== "start"; i++) { if (g.pending.weeklyCard) E.ensureCard(g, bal, [cards[0]]); if (!g.inbox.length) E.advanceDay(g, bal); }
|
||||
assert.equal(g.inbox[0].id, "start");
|
||||
E.answerCard(g, bal, cards, "yes");
|
||||
assert.equal(g.indicators.opinion, op + 5);
|
||||
assert.equal(g.economy.taxes.income, 32);
|
||||
@@ -379,22 +379,24 @@ assert.equal(E.advanceDay(s, bal).blocked, "over");
|
||||
|
||||
// content that changed since the save is repaired, not fatal
|
||||
const stale = clone(g);
|
||||
stale.pendingCard = { id: "deleted_card", day: stale.day }; stale.pending.weeklyCard = true;
|
||||
stale.inbox = [{ id: "deleted_card", day: stale.day }]; stale.pending.inboxFull = true;
|
||||
stale.followUps.push({ id: "deleted_card", due: 5 }, { id: cardsAll[0].id, due: 9 });
|
||||
const fixed = E.restoreState(stale, content);
|
||||
assert.equal(fixed.ok, true);
|
||||
assert.equal(fixed.state.pendingCard, null);
|
||||
assert.deepEqual(fixed.state.inbox, []);
|
||||
assert.equal(fixed.state.pending.inboxFull, false);
|
||||
assert.deepEqual(fixed.state.followUps.map((f) => f.id).filter((id) => id === "deleted_card"), []);
|
||||
assert.ok(fixed.state.followUps.some((f) => f.id === cardsAll[0].id));
|
||||
// an alert queue and its pause flag stay consistent
|
||||
const al = clone(g); al.alerts = [{ kind: "coup", day: 10 }]; al.pending.alert = false;
|
||||
assert.equal(E.restoreState(al, content).state.pending.alert, true);
|
||||
|
||||
// a game saved while waiting on a decision comes back waiting on the same decision
|
||||
// a game saved with a proposal in the tray comes back with the same tray, and keeps running
|
||||
const waiting = fresh(32); E.confirmBudget(waiting); E.ensureCard(waiting, bal, cardsAll);
|
||||
const w = E.restoreState(decodeSave(encodeSave(waiting)).state, content).state;
|
||||
assert.equal(w.pendingCard.id, waiting.pendingCard.id);
|
||||
assert.equal(E.advanceDay(w, bal).blocked, "pending");
|
||||
assert.deepEqual(w.inbox, waiting.inbox);
|
||||
assert.equal(w.inbox.length, 1);
|
||||
assert.equal(E.advanceDay(w, bal).advanced, true);
|
||||
|
||||
// storage: slots, autosave, settings, and the fallbacks
|
||||
const mem = new Map();
|
||||
@@ -412,11 +414,13 @@ assert.equal(E.advanceDay(s, bal).blocked, "over");
|
||||
mem.set(KEYS.slot(2), "{not json"); assert.equal(readSave(store, KEYS.slot(2)), null, "corrupt slot reads as empty");
|
||||
mem.set(KEYS.slot(3), JSON.stringify({ nope: 1 })); assert.equal(readSave(store, KEYS.slot(3)), null);
|
||||
|
||||
assert.deepEqual(loadSettings(store), { lang: null, slow: false });
|
||||
saveSettings(store, { lang: "fr", slow: true });
|
||||
assert.deepEqual(loadSettings(store), { lang: "fr", slow: true });
|
||||
assert.deepEqual(loadSettings(store), { lang: null, slow: false, sound: true, volume: 0.6 });
|
||||
saveSettings(store, { lang: "fr", slow: true, sound: false, volume: 0.25 });
|
||||
assert.deepEqual(loadSettings(store), { lang: "fr", slow: true, sound: false, volume: 0.25 });
|
||||
mem.set(KEYS.settings, JSON.stringify({ lang: "de", slow: "yes" }));
|
||||
assert.deepEqual(loadSettings(store), { lang: null, slow: false }, "unknown values are ignored");
|
||||
assert.deepEqual(loadSettings(store), { lang: null, slow: false, sound: true, volume: 0.6 }, "unknown values are ignored");
|
||||
mem.set(KEYS.settings, JSON.stringify({ volume: 7, sound: "no" }));
|
||||
assert.equal(loadSettings(store).volume, 0.6, "an out-of-range volume falls back to the default");
|
||||
|
||||
// no storage at all, a throwing storage, and a full storage: the game keeps going in memory
|
||||
const none = createStorage(null);
|
||||
@@ -433,6 +437,48 @@ assert.equal(E.advanceDay(s, bal).blocked, "over");
|
||||
assert.deepEqual(readSave(angry, KEYS.auto).state, clone(g));
|
||||
}
|
||||
|
||||
// 12. the in-tray: proposals pile up without stopping the clock; the game waits at the limit
|
||||
{
|
||||
const real = JSON.parse(fs.readFileSync(root + "cards/index.json")).files.flatMap((f) => JSON.parse(fs.readFileSync(root + "cards/" + f)));
|
||||
const max = bal.cards.inboxMax;
|
||||
const g = fresh(5); E.confirmBudget(g);
|
||||
let blockedDay = null;
|
||||
for (let i = 0; i < 200 && blockedDay === null; i++) {
|
||||
if (g.pending.review) E.confirmBudget(g);
|
||||
while (g.pending.alert) E.dismissAlert(g);
|
||||
if (g.pending.weeklyCard) E.ensureCard(g, bal, real);
|
||||
if (g.pending.inboxFull) { blockedDay = g.day; break; }
|
||||
E.advanceDay(g, bal);
|
||||
}
|
||||
assert.equal(g.inbox.length, max, "the game waits when the tray holds " + max);
|
||||
assert.equal(blockedDay, (max - 1) * bal.time.daysPerWeek, "the " + max + "th proposal arrives on week " + max);
|
||||
assert.equal(E.advanceDay(g, bal).blocked, "pending");
|
||||
assert.equal(new Set(g.inbox.map((e) => e.id)).size, max, "no proposal twice in the tray");
|
||||
assert.deepEqual(g.inbox.map((e) => e.day), [...g.inbox.map((e) => e.day)].sort((a, b) => a - b), "oldest first");
|
||||
|
||||
// answering the top one frees the clock; answering a chosen one works too
|
||||
const first = g.inbox[0].id, third = g.inbox[2].id;
|
||||
assert.equal(E.answerCard(g, bal, real, "yes").card.id, first);
|
||||
assert.equal(g.pending.inboxFull, false);
|
||||
assert.equal(E.advanceDay(g, bal).advanced, true);
|
||||
assert.equal(E.answerCard(g, bal, real, "no", third).card.id, third);
|
||||
assert.equal(g.inbox.length, max - 2);
|
||||
assert.equal(E.answerCard(g, bal, real, "no", "not_in_tray").ok, false);
|
||||
assert.equal(E.answerCard(g, bal, real, "maybe").ok, false);
|
||||
|
||||
// a card waiting in the tray is not drawn again, and a saved tray survives a round trip
|
||||
const copy = E.restoreState(decodeSave(encodeSave(g)).state, { scenarios: { default: scn }, balance: bal, cards: real });
|
||||
assert.equal(copy.ok, true);
|
||||
assert.deepEqual(copy.state.inbox, g.inbox);
|
||||
// a version-2 save with a pending card becomes a one-card tray
|
||||
const v2 = JSON.parse(JSON.stringify(fresh(6))); v2.version = 2; v2.pendingCard = { id: real[0].id, day: 0 }; v2.pending.weeklyCard = true; delete v2.inbox; delete v2.pending.inboxFull;
|
||||
const up = decodeSave(encodeSave(v2));
|
||||
assert.equal(up.ok, true);
|
||||
assert.deepEqual(up.state.inbox, [{ id: real[0].id, day: 0 }]);
|
||||
assert.equal(up.state.pending.weeklyCard, false);
|
||||
assert.equal(up.state.pendingCard, undefined);
|
||||
}
|
||||
|
||||
// M8: world cycle, growing needs, card conditions on choices, coup from neglect, v1 saves
|
||||
{
|
||||
// the world cycle moves, stays within bounds and is part of the saved state
|
||||
@@ -488,7 +534,7 @@ assert.equal(E.advanceDay(s, bal).blocked, "over");
|
||||
const content = { scenarios: { default: scn }, balance: bal, cards: [] };
|
||||
const v1 = clone(fresh()); delete v1.world; v1.version = 1;
|
||||
const up = decodeSave(encodeSave(v1));
|
||||
assert.equal(up.ok, true); assert.equal(up.state.version, 2); assert.deepEqual(up.state.world, { cycle: 0 });
|
||||
assert.equal(up.ok, true); assert.equal(up.state.version, 3); assert.deepEqual(up.state.world, { cycle: 0 }); assert.deepEqual(up.state.inbox, []);
|
||||
assert.equal(E.restoreState(up.state, content).ok, true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user