feat: implement Active Disciplines system
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 31s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 31s
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
// ─── Discipline Math Utilities ────────────────────────────────────────────────
|
||||
// Continuous scaling formulas for Active Disciplines
|
||||
|
||||
import type { DisciplineState, DisciplineDefinition } from '../types/disciplines';
|
||||
|
||||
/**
|
||||
* Calculate continuous stat bonus from discipline XP
|
||||
* StatBonus = BaseValue * (XP / ScalingFactor)^0.65
|
||||
*/
|
||||
export function calculateStatBonus(
|
||||
baseValue: number,
|
||||
xp: number,
|
||||
scalingFactor: number
|
||||
): number {
|
||||
if (xp <= 0) return 0;
|
||||
const ratio = xp / scalingFactor;
|
||||
const power = Math.pow(ratio, 0.65);
|
||||
return baseValue * power;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate dynamic mana drain per tick
|
||||
* ManaDrainPerTick = BaseDrain * (1 + (XP / DifficultyFactor)^0.4)
|
||||
*/
|
||||
export function calculateManaDrain(
|
||||
baseDrain: number,
|
||||
xp: number,
|
||||
difficultyFactor: number
|
||||
): number {
|
||||
if (xp <= 0) return baseDrain;
|
||||
const ratio = xp / difficultyFactor;
|
||||
const power = Math.pow(ratio, 0.4);
|
||||
return baseDrain * (1 + power);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate infinite perk tier
|
||||
* PerkTier = Math.max(0, Math.floor((XP - Threshold) / Interval) + 1)
|
||||
*/
|
||||
export function calculatePerkTier(
|
||||
xp: number,
|
||||
threshold: number,
|
||||
interval: number
|
||||
): number {
|
||||
if (xp < threshold) return 0;
|
||||
const excess = xp - threshold;
|
||||
return Math.max(0, Math.floor(excess / interval) + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if discipline can be activated (has required mana type)
|
||||
*/
|
||||
export function canActivateDiscipline(
|
||||
discipline: DisciplineDefinition,
|
||||
gameState: { elements?: Record<string, any> }
|
||||
): boolean {
|
||||
if (discipline.manaType === 'raw') return true;
|
||||
const element = gameState.elements?.[discipline.manaType];
|
||||
return element && element.unlocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if discipline can proceed (has sufficient mana for drain)
|
||||
*/
|
||||
export function canProceedDiscipline(
|
||||
discipline: DisciplineDefinition,
|
||||
disciplineState: DisciplineState,
|
||||
gameState: { elements?: Record<string, any>; rawMana?: number }
|
||||
): boolean {
|
||||
if (disciplineState.paused) return false;
|
||||
|
||||
const drain = calculateManaDrain(
|
||||
discipline.drainBase,
|
||||
disciplineState.xp,
|
||||
discipline.difficultyFactor
|
||||
);
|
||||
|
||||
if (discipline.manaType === 'raw') {
|
||||
return (gameState.rawMana || 0) >= drain;
|
||||
}
|
||||
|
||||
const element = gameState.elements?.[discipline.manaType];
|
||||
return element && element.current >= drain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unlocked perks for a discipline
|
||||
*/
|
||||
export function getUnlockedPerks(
|
||||
discipline: DisciplineDefinition,
|
||||
xp: number
|
||||
): DisciplinePerk[] {
|
||||
return discipline.perks.filter(perk => {
|
||||
if (perk.type === 'once') {
|
||||
return xp >= perk.threshold;
|
||||
} else if (perk.type === 'capped') {
|
||||
const tier = calculatePerkTier(xp, perk.threshold, perk.value);
|
||||
return tier > 0;
|
||||
} else if (perk.type === 'infinite') {
|
||||
return xp >= perk.threshold;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate total stats from all active disciplines
|
||||
*/
|
||||
export function calculateDisciplineStats(
|
||||
disciplines: DisciplineDefinition[],
|
||||
states: DisciplineState[]
|
||||
): Record<string, number> {
|
||||
const stats: Record<string, number> = {};
|
||||
|
||||
disciplines.forEach((discipline, index) => {
|
||||
const state = states[index];
|
||||
if (!state || state.paused) return;
|
||||
|
||||
const bonus = calculateStatBonus(
|
||||
discipline.statBonus.baseValue,
|
||||
state.xp,
|
||||
discipline.scalingFactor
|
||||
);
|
||||
|
||||
const statKey = discipline.statBonus.stat;
|
||||
stats[statKey] = (stats[statKey] || 0) + bonus;
|
||||
});
|
||||
|
||||
return stats;
|
||||
}
|
||||
Reference in New Issue
Block a user