57
packages/shared/src/xp.ts
Executable file
57
packages/shared/src/xp.ts
Executable file
@@ -0,0 +1,57 @@
|
||||
import type { AdventureItemState, XpSource } from "./types";
|
||||
|
||||
export const XP_AWARDS = {
|
||||
daily_visit: 5,
|
||||
adventure_started: 10,
|
||||
adventure_partial: 25,
|
||||
adventure_done: 40,
|
||||
reflection: 30,
|
||||
spiritual_per_check: 5,
|
||||
spiritual_daily_cap: 25,
|
||||
reading_per_10_pages: 15,
|
||||
reading_daily_cap: 60,
|
||||
exercise: 50,
|
||||
exploration: 100,
|
||||
weekly_review: 150,
|
||||
rest_day: 15,
|
||||
book_complete: 200,
|
||||
} as const;
|
||||
|
||||
export const DAILY_SOFT_CAPS: Partial<Record<XpSource, number>> = {
|
||||
adventure_item: 200,
|
||||
spiritual: 25,
|
||||
reading: 60,
|
||||
};
|
||||
|
||||
export function xpForAdventureState(state: AdventureItemState): number {
|
||||
switch (state) {
|
||||
case "started":
|
||||
return XP_AWARDS.adventure_started;
|
||||
case "partial":
|
||||
return XP_AWARDS.adventure_partial;
|
||||
case "done":
|
||||
return XP_AWARDS.adventure_done;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function applyDiminishingReturns(
|
||||
amount: number,
|
||||
earnedToday: number,
|
||||
softCap: number
|
||||
): number {
|
||||
if (earnedToday >= softCap) {
|
||||
return Math.floor(amount * 0.25);
|
||||
}
|
||||
if (earnedToday + amount > softCap) {
|
||||
const atFull = softCap - earnedToday;
|
||||
const over = amount - atFull;
|
||||
return atFull + Math.floor(over * 0.25);
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
export function xpForReadingPages(pages: number): number {
|
||||
return Math.floor(pages / 10) * XP_AWARDS.reading_per_10_pages;
|
||||
}
|
||||
Reference in New Issue
Block a user