<aside> <img src="/icons/reorder_gray.svg" alt="/icons/reorder_gray.svg" width="40px" />
Navigation
</aside>
<aside> 🔧 The Upgrades module is a player upgrade/perk system: stat-boosting upgrades with multiple purchasable stages, priced in Coins or Prestige, persisted per type in save, and surfaced through the Upgrades panel and the Skilltree.
</aside>
Base module (Assets/Project Files/Modules/Upgrades):
ScriptableObject that owns stage progression, level, save wiring, and cost/preview lookups. Every concrete upgrade asset inherits from it.Upgrade<T> - generic subclass of BaseUpgrade holding a typed T[] upgrades stage array. Every concrete upgrade in this project derives from this, not BaseUpgrade directly.BaseUpgradeStage - abstract data for one stage: price, currency type, preview sprite. Concrete stage classes add the stat value field.IUpgrade - minimal interface (UpgradeType, Title, Upgrades, Init(), UpgradeStage()) that BaseUpgrade implements.UpgradesController - MonoBehaviour with static facade methods. Registers every upgrade from both the Upgrades-panel database and the Skilltree database into one shared type-keyed registry, restores levels from save, and exposes GetUpgrade<T> / GetActiveTier<T>.UpgradesDatabase / UpgradesDatabaseEntry - ScriptableObject listing every BaseUpgrade asset shown in the Upgrades panel, plus each row's reveal threshold and optional parent upgrade (tiered continuations).MD_UpgradeType - the UpgradeType enum. One value per upgrade, including Skilltree-only and tier-II continuations. Modifiable per project.UpgradeSavableObject - ISaveObject holding one upgrade's level. One instance per UpgradeType, keyed "upgrades:{type}".Game layer (Assets/Project Files/Game/Scripts/Upgrades):
UpgradesPanelController - static class for the Upgrades panel's business logic: reveal gating, affordability, purchasing, and dismissed-maxed-row tracking.UIUpgradesPanel - UIPage that lists visible upgrade rows and drives the ABOUT panel for the selected upgrade.UIUpgradeRow - one row prefab script: icon, name, level, before/after stat preview, price, buy button, maxed-out animation and dismissal.UpgradesButton - HUD button that opens the panel and shows a notification dot when any revealed row is affordable.UpgradeEffects - static class gameplay systems call into to read an upgrade's effective value, with a fallback to a base value when the upgrade isn't registered yet.Concrete/ - one Upgrade<T> subclass per upgrade type (Chests Per Spawn, Chest Damage, Critical Click Chance, One Shot Chance, Button Return Speed, per-tier chest spawn chance, per-rarity item value, and Skilltree-only nodes). See the reference table below.All classes below live in Assets/Project Files/Game/Scripts/Upgrades/Concrete/ and follow the same shape: an Upgrade<T> subclass with an empty Init(), a nested Stage class with one stat field, and a GetStatValueText override for the panel's before/after display.
Tiered Upgrades-panel rows
ChestsPerSpawnUpgrade (ChestsPerSpawn / ChestsPerSpawnII) - how many chests spawn per button tap. Two tiers, resolved via GetActiveTier<T> in UpgradeEffects.GetChestsPerSpawn (see the worked example above).Single-tier Upgrades-panel rows (continued in the Skilltree on the same asset)
CriticalClickChanceUpgrade (CriticalClickChance) - chance for a click to roll critical. Its Skilltree stages are extra elements appended to the same asset's upgrades array, not a separate row.UncommonChestSpawnChanceUpgrade (UncommonChestSpawnChance) - additive bonus on the Uncommon chest's base spawn weight. Same same-asset Skilltree continuation as above.Other Upgrades-panel rows
ChestDamageUpgrade (ChestDamage) - base damage dealt per chest hit, read by ClickerController.RegisterChestHit via UpgradeEffects.GetChestDamage - see Core Clicker Loop.ButtonReturnSpeedUpgrade (ButtonReturnSpeed) - how fast the main button's press animation returns to rest, read by MainButtonPressBehavior.Press() via UpgradeEffects.GetButtonReturnDuration.EpicChestSpawnChanceUpgrade (EpicChestSpawnChance) - additive bonus on the Epic chest's base spawn weight.CommonItemsValueUpgrade / UncommonItemsValueUpgrade / RareItemsValueUpgrade (CommonItemsValue / UncommonItemsValue / RareItemsValue) - per-rarity sell value; RareItemsValueUpgrade covers ItemRarity.Epic (shown to players as "Rare"). Each stage's value replaces ChestData's authored baseline outright; see UpgradeEffects.GetItemBaseValue.Skilltree-only nodes
HelpingHandUpgrade (HelpingHandSkilltree) - single-rank unlock for the auto-clicking hand.InteractionRadiusUpgrade (InteractionRadius) - multiplier on the shared chest-tap/item-pickup interaction radius, read via UpgradeEffects.GetInteractionRadius.OneShotChanceUpgrade (OneShotChanceSkilltree) - chance for a chest hit to instantly clear its remaining health, read by ClickerController.RollOneShot via UpgradeEffects.GetOneShotChance; only rolled while the chest is above GameData.OneShotHealthThreshold - see Core Clicker Loop.ItemValueSkilltreeUpgrade (ItemValueGlobalSkilltree) - global sell-value multiplier, stacking multiplicatively on top of the per-rarity Items Value rows.RoyalChestSpawnChanceUpgrade (RoyalChestSpawnChanceSkilltree) / WarriorChestSpawnChanceUpgrade (WarriorChestSpawnChanceSkilltree) - standalone nodes stacking an additional spawn-weight bonus on top of the Epic/Uncommon Upgrades-panel rows respectively.TentaclesChestSpawnChanceUpgrade (TentaclesChestSpawnChanceSkilltree) / FrostChestSkilltreeUpgrade (FrostChestSpawnChanceSkilltree) / ChromaticChestSkilltreeUpgrade (ChromaticChestSpawnChanceSkilltree) - additive chance bonus for chest-spawn effects that have no Upgrades-panel row of their own; stacks on ChestEffectEntry's flat base chance. See UpgradeEffects.GetEffectChance and GetEffectUnlocked.UpgradeLevel
0-based purchased level, backed by the upgrade's UpgradeSavableObject. Setting it does not fire OnUpgraded - use UpgradeStage() to advance it through code.
CurrentStage / NextStage / GetCurrentStage() / GetNextStage()
CurrentStage/NextStage (declared on BaseUpgrade) return BaseUpgradeStage; NextStage is null at max level. GetCurrentStage()/GetNextStage() (declared on Upgrade<T>) return the typed T stage instead - prefer these on a concrete upgrade so the stat field is directly accessible without a cast.
IsMaxedOut / UpgradesCount / GetUpgradeCost(level)
IsMaxedOut is true once UpgradeLevel + 1 >= UpgradesCount. GetUpgradeCost(level) returns -1 past the last stage.
OnUpgraded
SimpleCallback event fired by UpgradeStage() and ResetUpgrade(). See How to hook into an upgrade's events above.
ResetForRebirth()
Resets UpgradeLevel to 0, unless any purchased stage was priced in CurrencyType.Prestige (Skilltree progress is kept across Rebirth by design).
GetUpgrade<T>(UpgradeType type)
Static lookup by type. Returns null and logs an error if the type isn't registered - always null-check the result.
GetActiveTier<T>(params UpgradeType[] tiersHighToLow)
Resolves a tiered chain (see How to add a tiered continuation above) to whichever tier the player has actually leveled, listing tiers from highest to lowest and falling back to the lowest tier.
IsInitialized
True once Init() has run. Check before calling GetUpgrade<T>/GetActiveTier<T> from code that might run before GameController boots.
GetTotalPurchasedLevels()
Sum of every registered upgrade's level, across both the Upgrades panel and the Skilltree. Not the same as UpgradesPanelController's own panel-only total used for reveal gating.
IsRevealed(UpgradesDatabaseEntry entry) / GetVisibleEntries()
IsRevealed checks revealThreshold against the panel-only purchased total, plus parentUpgrade.IsMaxedOut when the entry has one. GetVisibleEntries() returns every currently-revealed, non-dismissed row - what UIUpgradesPanel renders.
CanAfford(BaseUpgrade upgrade) / HasAffordableUpgrade()
CanAfford checks the next stage's price against CurrencyController.HasAmount. HasAffordableUpgrade() is true if any visible row is affordable - drives UpgradesButton's notification dot.
TryPurchase(BaseUpgrade upgrade)
Advances the upgrade one stage and spends currency if affordable; returns false and does nothing otherwise. Marks the save dirty on success.
Database
Static singleton set by Init(). UpgradesPanelController reads this directly rather than going through UpgradesController, since reveal thresholds are panel-specific data the Skilltree doesn't share.
UpgradesDatabaseEntry.Upgrade / RevealThreshold / ParentUpgrade
One entry per row shown in the Upgrades panel. ParentUpgrade is only set for a tiered continuation's second (or later) entry.