generated from nhcarrigan/template
feat: major content expansion with essence and crystal sinks
- 6 zones (up from 3): Shadow Marshes, Volcanic Depths, Astral Void - 18 bosses (up from 4): 3 per zone with zone-based sequential unlock - 24 quests (up from 9): 3-4 per zone, reorganised by zone - 15 adventurer tiers (up from 10): Shadow Assassin through Divine Champion - 28 equipment pieces (up from 12): boss drops + purchasable with essence/crystals - 24 upgrades (up from 13): crystal-cost upgrades + new adventurer upgrades - 22 achievements (up from 14): new milestones for bosses, quests, gold, armies - Purchasable equipment system: buy items directly with essence or crystals - Crystal-cost upgrades: spend crystals on global and click power boosts - Zone-based boss progression: defeating a zone's last boss unlocks the next zone
This commit is contained in:
@@ -69,7 +69,7 @@ gameRouter.get("/load", async (context) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Backfill new quests and upgrades from defaults (add missing ones)
|
||||
// Backfill new quests, upgrades, zones, and bosses from defaults (add missing ones)
|
||||
const { DEFAULT_QUESTS } = await import("../data/quests.js");
|
||||
const { DEFAULT_UPGRADES } = await import("../data/upgrades.js");
|
||||
const { DEFAULT_ZONES } = await import("../data/zones.js");
|
||||
@@ -82,10 +82,14 @@ gameRouter.get("/load", async (context) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Backfill zoneId on quests that predate the field
|
||||
// Sync zoneId on quests to match current defaults
|
||||
for (const quest of state.quests) {
|
||||
const defaults = DEFAULT_QUESTS.find((d) => d.id === quest.id);
|
||||
if (defaults && quest.zoneId !== defaults.zoneId) {
|
||||
quest.zoneId = defaults.zoneId;
|
||||
needsBackfill = true;
|
||||
}
|
||||
if (!quest.zoneId) {
|
||||
const defaults = DEFAULT_QUESTS.find((d) => d.id === quest.id);
|
||||
quest.zoneId = defaults?.zoneId ?? "verdant_vale";
|
||||
needsBackfill = true;
|
||||
}
|
||||
@@ -98,7 +102,23 @@ gameRouter.get("/load", async (context) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Backfill zones on saves that predate the feature
|
||||
// Backfill costCrystals on upgrades that predate the field
|
||||
for (const upgrade of state.upgrades) {
|
||||
if (upgrade.costCrystals == null) {
|
||||
upgrade.costCrystals = 0;
|
||||
needsBackfill = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge new adventurers from defaults
|
||||
for (const defaultAdventurer of DEFAULT_ADVENTURERS) {
|
||||
if (!state.adventurers.some((a) => a.id === defaultAdventurer.id)) {
|
||||
state.adventurers.push(structuredClone(defaultAdventurer));
|
||||
needsBackfill = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Backfill zones
|
||||
if (!Array.isArray(state.zones) || state.zones.length === 0) {
|
||||
state.zones = structuredClone(DEFAULT_ZONES);
|
||||
// Infer unlock state from defeated bosses
|
||||
@@ -111,6 +131,22 @@ gameRouter.get("/load", async (context) => {
|
||||
}
|
||||
}
|
||||
needsBackfill = true;
|
||||
} else {
|
||||
// Merge new zones from defaults
|
||||
for (const defaultZone of DEFAULT_ZONES) {
|
||||
if (!state.zones.some((z) => z.id === defaultZone.id)) {
|
||||
const newZone = structuredClone(defaultZone);
|
||||
// Infer unlock state from defeated bosses
|
||||
if (newZone.unlockBossId != null) {
|
||||
const unlockBoss = state.bosses.find((b) => b.id === newZone.unlockBossId);
|
||||
if (unlockBoss?.status === "defeated") {
|
||||
newZone.status = "unlocked";
|
||||
}
|
||||
}
|
||||
state.zones.push(newZone);
|
||||
needsBackfill = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Backfill zoneId on bosses that predate the field
|
||||
@@ -122,6 +158,23 @@ gameRouter.get("/load", async (context) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Merge new bosses from defaults (new zones' bosses)
|
||||
for (const defaultBoss of DEFAULT_BOSSES) {
|
||||
if (!state.bosses.some((b) => b.id === defaultBoss.id)) {
|
||||
const newBoss = structuredClone(defaultBoss);
|
||||
// If the zone for this boss is already unlocked, make the first boss in that zone available
|
||||
const zone = state.zones.find((z) => z.id === newBoss.zoneId);
|
||||
if (zone?.status === "unlocked") {
|
||||
const zoneBossesInState = state.bosses.filter((b) => b.zoneId === newBoss.zoneId);
|
||||
if (zoneBossesInState.length === 0 && newBoss.status === "locked") {
|
||||
newBoss.status = "available";
|
||||
}
|
||||
}
|
||||
state.bosses.push(newBoss);
|
||||
needsBackfill = true;
|
||||
}
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
const { offlineGold, offlineSeconds } = calculateOfflineGold(state, now);
|
||||
|
||||
Reference in New Issue
Block a user