Skip to content

Archived on 2026-10-24. The Godot rewrite is cancelled. Migration decisions and work checklists below are withdrawn. Original claims, code examples, file paths, and completion statements have not all been revalidated. Use the current documentation and issue register for maintenance decisions.

Upgrade System Analysis

Purpose

The upgrade system controls level-up choices, chest/boss rewards, permanent shop modifiers, special upgrades, ability unlocks, weapon level evolution, and timed/counter-based upgrade evolutions.

Current Unity Implementation

Main scripts:

Path Script Role
Assets/Script/Shared/ScriptableObjects/Upgrade.cs Upgrade Data asset for basic/special/boss/evo upgrades.
Assets/Script/Game/GameSystem/Rewards/RewardRoller.cs RewardRoller Builds reward pool, rolls card choices, handles reward phases and reroll.
Assets/Script/Game/GameSystem/Upgrades/UpgradeSelection.cs UpgradeSelection Handles one/two-player card navigation and confirmation.
Assets/Script/Game/UI/GameHUD/Upgrades/UpgradeButton.cs UpgradeButton Stores one card's upgrade data and calls UpgradeFunction.
Assets/Script/Game/GameSystem/Upgrades/UpgradeFunction.cs UpgradeFunction Applies upgrade effects through a large switch on UpgradeList.
Assets/Script/Game/GameSystem/Upgrades/UpgradeEvoFunction.cs UpgradeEvoFunction Starts evolution conditions and swaps old upgrade/ability for evolved upgrade.
Assets/Script/Game/GameSystem/Upgrades/WeaponEvoData.cs WeaponEvoData Character weapon-level evolution functions.
Assets/Script/App/Managers/ShopManager.cs ShopManager Permanent shop upgrades that become GameSession modifiers.
Assets/Script/Shared/ScriptableObjects/ShopUpgrade.cs ShopUpgrade Shop upgrade data and costs.

Key Data

Upgrade fields:

Field Meaning
idname Stable upgrade id used by save/leaderboard/localization.
upgradeName Display name.
rarity Basic, Uncommon, Rare, Epic, Legendary, Unique, Mythic, Evo.
upgradeList Array of UpgradeList enum effects.
value Parallel array of effect values.
ability Ability asset to equip or use as requirement/evolution id.
appearsInStages Stage filter.
weight, modifiedWeight Roll weight and runtime modified weight.
isBasicUpgrade, appearInSpecialChest Reward table classification.
maxUpgrade, upgradeTaken Per-run limit and runtime count.
requiredUpgrade, requiredAchievement, isUnlocked Gating.
evolve Evolved upgrade asset.
popularity Used by leaderboard/popularity UI.

UpgradeList effect categories:

  • Stat add/sub: DMG, ASP, CDMG, CCH, RS, MS, AMMO, HP, STM, SAMP.
  • Stat modifiers: DMGMODIF, ASPMODIF, CDMGMODIF, CCHMODIF, RSMODIF, MSMODIF, AMMOMODIF, HPMODIF, STMMODIF, SAMPMODIF.
  • Ability: EQUIPABILITY.
  • Utility/progression: MAGNET, REROLL, STAMINAREGEN, REVIVE, POTIONBAG, WEAPONLEVELUP.
  • Special: DRONE, ARCHMAGE, JETPROP, KARMAYANA, EVOUPGRADE, and others.

Runtime Flow

Reward Table Import

  1. GameInitialization.ImportRewardTable() clears reward tables.
  2. It iterates all special upgrades from GameDataLoader.GetAllUpgrades().
  3. If an upgrade appears in the current stage:
  4. appearInSpecialChest upgrades are also added to the boss/ultimate table.
  5. Mythic upgrades are skipped from normal special reward import.
  6. Other eligible upgrades are added to the special table.
  7. It iterates all basic upgrades from GetAllBasicUpgrades() and adds stage-eligible basic upgrades.
  8. PrepareRewardTable() resets upgradeTaken to 0 on all table entries.

Reward Rolling

  1. GameManager.EnqueueReward() sends reward types into RewardRoller.
  2. RewardRoller.ProcessRewardQueue() starts rolling if no reward phase is active.
  3. RollTheUpgradeTable() sets reward state/phase and chooses a source table:
  4. LevelUpReward: basic upgrades.
  5. SpecialReward: special upgrades.
  6. BossReward: ultimate/boss upgrades.
  7. Candidate upgrades are filtered:
  8. Revive is blocked if all relevant players are alive.
  9. Weapon level is blocked if maxed.
  10. Some vampire/basic edge cases are filtered.
  11. Special rewards require unlock and required abilities.
  12. Roll weights are modified by luck for Epic, Legendary, and Mythic rarities.
  13. Cards are rolled without duplicates by removing chosen upgrades from currentUpgrade.
  14. UI cards are instantiated and configured.
  15. DisplayAnimation() moves reward phase to Selecting and activates selection markers.

