feat: add Goddess expansion type definitions

Adds all TypeScript interfaces for the Goddess expansion to packages/types:
GoddessState, GoddessZone, GoddessBoss, GoddessQuest, GoddessDisciple,
GoddessEquipment, GoddessUpgrade, ConsecrationData, EnlightenmentData,
GoddessExplorationState, GoddessAchievement. Extends Resource with optional
goddess currencies (prayers, divinity, stardust) and GameState with optional
goddess field. Also adds goddess-todo.md implementation tracker.
This commit is contained in:
2026-04-13 12:01:40 -07:00
committed by Naomi Carrigan
parent 9bb1d01d2b
commit c09777199a
15 changed files with 863 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
# Goddess Expansion — Implementation Tracker
Branch: `feat/goddess`
## Chunk 1 — Types ✅ COMPLETE
- [x] Add `GoddessZone`, `GoddessBoss`, `GoddessQuest` interfaces
- [x] Add `GoddessDisciple` (Disciples) interface
- [x] Add `GoddessEquipment`, `GoddessUpgrade` interfaces
- [x] Add `GoddessExplorationState` interface
- [x] Add `ConsecrationData` + `ConsecrationUpgrade` (Prestige) interfaces
- [x] Add `EnlightenmentData` + `EnlightenmentUpgrade` (Transcendence) interfaces
- [x] Add `GoddessAchievement` interface
- [x] Add goddess currency fields (prayers, divinity, stardust) to `Resource`
- [x] Add top-level `GoddessState` container + add `goddess?` to `GameState`
- [x] Export all new types from `packages/types`
- Lint ✅ · Build ✅ · Tests ✅ (100% coverage)
## Chunk 2 — Data
- [ ] `goddess-zones.ts` — goddess zone definitions
- [ ] `goddess-bosses.ts` — goddess boss definitions
- [ ] `goddess-quests.ts` — goddess quest definitions
- [ ] `goddess-disciples.ts` — disciple (adventurer) tier definitions
- [ ] `goddess-equipment.ts` — goddess equipment definitions
- [ ] `goddess-upgrades.ts` — goddess upgrade definitions
- [ ] `goddess-prestige-upgrades.ts` — consecration upgrade definitions
- [ ] `goddess-transcendence-upgrades.ts` — enlightenment upgrade definitions
- [ ] `goddess-crafting.ts` — goddess materials + recipes
- [ ] `goddess-explorations.ts` — goddess exploration areas
- [ ] `goddess-achievements.ts` — goddess achievement definitions
## Chunk 3 — Sync / Sanitize
- [ ] Update `validateAndSanitize` to inject goddess state defaults for existing saves
- [ ] Update force-sync (`syncNewContent`) to inject missing goddess fields
- [ ] Add apotheosis unlock flag handling
## Chunk 4 — API Routes
- [ ] Goddess boss fight route
- [ ] Consecration (goddess prestige) route
- [ ] Enlightenment (goddess transcendence) route
- [ ] Goddess upgrade purchase route
- [ ] Goddess crafting route
- [ ] Goddess exploration route
## Chunk 5 — UI: Resource Bar + Tab Row
- [ ] Add goddess currencies to resource bar dropdown (greyed pre-apotheosis)
- [ ] Add second tab row to nav (always visible, locked pre-apotheosis)
- [ ] `.goddess-mode` CSS class toggle on root when goddess tab active
- [ ] 300ms CSS fade transition between base and goddess themes
## Chunk 6 — UI: Goddess Panels
- [ ] `GoddessZonesPanel` — zones with lock states
- [ ] `GoddessBossPanel` — boss fights
- [ ] `GoddessQuestsPanel` — quests
- [ ] `DisciplesPanel` — goddess adventurers
- [ ] `GoddessEquipmentPanel` — equipment
- [ ] `GoddessUpgradesPanel` — upgrades
- [ ] `ConsecrationPanel` — goddess prestige
- [ ] `EnlightenmentPanel` — goddess transcendence
- [ ] `GoddessCraftingPanel` — crafting
- [ ] `GoddessExplorationPanel` — exploration
- [ ] `GoddessAchievementsPanel` — achievements
## Chunk 7 — Tick Engine
- [ ] Goddess passive income (prayers, divinity accumulation)
- [ ] Disciple passive income logic
- [ ] Lock state checks (no goddess income pre-apotheosis)
- [ ] Goddess quest timer logic
## Chunk 8 — CSS Theme
- [ ] Define goddess CSS variables (soft blue primary, gold/white accents)
- [ ] Apply `.goddess-mode` overrides to all themed elements
- [ ] Verify logo stays unchanged during theme shift
- [ ] Test fade transition smoothness
## Chunk 9 — About Page
- [ ] Update `HOW_TO_PLAY` array in `aboutPanel.tsx` with Goddess expansion documentation
## Notes
- Apotheosis = the unlock gate for all goddess content (replaces original "Transcendence 20" concept — verify exact trigger)
- Goddess currencies always visible in resource bar, greyed pre-apotheosis
- All goddess tabs always visible in second row, content locked internally pre-apotheosis
- Vampire Mode will follow same pattern as third tab row (future work, not this PR)
- Sync new content must inject goddess defaults for all existing saves
+54
View File
@@ -97,6 +97,60 @@ export type {
} from "./interfaces/equipmentSet.js";
export { computeSetBonuses } from "./interfaces/equipmentSet.js";
export type { GameState } from "./interfaces/gameState.js";
export type {
GoddessAchievement,
GoddessAchievementCondition,
GoddessAchievementConditionType,
GoddessAchievementReward,
} from "./interfaces/goddessAchievement.js";
export type {
GoddessBoss,
GoddessBossStatus,
} from "./interfaces/goddessBoss.js";
export type {
ConsecrationData,
ConsecrationUpgrade,
ConsecrationUpgradeCategory,
} from "./interfaces/goddessConsecration.js";
export type {
GoddessDisciple,
GoddessDiscipleClass,
} from "./interfaces/goddessDisciple.js";
export type {
EnlightenmentData,
EnlightenmentUpgrade,
EnlightenmentUpgradeCategory,
} from "./interfaces/goddessEnlightenment.js";
export type {
GoddessEquipment,
GoddessEquipmentBonus,
GoddessEquipmentRarity,
GoddessEquipmentType,
} from "./interfaces/goddessEquipment.js";
export type {
GoddessExplorationArea,
GoddessExplorationAreaState,
GoddessExplorationEvent,
GoddessExplorationEventEffect,
GoddessExplorationEventEffectType,
GoddessExplorationMaterialDrop,
GoddessExplorationState,
} from "./interfaces/goddessExploration.js";
export type {
GoddessQuest,
GoddessQuestReward,
GoddessQuestRewardType,
GoddessQuestStatus,
} from "./interfaces/goddessQuest.js";
export type { GoddessState } from "./interfaces/goddessState.js";
export type {
GoddessUpgrade,
GoddessUpgradeTarget,
} from "./interfaces/goddessUpgrade.js";
export type {
GoddessZone,
GoddessZoneStatus,
} from "./interfaces/goddessZone.js";
export type { Player } from "./interfaces/player.js";
export type { PrestigeData } from "./interfaces/prestige.js";
export type {
@@ -13,6 +13,7 @@ import type { CompanionState } from "./companion.js";
import type { DailyChallengeState } from "./dailyChallenge.js";
import type { Equipment } from "./equipment.js";
import type { ExplorationState } from "./exploration.js";
import type { GoddessState } from "./goddessState.js";
import type { Player } from "./player.js";
import type { PrestigeData } from "./prestige.js";
import type { Quest } from "./quest.js";
@@ -94,6 +95,11 @@ interface GameState {
*/
story?: StoryState;
/**
* Goddess expansion state — optional for backwards compatibility with pre-goddess saves.
*/
goddess?: GoddessState;
/**
* Schema version — used to detect saves from older game versions.
*/
@@ -0,0 +1,45 @@
/**
* @file Goddess Achievement types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessAchievementConditionType =
| "totalPrayersEarned"
| "goddessBossesDefeated"
| "goddessQuestsCompleted"
| "discipleTotal"
| "consecrationCount"
| "goddessEquipmentOwned";
interface GoddessAchievementCondition {
type: GoddessAchievementConditionType;
amount: number;
}
interface GoddessAchievementReward {
divinity?: number;
stardust?: number;
}
interface GoddessAchievement {
id: string;
name: string;
description: string;
icon: string;
condition: GoddessAchievementCondition;
reward?: GoddessAchievementReward;
/**
* Unix timestamp when unlocked, null if not yet unlocked.
*/
unlockedAt: number | null;
}
export type {
GoddessAchievement,
GoddessAchievementCondition,
GoddessAchievementConditionType,
GoddessAchievementReward,
};
@@ -0,0 +1,69 @@
/**
* @file Goddess Boss types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessBossStatus = "locked" | "available" | "in_progress" | "defeated";
interface GoddessBoss {
id: string;
name: string;
description: string;
status: GoddessBossStatus;
maxHp: number;
currentHp: number;
/**
* Damage dealt to disciples per second whilst the fight is active.
*/
damagePerSecond: number;
/**
* Prayers reward on defeat.
*/
prayersReward: number;
/**
* Divinity reward on defeat.
*/
divinityReward: number;
/**
* Stardust reward on defeat.
*/
stardustReward: number;
/**
* IDs of goddess upgrades unlocked on defeat.
*/
upgradeRewards: Array<string>;
/**
* IDs of goddess equipment items granted on defeat.
*/
equipmentRewards: Array<string>;
/**
* Minimum consecration level required to access this boss.
*/
consecrationRequirement: number;
/**
* Goddess zone this boss belongs to.
*/
zoneId: string;
/**
* One-time divinity bounty awarded on first-ever defeat.
*/
bountyDivinity: number;
/**
* Whether the first-kill divinity bounty has already been claimed.
*/
bountyDivinityClaimed?: boolean;
}
export type { GoddessBoss, GoddessBossStatus };
@@ -0,0 +1,75 @@
/**
* @file Goddess Consecration (prestige) types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type ConsecrationUpgradeCategory =
| "prayers"
| "disciples"
| "combat"
| "divinity"
| "utility";
interface ConsecrationUpgrade {
id: string;
name: string;
description: string;
category: ConsecrationUpgradeCategory;
divinityCost: number;
/**
* Multiplier applied when this upgrade is purchased.
*/
multiplier: number;
}
interface ConsecrationData {
/**
* Number of times the player has consecrated (goddess prestige).
*/
count: number;
/**
* Divinity carried over between consecrations.
*/
divinity: number;
/**
* Multiplier applied to all prayers/s production (based on consecration count).
*/
productionMultiplier: number;
/**
* IDs of consecration upgrades purchased with divinity.
*/
purchasedUpgradeIds: Array<string>;
/**
* Unix timestamp of last consecration.
*/
lastConsecratedAt?: number;
/**
* Pre-computed multiplier from "prayers" divinity upgrades.
*/
divinityPrayersMultiplier?: number;
/**
* Pre-computed multiplier from "disciples" divinity upgrades.
*/
divinityDisciplesMultiplier?: number;
/**
* Pre-computed multiplier from "combat" divinity upgrades.
*/
divinityCombatMultiplier?: number;
}
export type {
ConsecrationData,
ConsecrationUpgrade,
ConsecrationUpgradeCategory,
};
@@ -0,0 +1,46 @@
/**
* @file Goddess Disciple types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessDiscipleClass =
| "oracle"
| "seraph"
| "invoker"
| "templar"
| "warden"
| "herald";
interface GoddessDisciple {
id: string;
name: string;
class: GoddessDiscipleClass;
level: number;
/**
* Base cost for the first purchase of this tier (scales by 1.15× per count).
* Paid in prayers.
*/
baseCost: number;
/**
* Base prayers generated per second.
*/
prayersPerSecond: number;
/**
* Base divinity generated per second.
*/
divinityPerSecond: number;
/**
* Combat power per unit — used in goddess boss battle simulation.
*/
combatPower: number;
count: number;
unlocked: boolean;
}
export type { GoddessDisciple, GoddessDiscipleClass };
@@ -0,0 +1,79 @@
/**
* @file Goddess Enlightenment (transcendence) types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type EnlightenmentUpgradeCategory =
| "prayers"
| "combat"
| "consecration_threshold"
| "consecration_divinity"
| "stardust_meta";
interface EnlightenmentUpgrade {
id: string;
name: string;
description: string;
category: EnlightenmentUpgradeCategory;
/**
* Stardust cost to purchase.
*/
cost: number;
/**
* Multiplicative effect of this upgrade.
*/
multiplier: number;
}
interface EnlightenmentData {
/**
* Number of times the player has achieved Enlightenment.
*/
count: number;
/**
* Stardust accumulated across all enlightenments.
*/
stardust: number;
/**
* IDs of stardust upgrades purchased.
*/
purchasedUpgradeIds: Array<string>;
/**
* Pre-computed: multiplier applied to all passive prayers income.
*/
stardustPrayersMultiplier: number;
/**
* Pre-computed: multiplier applied to disciple DPS in goddess boss fights.
*/
stardustCombatMultiplier: number;
/**
* Pre-computed: multiplier applied to the consecration prayers threshold (< 1 lowers requirement).
*/
stardustConsecrationThresholdMultiplier: number;
/**
* Pre-computed: multiplier applied to divinity earned per consecration.
*/
stardustConsecrationDivinityMultiplier: number;
/**
* Pre-computed: multiplier applied to stardust yield on future enlightenments.
*/
stardustMetaMultiplier: number;
}
export type {
EnlightenmentData,
EnlightenmentUpgrade,
EnlightenmentUpgradeCategory,
};
@@ -0,0 +1,64 @@
/**
* @file Goddess Equipment types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessEquipmentType = "relic" | "vestment" | "sigil";
type GoddessEquipmentRarity = "common" | "rare" | "epic" | "legendary";
interface GoddessEquipmentBonus {
/**
* Multiplier applied to all prayers/s income (e.g. 1.1 = +10%).
*/
prayersMultiplier?: number;
/**
* Multiplier applied to all disciple combat power (e.g. 1.25 = +25%).
*/
combatMultiplier?: number;
/**
* Multiplier applied to divinity earned per consecration (e.g. 1.5 = +50%).
*/
divinityMultiplier?: number;
}
interface GoddessEquipment {
id: string;
name: string;
description: string;
type: GoddessEquipmentType;
rarity: GoddessEquipmentRarity;
bonus: GoddessEquipmentBonus;
/**
* Whether the player has acquired this item.
*/
owned: boolean;
/**
* Whether this item is currently equipped (only one per type can be equipped).
*/
equipped: boolean;
/**
* If set, this item can be purchased directly rather than obtained via goddess boss drops.
*/
cost?: { prayers: number; divinity: number; stardust: number };
/**
* Goddess equipment set this item belongs to, if any.
*/
setId?: string;
}
export type {
GoddessEquipment,
GoddessEquipmentBonus,
GoddessEquipmentRarity,
GoddessEquipmentType,
};
@@ -0,0 +1,123 @@
/**
* @file Goddess Exploration types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessExplorationEventEffectType =
| "prayers_gain"
| "prayers_loss"
| "divinity_gain"
| "sacred_material_gain"
| "disciple_loss";
interface GoddessExplorationEventEffect {
type: GoddessExplorationEventEffectType;
/**
* Prayers amount for prayers_gain / prayers_loss.
*/
amount?: number;
/**
* Sacred material ID for sacred_material_gain.
*/
materialId?: string;
/**
* Quantity for sacred_material_gain.
*/
quantity?: number;
/**
* Fraction (01) of total disciples lost for disciple_loss.
*/
fraction?: number;
}
interface GoddessExplorationEvent {
id: string;
text: string;
effect: GoddessExplorationEventEffect;
}
interface GoddessExplorationMaterialDrop {
materialId: string;
minQuantity: number;
maxQuantity: number;
/**
* Relative probability weight — higher = more likely.
*/
weight: number;
}
interface GoddessExplorationArea {
id: string;
name: string;
description: string;
zoneId: string;
durationSeconds: number;
possibleMaterials: Array<GoddessExplorationMaterialDrop>;
events: Array<GoddessExplorationEvent>;
}
interface GoddessExplorationAreaState {
id: string;
status: "locked" | "available" | "in_progress" | "completed";
/**
* Unix timestamp when exploration started (set when status becomes in_progress).
*/
startedAt?: number;
/**
* Unix timestamp when the exploration will complete.
*/
endsAt?: number;
/**
* True after the first successful collect — used for codex unlock detection.
*/
completedOnce?: boolean;
}
interface GoddessExplorationState {
areas: Array<GoddessExplorationAreaState>;
/**
* Current sacred material inventory.
*/
materials: Array<{ materialId: string; quantity: number }>;
/**
* IDs of goddess crafting recipes that have been crafted (resets on consecration).
*/
craftedRecipeIds: Array<string>;
/**
* Pre-computed prayers income multiplier from all crafted goddess recipes.
*/
craftedPrayersMultiplier: number;
/**
* Pre-computed divinity income multiplier from all crafted goddess recipes.
*/
craftedDivinityMultiplier: number;
/**
* Pre-computed combat power multiplier from all crafted goddess recipes.
*/
craftedCombatMultiplier: number;
}
export type {
GoddessExplorationArea,
GoddessExplorationAreaState,
GoddessExplorationEvent,
GoddessExplorationEventEffect,
GoddessExplorationEventEffectType,
GoddessExplorationMaterialDrop,
GoddessExplorationState,
};
@@ -0,0 +1,71 @@
/**
* @file Goddess Quest types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessQuestStatus = "locked" | "available" | "active" | "completed";
type GoddessQuestRewardType =
| "prayers"
| "divinity"
| "stardust"
| "upgrade"
| "disciple"
| "equipment";
interface GoddessQuestReward {
type: GoddessQuestRewardType;
amount?: number;
/**
* ID of the goddess upgrade or disciple to unlock (if applicable).
*/
targetId?: string;
}
interface GoddessQuest {
id: string;
name: string;
description: string;
status: GoddessQuestStatus;
/**
* Unix timestamp when quest was started (if active).
*/
startedAt?: number;
/**
* Duration in seconds.
*/
durationSeconds: number;
rewards: Array<GoddessQuestReward>;
/**
* IDs of goddess quests that must be completed before this one unlocks.
*/
prerequisiteIds: Array<string>;
/**
* Goddess zone this quest belongs to.
*/
zoneId: string;
/**
* Minimum disciple combat power required to start this quest.
*/
combatPowerRequired?: number;
/**
* Unix timestamp of the most recent failed attempt (if any).
*/
lastFailedAt?: number;
}
export type {
GoddessQuest,
GoddessQuestReward,
GoddessQuestRewardType,
GoddessQuestStatus,
};
@@ -0,0 +1,76 @@
/**
* @file Goddess expansion state types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
import type { GoddessAchievement } from "./goddessAchievement.js";
import type { GoddessBoss } from "./goddessBoss.js";
import type { ConsecrationData } from "./goddessConsecration.js";
import type { GoddessDisciple } from "./goddessDisciple.js";
import type { EnlightenmentData } from "./goddessEnlightenment.js";
import type { GoddessEquipment } from "./goddessEquipment.js";
import type { GoddessExplorationState } from "./goddessExploration.js";
import type { GoddessQuest } from "./goddessQuest.js";
import type { GoddessUpgrade } from "./goddessUpgrade.js";
import type { GoddessZone } from "./goddessZone.js";
interface GoddessState {
zones: Array<GoddessZone>;
bosses: Array<GoddessBoss>;
quests: Array<GoddessQuest>;
disciples: Array<GoddessDisciple>;
equipment: Array<GoddessEquipment>;
upgrades: Array<GoddessUpgrade>;
achievements: Array<GoddessAchievement>;
consecration: ConsecrationData;
enlightenment: EnlightenmentData;
exploration: GoddessExplorationState;
/**
* Total prayers earned in the current consecration run (resets on consecration).
*/
totalPrayersEarned: number;
/**
* Total prayers earned across all time (never resets — used for achievements and unlock thresholds).
*/
lifetimePrayersEarned: number;
/**
* Total goddess bosses defeated across all time.
*/
lifetimeBossesDefeated: number;
/**
* Total goddess quests completed across all time.
*/
lifetimeQuestsCompleted: number;
/**
* Click power for the goddess realm (prayers per click, before upgrades).
*/
baseClickPower: number;
/**
* Unix timestamp of the last goddess-side client tick.
*/
lastTickAt: number;
/**
* When true, the tick engine automatically starts the highest-zone available goddess quest.
*/
autoQuest?: boolean;
/**
* When true, the tick engine automatically challenges the highest available goddess boss.
*/
autoBoss?: boolean;
/**
* When true, the tick engine automatically purchases the highest-tier affordable disciple.
*/
autoDisciple?: boolean;
}
export type { GoddessState };
@@ -0,0 +1,37 @@
/**
* @file Goddess Upgrade types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessUpgradeTarget =
| "prayers"
| "disciple"
| "global"
| "consecration"
| "boss";
interface GoddessUpgrade {
id: string;
name: string;
description: string;
target: GoddessUpgradeTarget;
/**
* ID of the disciple this applies to (if target is "disciple").
*/
discipleId?: string;
/**
* Multiplier applied to the target's output.
*/
multiplier: number;
costPrayers: number;
costDivinity: number;
costStardust: number;
purchased: boolean;
unlocked: boolean;
}
export type { GoddessUpgrade, GoddessUpgradeTarget };
@@ -0,0 +1,28 @@
/**
* @file Goddess Zone types for the Elysium game.
* @copyright nhcarrigan
* @license Naomi's Public License
* @author Naomi Carrigan
*/
type GoddessZoneStatus = "locked" | "unlocked";
interface GoddessZone {
id: string;
name: string;
description: string;
emoji: string;
status: GoddessZoneStatus;
/**
* Goddess boss ID whose defeat is required to unlock this zone (null for the starter zone).
*/
unlockBossId: string | null;
/**
* Goddess quest ID that must be completed to unlock this zone (null for the starter zone).
*/
unlockQuestId: string | null;
}
export type { GoddessZone, GoddessZoneStatus };
@@ -10,6 +10,13 @@ interface Resource {
essence: number;
crystals: number;
runestones: number;
/**
* Goddess expansion currencies — optional for backwards compatibility with pre-goddess saves.
*/
prayers?: number;
divinity?: number;
stardust?: number;
}
export type { Resource };