generated from nhcarrigan/template
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
7d1126e8ad
|
|||
|
ec0763819e
|
|||
|
4a9ecbf706
|
|||
|
96868c4143
|
@@ -122,7 +122,7 @@ export const defaultBosses: Array<Boss> = [
|
||||
// ── Shadow Marshes ────────────────────────────────────────────────────────
|
||||
{
|
||||
bountyRunestones: 20,
|
||||
crystalReward: 700,
|
||||
crystalReward: 1500,
|
||||
currentHp: 6_000_000,
|
||||
damagePerSecond: 1200,
|
||||
description:
|
||||
@@ -140,7 +140,7 @@ export const defaultBosses: Array<Boss> = [
|
||||
},
|
||||
{
|
||||
bountyRunestones: 25,
|
||||
crystalReward: 1500,
|
||||
crystalReward: 3000,
|
||||
currentHp: 12_000_000,
|
||||
damagePerSecond: 2400,
|
||||
description:
|
||||
@@ -158,7 +158,7 @@ export const defaultBosses: Array<Boss> = [
|
||||
},
|
||||
{
|
||||
bountyRunestones: 30,
|
||||
crystalReward: 3000,
|
||||
crystalReward: 6000,
|
||||
currentHp: 20_000_000,
|
||||
damagePerSecond: 4000,
|
||||
description:
|
||||
|
||||
@@ -223,7 +223,7 @@ export const defaultQuests: Array<Quest> = [
|
||||
},
|
||||
// ── Shadow Marshes ────────────────────────────────────────────────────────
|
||||
{
|
||||
combatPowerRequired: 5_000_000,
|
||||
combatPowerRequired: 2_000_000,
|
||||
description:
|
||||
"A cursed lake shrouded in permanent twilight. Strange energies pulse beneath its surface.",
|
||||
durationSeconds: 45 * 60,
|
||||
@@ -233,6 +233,7 @@ export const defaultQuests: Array<Quest> = [
|
||||
rewards: [
|
||||
{ amount: 5_000_000, type: "gold" },
|
||||
{ amount: 5000, type: "essence" },
|
||||
{ amount: 150, type: "crystals" },
|
||||
{ targetId: "peasant_3", type: "upgrade" },
|
||||
],
|
||||
status: "locked",
|
||||
@@ -249,6 +250,7 @@ export const defaultQuests: Array<Quest> = [
|
||||
rewards: [
|
||||
{ amount: 20_000_000, type: "gold" },
|
||||
{ amount: 20_000, type: "essence" },
|
||||
{ amount: 500, type: "crystals" },
|
||||
{ targetId: "shadow_assassin", type: "adventurer" },
|
||||
],
|
||||
status: "locked",
|
||||
|
||||
@@ -71,8 +71,7 @@ const shuffleWithSeed = <T>(array: Array<T>, seed: number): Array<T> => {
|
||||
return result;
|
||||
};
|
||||
|
||||
const challengeTypes: Array<DailyChallengeType> = [
|
||||
"clicks",
|
||||
const progressionChallengeTypes: Array<DailyChallengeType> = [
|
||||
"bossesDefeated",
|
||||
"questsCompleted",
|
||||
"prestige",
|
||||
@@ -80,7 +79,8 @@ const challengeTypes: Array<DailyChallengeType> = [
|
||||
|
||||
/**
|
||||
* Generates 3 daily challenges for the given date string, deterministically.
|
||||
* Picks one challenge from 3 different randomly-selected types.
|
||||
* Always includes a "clicks" challenge (always completable regardless of
|
||||
* progression), then picks 2 more from the remaining types.
|
||||
* @param dateString - The date string (YYYY-MM-DD) to generate challenges for.
|
||||
* @returns An array of 3 DailyChallenge objects.
|
||||
*/
|
||||
@@ -88,8 +88,10 @@ const generateDailyChallenges = (
|
||||
dateString: string,
|
||||
): Array<DailyChallenge> => {
|
||||
const seed = dateSeed(dateString);
|
||||
const selectedTypes = shuffleWithSeed([ ...challengeTypes ], seed).
|
||||
slice(0, 3);
|
||||
const selectedTypes: Array<DailyChallengeType> = [
|
||||
"clicks",
|
||||
...shuffleWithSeed([ ...progressionChallengeTypes ], seed).slice(0, 2),
|
||||
];
|
||||
|
||||
return selectedTypes.map((type, index) => {
|
||||
const templates = dailyChallengeTemplates.filter((template) => {
|
||||
|
||||
@@ -15,7 +15,7 @@ import type {
|
||||
} from "@elysium/types";
|
||||
|
||||
const basePrestigeGoldThreshold = 1_000_000;
|
||||
const runestonesPerPrestigeLevel = 10;
|
||||
const runestonesPerPrestigeLevel = 15;
|
||||
const milestoneInterval = 5;
|
||||
const milestoneRunestonesPerInterval = 25;
|
||||
|
||||
|
||||
@@ -46,13 +46,24 @@ describe("generateDailyChallenges", () => {
|
||||
expect(a.map((c) => c.id)).toEqual(b.map((c) => c.id));
|
||||
});
|
||||
|
||||
it("always includes a clicks challenge regardless of date", async () => {
|
||||
vi.setSystemTime(LA_MIDNIGHT_2024_01_15);
|
||||
const { generateDailyChallenges } = await import("../../src/services/dailyChallenges.js");
|
||||
const day1 = generateDailyChallenges("2024-01-15");
|
||||
const day2 = generateDailyChallenges("2024-01-16");
|
||||
expect(day1.some((c) => c.type === "clicks")).toBe(true);
|
||||
expect(day2.some((c) => c.type === "clicks")).toBe(true);
|
||||
});
|
||||
|
||||
it("generates different challenges for different dates", async () => {
|
||||
vi.setSystemTime(LA_MIDNIGHT_2024_01_15);
|
||||
const { generateDailyChallenges } = await import("../../src/services/dailyChallenges.js");
|
||||
const day1 = generateDailyChallenges("2024-01-15");
|
||||
const day2 = generateDailyChallenges("2024-01-16");
|
||||
// They should differ in at least one challenge ID (types vary by seed)
|
||||
expect(day1.map((c) => c.type)).not.toEqual(day2.map((c) => c.type));
|
||||
// The 2 non-clicks types should vary by seed between dates
|
||||
const day1NonClicks = day1.filter((c) => c.type !== "clicks").map((c) => c.type);
|
||||
const day2NonClicks = day2.filter((c) => c.type !== "clicks").map((c) => c.type);
|
||||
expect(day1NonClicks).not.toEqual(day2NonClicks);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -102,21 +102,21 @@ describe("isEligibleForPrestige", () => {
|
||||
|
||||
describe("calculateRunestones", () => {
|
||||
it("calculates basic runestones formula", () => {
|
||||
// floor(cbrt(4_000_000 / 1_000_000)) × 10 = floor(cbrt(4)) × 10 = 1 × 10 = 10
|
||||
// floor(cbrt(4_000_000 / 1_000_000)) × 15 = floor(cbrt(4)) × 15 = 1 × 15 = 15
|
||||
const result = calculateRunestones({ totalGoldEarned: 4_000_000, prestigeCount: 0, purchasedUpgradeIds: [] });
|
||||
expect(result).toBe(10);
|
||||
expect(result).toBe(15);
|
||||
});
|
||||
|
||||
it("applies echo runestone multiplier", () => {
|
||||
// floor(cbrt(4)) × 10 = 10; × 2 = 20
|
||||
// floor(cbrt(4)) × 15 = 15; × 2 = 30
|
||||
const result = calculateRunestones({ totalGoldEarned: 4_000_000, prestigeCount: 0, purchasedUpgradeIds: [], echoRunestoneMultiplier: 2 });
|
||||
expect(result).toBe(20);
|
||||
expect(result).toBe(30);
|
||||
});
|
||||
|
||||
it("applies purchased runestone upgrade multiplier", () => {
|
||||
// With "runestone_gain_1" purchased (multiplier 1.25): floor(10 × 1.25) = 12
|
||||
// With "runestone_gain_1" purchased (multiplier 1.25): floor(15 × 1.25) = 18
|
||||
const result = calculateRunestones({ totalGoldEarned: 4_000_000, prestigeCount: 0, purchasedUpgradeIds: ["runestone_gain_1"] });
|
||||
expect(result).toBe(12);
|
||||
expect(result).toBe(18);
|
||||
});
|
||||
|
||||
it("caps base runestones before multipliers", () => {
|
||||
|
||||
Reference in New Issue
Block a user