Selection

  1. UpgradeSelection.Update() only processes card navigation/selection when game is paused and reward phase is Selecting.
  2. Each active player moves a marker left/right and locks a choice with Dash input.
  3. Two active players cannot choose the same card.
  4. Once all active players lock a selection, ConfirmSelect() waits briefly.
  5. Each selected UpgradeButton calls UpgradeFunction.SelectUpgrade(playerIndex, ...).
  6. Reward UI is destroyed, RewardRoller.CompleteReward() clears reward state, and the game resumes.

Applying Upgrades

UpgradeFunction.SelectUpgrade():

  1. Gets GameManager.instance.player[playerIndex].
  2. Increments upgrade.upgradeTaken if limited.
  3. Iterates upgradeList and value arrays.
  4. Applies each effect through a switch.
  5. Stat effects call PlayerModifier add/modify methods.
  6. Ability effects call AbilityFunction.AddAbility.
  7. Special effects directly mutate player fields, ability holder fields, game manager reroll, companion spawns, revival state, or weapon evolution.

Evolution

UpgradeEvoFunction.StartEvo():

  1. Builds an UpgradeEvoData from upgrade.evolve.
  2. Switches on the old upgrade ability type.
  3. Starts either:
  4. counter-based evolution, such as collect 300 SuperMagnet coins or 500 reflected damage,
  5. time-based evolution, such as 120 seconds.
  6. Once condition is met, plays evolve sound, applies evolved upgrade via UpgradeFunction.SelectUpgrade, and removes the old ability.

Dependencies

  • Reward system depends on GameManager as the owner of all serialized UI/reward references.
  • Upgrade logic depends on Player, PlayerModifier, AbilityHolder, AbilityFunction, GameSession, PoolManager, WeaponEvoData, UpgradeEvoFunction, GameDataCount.
  • UI depends on DOTween, InputManager, AudioResources, and Game.Audio.
  • Unlock/progression depends on AchievementManager, Save, and GameDataLoader.

Problems / Risks

  • UpgradeFunction is a large hardcoded switch.
  • Upgrade.upgradeList and value are parallel arrays; mismatched lengths would break or misapply effects.
  • Runtime state (upgradeTaken, modifiedWeight, isUnlocked) is stored on shared ScriptableObject assets.
  • Reward rolling and UI animation are coupled in RewardRoller.
  • UpgradeSelection requires GameManager.instance.isPaused, while reward state is tracked separately as RewardPhase and GameState.IsRewarding.
  • Evolution conditions are hardcoded by ability type.
  • Some conditions assume two player slots exist.
  • Upgrade ids use both idname and upgradeName; saves use some upgradeName keys for special unlocks.

Migration Notes for Godot

Preserve:

  • Reward types: level-up, special chest, boss chest.
  • Rarity/weight/luck behavior.
  • Required achievement/required ability gating.
  • Max upgrade count behavior.
  • Two-player card selection restrictions.
  • Evolution conditions and final swap behavior.
  • Old shop upgrade values and costs only as balancing/save-conversion reference.

Redesign:

UpgradeResource
- id
- display/localization keys
- rarity
- roll weight
- stage filters
- max count
- requirements
- effects: Array[UpgradeEffectResource]

UpgradeRuntimeState
- times_taken
- modified_weight
- unlocked for current run if needed

UpgradeEffect
- apply(context)
- examples: StatAddEffect, StatMultiplyEffect, UnlockAbilityEffect, SpawnCompanionEffect, ReviveEffect, StartEvolutionEffect

RewardDirector
- owns queue and roll logic
- no UI animation details

RewardUI
- displays cards and emits selected(upgrade_id, player_id)

Do not copy:

  • One giant UpgradeFunction switch.
  • Runtime mutation of upgrade resources.
  • Parallel upgradeList/value arrays.
  • Card UI instantiation logic inside reward roll logic.

Open Questions

  • Which upgrades in Testing, InDevelopment, and Need Revamp should be excluded from Godot data conversion?
  • Most saved content is expected to use manually typed ids, but audit whether any upgrade saves still use upgradeName or localized names.
  • Exact reward-state pause behavior should be separated from pause-menu behavior so selection cannot soft-lock.