generated from nhcarrigan/template
feat: goddess API routes, services, and tests (chunk 4)
Add six new goddess-mode API routes (boss fight, consecration, enlightenment, upgrade purchase, crafting, exploration) alongside matching service modules and full test suites at 100% coverage.
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* @file Enlightenment service handling eligibility checks and post-enlightenment state building.
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
/* eslint-disable stylistic/max-len -- Service logic requires long lines */
|
||||
import { defaultEnlightenmentUpgrades } from "../data/goddessEnlightenmentUpgrades.js";
|
||||
import { initialGoddessState } from "../data/initialState.js";
|
||||
import type { EnlightenmentData, GameState } from "@elysium/types";
|
||||
|
||||
/**
|
||||
* ID of the final goddess boss — must be defeated to unlock Enlightenment.
|
||||
*/
|
||||
const finalGoddessBossId = "divine_heart_sovereign";
|
||||
|
||||
const getCategoryMultiplier = (
|
||||
purchasedIds: Array<string>,
|
||||
category: string,
|
||||
): number => {
|
||||
return defaultEnlightenmentUpgrades.filter((upgrade) => {
|
||||
return upgrade.category === category && purchasedIds.includes(upgrade.id);
|
||||
}).reduce((mult, upgrade) => {
|
||||
return mult * upgrade.multiplier;
|
||||
}, 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Computes all five stardust multipliers from the purchased enlightenment upgrade IDs.
|
||||
* @param purchasedUpgradeIds - The array of purchased enlightenment upgrade IDs.
|
||||
* @returns An object containing all five stardust multiplier values.
|
||||
*/
|
||||
const computeEnlightenmentMultipliers = (
|
||||
purchasedUpgradeIds: Array<string>,
|
||||
): Omit<EnlightenmentData, "count" | "stardust" | "purchasedUpgradeIds"> => {
|
||||
return {
|
||||
stardustCombatMultiplier: getCategoryMultiplier(purchasedUpgradeIds, "combat"),
|
||||
stardustConsecrationDivinityMultiplier: getCategoryMultiplier(purchasedUpgradeIds, "consecration_divinity"),
|
||||
stardustConsecrationThresholdMultiplier: getCategoryMultiplier(purchasedUpgradeIds, "consecration_threshold"),
|
||||
stardustMetaMultiplier: getCategoryMultiplier(purchasedUpgradeIds, "stardust_meta"),
|
||||
stardustPrayersMultiplier: getCategoryMultiplier(purchasedUpgradeIds, "prayers"),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true when the player is eligible for Enlightenment:
|
||||
* they must have defeated the final goddess boss at least once.
|
||||
* @param state - The current game state.
|
||||
* @returns Whether the player is eligible for Enlightenment.
|
||||
*/
|
||||
const isEligibleForEnlightenment = (state: GameState): boolean => {
|
||||
// eslint-disable-next-line capitalized-comments -- v8 ignore
|
||||
/* v8 ignore next 3 -- @preserve */
|
||||
if (state.goddess === undefined) {
|
||||
return false;
|
||||
}
|
||||
return state.goddess.bosses.some((boss) => {
|
||||
return boss.id === finalGoddessBossId && boss.status === "defeated";
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the stardust yield from an Enlightenment.
|
||||
* Formula: MAX(1, FLOOR(SQRT(consecrationCount) * metaMultiplier)).
|
||||
* @param consecrationCount - The number of consecrations completed before this Enlightenment.
|
||||
* @param metaMultiplier - Multiplier from prior enlightenment upgrades applied to stardust yield.
|
||||
* @returns The stardust earned.
|
||||
*/
|
||||
const calculateStardustYield = (
|
||||
consecrationCount: number,
|
||||
metaMultiplier: number,
|
||||
): number => {
|
||||
return Math.max(1, Math.floor(Math.sqrt(consecrationCount) * metaMultiplier));
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the updated goddess state after an Enlightenment — a full goddess reset.
|
||||
* Wipes everything including consecration, preserving only equipment, achievements, and enlightenment data.
|
||||
* @param state - The current game state before enlightenment.
|
||||
* @returns The stardust earned and the updated goddess state.
|
||||
*/
|
||||
const buildPostEnlightenmentState = (
|
||||
state: GameState,
|
||||
): { stardustEarned: number; updatedGoddess: NonNullable<GameState["goddess"]> } => {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Caller must ensure goddess exists
|
||||
const goddess = state.goddess as NonNullable<GameState["goddess"]>;
|
||||
|
||||
const metaMultiplier = goddess.enlightenment.stardustMetaMultiplier;
|
||||
const stardustEarned = calculateStardustYield(
|
||||
goddess.consecration.count,
|
||||
metaMultiplier,
|
||||
);
|
||||
|
||||
const updatedCount = goddess.enlightenment.count + 1;
|
||||
const updatedStardust = goddess.enlightenment.stardust + stardustEarned;
|
||||
const updatedPurchasedIds = goddess.enlightenment.purchasedUpgradeIds;
|
||||
const updatedMultipliers = computeEnlightenmentMultipliers(updatedPurchasedIds);
|
||||
|
||||
const updatedEnlightenment: EnlightenmentData = {
|
||||
count: updatedCount,
|
||||
purchasedUpgradeIds: updatedPurchasedIds,
|
||||
stardust: updatedStardust,
|
||||
...updatedMultipliers,
|
||||
};
|
||||
|
||||
const freshGoddess = initialGoddessState();
|
||||
|
||||
const updatedGoddess: NonNullable<GameState["goddess"]> = {
|
||||
...freshGoddess,
|
||||
achievements: goddess.achievements,
|
||||
bosses: freshGoddess.bosses.map((b) => {
|
||||
const existing = goddess.bosses.find((gb) => {
|
||||
return gb.id === b.id;
|
||||
});
|
||||
return {
|
||||
...b,
|
||||
bountyDivinityClaimed: existing?.bountyDivinityClaimed ?? false,
|
||||
};
|
||||
}),
|
||||
enlightenment: updatedEnlightenment,
|
||||
equipment: goddess.equipment,
|
||||
lastTickAt: Date.now(),
|
||||
lifetimeBossesDefeated: goddess.lifetimeBossesDefeated,
|
||||
lifetimePrayersEarned: goddess.lifetimePrayersEarned,
|
||||
lifetimeQuestsCompleted: goddess.lifetimeQuestsCompleted,
|
||||
totalPrayersEarned: 0,
|
||||
};
|
||||
|
||||
return { stardustEarned, updatedGoddess };
|
||||
};
|
||||
|
||||
export {
|
||||
buildPostEnlightenmentState,
|
||||
calculateStardustYield,
|
||||
computeEnlightenmentMultipliers,
|
||||
isEligibleForEnlightenment,
|
||||
};
|
||||
Reference in New Issue
Block a user