feat: vampire equipment, upgrades, siring, and awakening panels

This commit is contained in:
2026-04-16 12:36:05 -07:00
committed by Naomi Carrigan
parent bd88eecda5
commit a7598dca12
6 changed files with 2002 additions and 12 deletions
+277
View File
@@ -22,6 +22,8 @@ import {
type GameState,
type GoddessBossChallengeResponse,
type GoddessExploreCollectResponse,
type AwakeningResponse,
type SiringResponse,
type VampireBossChallengeResponse,
type LoginBonusResult,
type NumberFormat,
@@ -43,11 +45,15 @@ import {
} from "react";
import {
achieveApotheosis as achieveApotheosisApi,
awaken as awakenApi,
buyAwakeningUpgrade as buyAwakeningUpgradeApi,
buyConsecrationUpgrade as buyConsecrationUpgradeApi,
buyEchoUpgrade as buyEchoUpgradeApi,
buyEnlightenmentUpgrade as buyEnlightenmentUpgradeApi,
buyGoddessUpgrade as buyGoddessUpgradeApi,
buyPrestigeUpgrade as buyPrestigeUpgradeApi,
buySiringUpgrade as buySiringUpgradeApi,
buyVampireUpgrade as buyVampireUpgradeApi,
challengeBoss as challengeBossApi,
challengeGoddessBoss as challengeGoddessBossApi,
challengeVampireBoss as challengeVampireBossApi,
@@ -64,6 +70,7 @@ import {
prestige as prestigeApi,
resetProgress as resetProgressApi,
saveGame,
sire as sireApi,
startExploration as startExplorationApi,
startGoddessExploration as startGoddessExplorationApi,
transcend as transcendApi,
@@ -790,6 +797,43 @@ interface GameContextValue {
* Buy one or more thralls (client-side blood deduction).
*/
buyVampireThrall: (thrallId: string, quantity: number)=> void;
/**
* Purchase a vampire equipment item (client-side state mutation).
*/
buyVampireEquipment: (equipmentId: string)=> void;
/**
* Equip an owned vampire equipment item (auto-unequips same slot).
*/
equipVampireEquipment: (equipmentId: string)=> void;
/**
* Purchase a vampire upgrade using blood/ichor/soul shards.
*/
buyVampireUpgrade: (upgradeId: string)=> Promise<void>;
/**
* Perform a vampire siring (prestige reset) for ichor.
* @returns The siring response containing ichorEarned.
*/
sire: ()=> Promise<SiringResponse>;
/**
* Purchase a siring upgrade from the ichor shop.
*/
buySiringUpgrade: (upgradeId: string)=> Promise<void>;
/**
* Perform a vampire awakening (meta-reset) for soul shards.
* @returns The awakening response containing soulShardsEarned.
*/
awaken: ()=> Promise<AwakeningResponse>;
/**
* Purchase an awakening upgrade from the soul shards shop.
*/
buyAwakeningUpgrade: (upgradeId: string)=> Promise<void>;
}
export interface BattleResult {
@@ -2218,6 +2262,225 @@ export const GameProvider = ({
[],
);
const buyVampireEquipment = useCallback((equipmentId: string) => {
setState((previous) => {
if (previous?.vampire === undefined) {
return previous;
}
const item = previous.vampire.equipment.find((equip) => {
return equip.id === equipmentId;
});
if (item?.owned === true) {
return previous;
}
const blood = previous.resources.blood ?? 0;
const { ichor } = previous.vampire.siring;
const { soulShards } = previous.vampire.awakening;
if (
blood < (item?.cost?.blood ?? 0)
|| ichor < (item?.cost?.ichor ?? 0)
|| soulShards < (item?.cost?.soulShards ?? 0)
) {
return previous;
}
const slotAlreadyEquipped = previous.vampire.equipment.find((equip) => {
return equip.equipped && equip.type === item?.type;
});
return {
...previous,
resources: {
...previous.resources,
blood: blood - (item?.cost?.blood ?? 0),
},
vampire: {
...previous.vampire,
awakening: {
...previous.vampire.awakening,
soulShards: soulShards - (item?.cost?.soulShards ?? 0),
},
equipment: previous.vampire.equipment.map((equip) => {
if (equip.id === equipmentId) {
return {
...equip,
equipped: slotAlreadyEquipped === undefined,
owned: true,
};
}
if (equip.id === slotAlreadyEquipped?.id) {
return { ...equip, equipped: false };
}
return equip;
}),
siring: {
...previous.vampire.siring,
ichor: ichor - (item?.cost?.ichor ?? 0),
},
},
};
});
}, []);
const equipVampireEquipment = useCallback((equipmentId: string) => {
setState((previous) => {
if (previous?.vampire === undefined) {
return previous;
}
const item = previous.vampire.equipment.find((equip) => {
return equip.id === equipmentId;
});
if (item?.owned !== true) {
return previous;
}
const slotAlreadyEquipped = previous.vampire.equipment.find((equip) => {
return (
equip.equipped && equip.type === item.type && equip.id !== equipmentId
);
});
return {
...previous,
vampire: {
...previous.vampire,
equipment: previous.vampire.equipment.map((equip) => {
if (equip.id === equipmentId) {
return { ...equip, equipped: true };
}
if (equip.id === slotAlreadyEquipped?.id) {
return { ...equip, equipped: false };
}
return equip;
}),
},
};
});
}, []);
const buyVampireUpgrade = useCallback(async(upgradeId: string) => {
try {
const result = await buyVampireUpgradeApi({ upgradeId });
setState((previous) => {
if (previous?.vampire === undefined) {
return previous;
}
return {
...previous,
resources: {
...previous.resources,
blood: result.bloodRemaining,
},
vampire: {
...previous.vampire,
awakening: {
...previous.vampire.awakening,
soulShards: result.soulShardsRemaining,
},
siring: {
...previous.vampire.siring,
ichor: result.ichorRemaining,
},
upgrades: previous.vampire.upgrades.map((u) => {
return u.id === upgradeId
? { ...u, purchased: true }
: u;
}),
},
};
});
signatureReference.current = null;
localStorage.removeItem("elysium_save_signature");
} catch (error_: unknown) {
logError("buy_vampire_upgrade", error_);
}
}, []);
const sire = useCallback(async(): Promise<SiringResponse> => {
try {
const result = await sireApi({});
await reloadSilent();
return result;
} catch (error_: unknown) {
logError("sire", error_);
throw error_;
}
}, [ reloadSilent ]);
const buySiringUpgrade = useCallback(async(upgradeId: string) => {
try {
const result = await buySiringUpgradeApi({ upgradeId });
setState((previous) => {
if (previous?.vampire === undefined) {
return previous;
}
return {
...previous,
vampire: {
...previous.vampire,
siring: {
...previous.vampire.siring,
ichor: result.ichorRemaining,
ichorBloodMultiplier: result.ichorBloodMultiplier,
ichorCombatMultiplier: result.ichorCombatMultiplier,
ichorThrallsMultiplier: result.ichorThrallsMultiplier,
purchasedUpgradeIds: result.purchasedUpgradeIds,
},
},
};
});
signatureReference.current = null;
localStorage.removeItem("elysium_save_signature");
} catch (error_: unknown) {
logError("buy_siring_upgrade", error_);
}
}, []);
const awaken = useCallback(async(): Promise<AwakeningResponse> => {
try {
const result = await awakenApi({});
await reloadSilent();
return result;
} catch (error_: unknown) {
logError("awaken", error_);
throw error_;
}
}, [ reloadSilent ]);
const buyAwakeningUpgrade = useCallback(async(upgradeId: string) => {
try {
const result = await buyAwakeningUpgradeApi({ upgradeId });
setState((previous) => {
if (previous?.vampire === undefined) {
return previous;
}
return {
...previous,
vampire: {
...previous.vampire,
awakening: {
...previous.vampire.awakening,
purchasedUpgradeIds:
result.purchasedUpgradeIds,
soulShards:
result.soulShardsRemaining,
soulShardsBloodMultiplier:
result.soulShardsBloodMultiplier,
soulShardsCombatMultiplier:
result.soulShardsCombatMultiplier,
soulShardsMetaMultiplier:
result.soulShardsMetaMultiplier,
soulShardsSiringIchorMultiplier:
result.soulShardsSiringIchorMultiplier,
soulShardsSiringThresholdMultiplier:
result.soulShardsSiringThresholdMultiplier,
},
},
};
});
signatureReference.current = null;
localStorage.removeItem("elysium_save_signature");
} catch (error_: unknown) {
logError("buy_awakening_upgrade", error_);
}
}, []);
const consecrate = useCallback(async() => {
try {
const result = await consecrateApi({});
@@ -3167,9 +3430,11 @@ export const GameProvider = ({
apotheosis,
autoBossError,
autoBossLastResult,
awaken,
battleResult,
bossError,
buyAdventurer,
buyAwakeningUpgrade,
buyConsecrationUpgrade,
buyEchoUpgrade,
buyEnlightenmentUpgrade,
@@ -3178,8 +3443,11 @@ export const GameProvider = ({
buyGoddessEquipment,
buyGoddessUpgrade,
buyPrestigeUpgrade,
buySiringUpgrade,
buyUpgrade,
buyVampireEquipment,
buyVampireThrall,
buyVampireUpgrade,
challengeBoss,
challengeGoddessBoss,
challengeVampireBoss,
@@ -3212,6 +3480,7 @@ export const GameProvider = ({
enlighten,
equipGoddessItem,
equipItem,
equipVampireEquipment,
error,
failedQuestToasts,
flushBossLoreToasts,
@@ -3244,6 +3513,7 @@ export const GameProvider = ({
showEnlightenmentToast,
showPrestigeToast,
showTranscendenceToast,
sire,
startExploration,
startGoddessExploration,
startQuest,
@@ -3266,9 +3536,11 @@ export const GameProvider = ({
apotheosis,
autoBossError,
autoBossLastResult,
awaken,
battleResult,
bossError,
buyAdventurer,
buyAwakeningUpgrade,
buyConsecrationUpgrade,
buyEchoUpgrade,
buyEnlightenmentUpgrade,
@@ -3277,8 +3549,11 @@ export const GameProvider = ({
buyGoddessEquipment,
buyGoddessUpgrade,
buyPrestigeUpgrade,
buySiringUpgrade,
buyUpgrade,
buyVampireEquipment,
buyVampireThrall,
buyVampireUpgrade,
challengeBoss,
challengeGoddessBoss,
challengeVampireBoss,
@@ -3311,6 +3586,7 @@ export const GameProvider = ({
enlighten,
equipGoddessItem,
equipItem,
equipVampireEquipment,
error,
failedQuestToasts,
flushBossLoreToasts,
@@ -3342,6 +3618,7 @@ export const GameProvider = ({
showEnlightenmentToast,
showPrestigeToast,
showTranscendenceToast,
sire,
startExploration,
startGoddessExploration,
startQuest,