Overview
Both GoldUpgradeService and PrestigeUpgradeService extend BaseUpgradeService to provide upgrade management functionality. They handle different currencies (gold vs prestige cores) but share the same core mechanics for purchasing, calculating costs, and applying effects.
GoldUpgradeService
Manages upgrades purchased with gold. These upgrades are temporary and reset on prestige.
Available upgrades
Noob Gains
{
id: 'gold_strength_flat',
name: 'Noob Gains',
description: 'Gain 1 Strength per Level',
baseCost: 1,
costScaling: 1.3,
effectType: UpgradeEffectType.FLAT_STAT_BOOST,
effectValue: 1,
effectScaling: UpgradeScalingType.LINEAR
}
Professional Kaizen Trainer
{
id: 'gold_strength_stronger',
name: 'Professional Kaizen Trainer',
description: 'Gain 10 Strength per Level',
baseCost: 10,
costScaling: 1.5,
effectType: UpgradeEffectType.FLAT_STAT_BOOST,
effectValue: 10,
effectScaling: UpgradeScalingType.LINEAR
}
KaaChow Statue
{
id: 'gold_critical_chance_basic',
name: 'KaaChow Statue',
description: 'Gain 1% additive Critical Chance per Level',
baseCost: 50,
costScaling: 1.2,
effectType: UpgradeEffectType.CRITICAL_CHANCE_BOOST,
effectValue: 0.01,
effectScaling: UpgradeScalingType.LINEAR
}
Heavy Hitter
{
id: 'gold_critical_damage_basic',
name: 'Heavy Hitter',
description: 'Gain 5% additive Critical Damage per Level',
baseCost: 50,
costScaling: 1.2,
effectType: UpgradeEffectType.CRITICAL_DAMAGE_BOOST,
effectValue: 0.05,
effectScaling: UpgradeScalingType.LINEAR
}
Currency methods
protected getCurrentCurrency(): number
Returns the character’s current gold amount.
protected spendCurrency(amount: number): void
Spends gold from the character via CharacterService.spendGold().
Database persistence
public updateDatabase(): void
Saves current upgrade levels to the database using Convex mutation.
Usage:
goldUpgradeService.updateDatabase();
PrestigeUpgradeService
Manages permanent upgrades purchased with prestige cores. These upgrades persist across prestige cycles.
Available upgrades
Swift Strikes
{
id: 'attack_speed_boost',
name: 'Swift Strikes',
description: 'Reduce attack interval by 5% per Level',
baseCost: 1,
costScaling: 2,
effectType: UpgradeEffectType.ATTACK_SPEED,
effectValue: 0.05,
effectScaling: UpgradeScalingType.LINEAR
}
Titans Power
{
id: 'strength_multiplier',
name: 'Titans Power',
description: 'Increase strength by 1 per Level',
baseCost: 1,
costScaling: 1.8,
effectType: UpgradeEffectType.FLAT_STAT_BOOST,
effectValue: 1,
effectScaling: UpgradeScalingType.LINEAR
}
Kaizen Mastery
{
id: 'core_gain_boost',
name: 'Kaizen Mastery',
description: 'Increase Kaizen-Core gain by 10% per Level',
baseCost: 1,
costScaling: 2,
effectType: UpgradeEffectType.MULTIPLIER_BOOST,
effectValue: 0.1,
effectScaling: UpgradeScalingType.LINEAR
}
Fragile Foes
{
id: 'enemy_health_reduction',
name: 'Fragile Foes',
description: 'Reduce enemy health by 5% per Level',
baseCost: 1,
costScaling: 1.6,
effectType: UpgradeEffectType.ENEMY_HEALTH_REDUCTION,
effectValue: 0.05,
effectScaling: UpgradeScalingType.LINEAR
}
Hoarded Power
{
id: 'dps_per_core',
name: 'Hoarded Power',
description: 'Gain 2% DPS per unused Kaizen-Core',
baseCost: 1,
costScaling: 2.5,
effectType: UpgradeEffectType.DYNAMIC_PER_CORE,
effectValue: 0.02,
effectScaling: UpgradeScalingType.LINEAR
}
Currency methods
protected getCurrentCurrency(): number
Returns the character’s current prestige core count.
protected spendCurrency(amount: number): void
Spends prestige cores from the character via CharacterService.spendPrestigeCores().
Database persistence
public updateDatabase(): void
Saves current upgrade levels to the database using Convex mutation.
Usage:
prestigeUpgradeService.updateDatabase();
Shared methods (from BaseUpgradeService)
Both services inherit these methods from BaseUpgradeService:
Properties
allUpgrades
readonly allUpgrades: Signal<Upgrade[]>
Read-only signal containing all upgrades with their current levels.
hasLoadedFromDb
hasLoadedFromDb: Signal<boolean>
Indicates whether upgrades have been loaded from the database.
calculateCost
calculateCost(upgrade: Upgrade): number
Calculates the cost to purchase the next level of an upgrade.
Formula:
cost = baseCost * Math.pow(costScaling, currentLevel)
The upgrade object containing baseCost, costScaling, and currentLevel
Returns: The cost for the next level (floored to integer)
Usage:
const upgrade = goldUpgradeService.getUpgradeByID('gold_strength_flat');
const cost = goldUpgradeService.calculateCost(upgrade);
Cost scaling examples:
// Upgrade with baseCost: 10, costScaling: 1.5
// Level 0 → 1: 10 * (1.5^0) = 10
// Level 1 → 2: 10 * (1.5^1) = 15
// Level 2 → 3: 10 * (1.5^2) = 22
// Level 3 → 4: 10 * (1.5^3) = 33
canPurchase
canPurchase(upgradeID: string): boolean
Checks if the player has enough currency to purchase an upgrade.
The unique identifier of the upgrade
Returns: true if the upgrade can be purchased, false otherwise
Usage:
if (goldUpgradeService.canPurchase('gold_strength_flat')) {
// Show as purchasable
}
purchaseUpgrade
purchaseUpgrade(upgradeID: string): boolean
Attempts to purchase an upgrade. Checks affordability, spends currency, and increments the upgrade level.
The unique identifier of the upgrade to purchase
Returns: true if purchase was successful, false if not enough currency
Usage:
const success = goldUpgradeService.purchaseUpgrade('gold_strength_flat');
if (success) {
console.log('Upgrade purchased!');
} else {
console.log('Not enough gold');
}
This method does not persist to the database automatically. Call updateDatabase() separately to save the purchase.
getUpgradeByID
getUpgradeByID(upgradeID: string): Upgrade | undefined
Retrieves an upgrade by its unique identifier.
The unique identifier of the upgrade
Returns: The upgrade object, or undefined if not found
Usage:
const upgrade = prestigeUpgradeService.getUpgradeByID('attack_speed_boost');
if (upgrade) {
console.log(`${upgrade.name} - Level ${upgrade.currentLevel}`);
}
getTotalEffect
getTotalEffect(effectType: UpgradeEffectType): number
Calculates the total effect value for all upgrades of a specific effect type.
effectType
UpgradeEffectType
required
The effect type to sum. Valid values: FLAT_STAT_BOOST, MULTIPLIER_BOOST, ATTACK_SPEED, ENEMY_HEALTH_REDUCTION, DYNAMIC_PER_CORE, CRITICAL_CHANCE_BOOST, CRITICAL_DAMAGE_BOOST
Returns: The sum of all effects of the specified type
Usage:
const totalStrengthBoost = goldUpgradeService.getTotalEffect(
UpgradeEffectType.FLAT_STAT_BOOST
);
// If "Noob Gains" is level 5 and "Professional Kaizen Trainer" is level 3:
// Returns: (1 * 5) + (10 * 3) = 35
const attackSpeedBoost = prestigeUpgradeService.getTotalEffect(
UpgradeEffectType.ATTACK_SPEED
);
// If "Swift Strikes" is level 4:
// Returns: 0.05 * 4 = 0.20 (20% attack speed increase)
This method is heavily used in combat and damage calculations to aggregate all upgrade bonuses.
calculateEffect
calculateEffect(upgrade: Upgrade): number
Calculates the current effect value for a single upgrade based on its level and scaling type.
The upgrade object to calculate effect for
Returns: The calculated effect value
Scaling types:
- Linear:
effectValue * currentLevel
- Exponential:
Math.pow(effectValue, currentLevel)
- Fixed per level:
effectValue if level > 0, else 0
Usage:
const upgrade = prestigeUpgradeService.getUpgradeByID('strength_multiplier');
const effect = prestigeUpgradeService.calculateEffect(upgrade);
// If level is 10: effect = 1 * 10 = 10
Effect types
Upgrades can have different effect types that are applied in various parts of the game:
enum UpgradeEffectType {
FLAT_STAT_BOOST = 'flat_stat_boost', // Adds flat damage
MULTIPLIER_BOOST = 'multiplier_boost', // Increases prestige core gain
ATTACK_SPEED = 'attack_speed', // Reduces attack interval
ENEMY_HEALTH_REDUCTION = 'enemy_health_reduction', // Reduces enemy HP
DYNAMIC_PER_CORE = 'dynamic_per_core', // DPS bonus per unused core
CRITICAL_CHANCE_BOOST = 'critical_chance_boost', // Increases crit chance
CRITICAL_DAMAGE_BOOST = 'critical_damage_boost' // Increases crit damage
}
Scaling types
Upgrades scale in different ways:
enum UpgradeScalingType {
LINEAR = 'linear', // Value * Level
EXPONENTIAL = 'exponential', // Value ^ Level
FIXED_PER_LEVEL = 'fixed_per_level' // Value (if level > 0)
}
All current upgrades use LINEAR scaling in the implementation.
Database integration
Both services use Convex for real-time database synchronization:
GoldUpgradeService:
private getUpgradesFromDatabase = injectQuery(api.goldUpgrades.getGoldUpgrades, () => ({}));
private databaseUpdateMutation = injectMutation(api.goldUpgrades.updateGoldUpgradeLevels);
PrestigeUpgradeService:
private getUpgradesFromDatabase = injectQuery(api.prestigeUpgrades.getPrestigeUpgrades, () => ({}));
private databaseUpdateMutation = injectMutation(api.prestigeUpgrades.updatePrestigeUpgradeLevels);
Upgrades are loaded on initialization and merged with default definitions:
effect(() => {
const dbUpgrades = query.data();
if (!dbUpgrades) return;
const merged = defaultUpgrades.map((upgrade) => {
const savedUpgrade = dbUpgrades.find(s => s.id === upgrade.id);
return {
...upgrade,
currentLevel: savedUpgrade?.currentLevel ?? 0
};
});
this.upgrades.set(merged);
});
See the Upgrade model for the complete Upgrade interface and enum definitions.