Files
Michele Rossi 81a4058b04 systems rework: buffs, prestige graph, research, modular architecture
Decouples core systems from centralized globals in favor of catalogue-based architecture and data-driven content.

   Key changes:
   - Prestige: node-based buff tech tree, graph panel, progress bar
   - Research: multi-worker system, per-generator research, xp generation
   - Ascension: meta-currency layer via multi-currency prestige resets
   - Buffs: refactored as generator-independent via catalogues
   - UI: currency panel, edge-scrolling camera + zoom, current-goal panel
   - Alchemy Tower: crafting building with recipe/cost system
   - Testing: 7 test suites (ascension, prestige, research, goals)
   - Content: migrated from hardcoded idles/ to gym format (tiny_sword)
2026-05-07 20:36:21 +00:00
..

Generator Module Documentation

Overview

The generator/ subfolder contains the core idle game mechanics: automated resource production with scaling costs, upgrades (buffs), and manual interaction.

Files

File Purpose
currency_generator.gd Runtime generator logic (Node2D)
currency_generator_data.gd Balancing data resource
generator_buff_data.gd Buff/upgrade definitions
generator_container.gd UI panel for generator stats

Architecture

CurrencyGenerator (Node2D)
├── Handles production cycles
├── Manages purchases
├── Processes clicks/hover
└── GeneratorPanel (UI)
	├── Shows stats/costs
	└── Buff upgrade buttons

CurrencyGeneratorData

Resource class for generator balancing data.

Key Properties

@export var id: StringName = &""              # Unique identifier
@export var name: String = ""                 # Display name
@export var starts_unlocked: bool = true      # Visible at game start
@export var purchase_currency: Currency       # What to spend
@export var unlock_goal: GoalData             # Goal to unlock this (behavior defined in GoalData)

# Cost formula: cost = base * coefficient^owned
@export var initial_cost: float = 10.0        # Base cost
@export var coefficient: float = 1.15         # Growth factor

# Production
@export var initial_time: float = 1.0         # Seconds per cycle
@export var initial_productivity: float = 1.0 # Resources per cycle

# Milestones
@export var milestone_step: int = 25          # Every N units
@export var milestone_multiplier: float = 2.0 # x multiplier

# Manual click
@export var click_mantissa: float = 1.0
@export var click_exponent: int = 0
@export var click_cooldown_seconds: float = 0.2

Cost Formula

Bulk Buy Cost (geometric series):

total_cost = base * r^owned * ((r^n - 1) / (r - 1))

Where:

  • base = initial_cost
  • r = coefficient
  • owned = current count
  • n = amount to buy

Max Buy (inverse formula):

max = floor(log((currency * (r-1) / (base * r^owned)) + 1) / log(r))

Production Formula

production_per_cycle = initial_productivity * owned * run_multiplier * milestone_mult * purchased_mult
production_per_second = production_per_cycle / initial_time

CurrencyGenerator

Runtime node instance attached to generator scenes.

Signals

signal purchase_completed(amount, total_owned, total_purchased, total_cost)
signal production_tick(amount, cycle_count, total_owned)
signal buff_purchased(buff_id, new_level, cost, cost_currency_id)
signal goal_achieved(generator_id, goal_id)  # Emitted when generator unlocks from goal

Key Methods

# Purchase
func buy(amount: int = 1) -> bool
func buy_max() -> int
func get_cost_for_amount(amount: int) -> BigNumber
func can_buy(amount: int) -> bool

# Goal-based unlock (automatic when goal completes)
# Generator listens to GameState.goal_completed signal

Production

func grant_currency(amount: BigNumber) func get_effective_auto_run_multiplier() -> float

Buffs

func buy_buff(buff_id: StringName) -> bool func get_buff_level(buff_id: StringName) -> int func is_buff_unlocked(buff_id: StringName) -> bool


### Production Cycle

1. Accumulate `cycle_progress_seconds` in `_process()`
2. When `>= initial_time`, grant production
3. Emit `production_tick` signal
4. Multiply by:
   - Owned count
   - Run multiplier (export)
   - Buff multipliers (auto_production)
   - Milestone bonuses
   - Purchase boost

## GeneratorBuffData

Defines upgradeable modifiers for generators.

### Buff Kinds

```gdscript
enum BuffKind {
	AUTO_PRODUCTION_MULTIPLIER,  # x output per cycle
	MANUAL_CLICK_MULTIPLIER,      # x click reward
	RESOURCE_PURCHASE             # Instant currency grant
}

Key Properties

@export var id: StringName = &""
@export var target_ids: Array[StringName] = []  # Generators affected
@export var kind: BuffKind
@export var max_level: int = -1                  # -1 = unlimited
@export var base_effect: float = 1.0             # Starting multiplier
@export var effect_increment: float = 0.1        # +per level

@export var base_cost_mantissa: float = 10.0
@export var base_cost_exponent: int = 0
@export var cost_multiplier: float = 1.5         # Cost growth

# Effect: base_effect + (effect_increment * level)
func get_effect_multiplier(level: int) -> float

Cost Formula

cost_for_level = base_cost * cost_multiplier^level

Resource Purchase Buff

Special buff type that grants instant currency:

resource_purchase_amount = base_amount * (resource_purchase_increment_multiplier^level)

GeneratorPanel

UI component showing generator information.

Displays

  • Generator name and owned count
  • Next purchase cost
  • Production per second
  • Buff upgrade buttons with costs

Signals Connected

  • purchase_completed - Refresh UI
  • production_tick - Update production display
  • generator_buff_level_changed - Refresh buff rows

Goal-Based Unlock

Generators with unlock_goal automatically listen to LevelGameState.goal_completed signal:

  • When goal completes, generator unlocks automatically
  • Goal's unlock_behavior (AUTOMATIC/MANUAL) controls when goal completes
  • Manual goals require player to click "Unlock" button first
# In CurrencyGenerator._ready():
level_game_state.goal_completed.connect(_on_goal_completed)

func _on_goal_completed(goal_id: StringName) -> void:
	if data.has_unlock_goal() and data.get_unlock_goal_id() == goal_id:
		unlock_generator()

Prestige Integration

Generators automatically apply prestige multipliers:

effective_multiplier = run_multiplier * buff_multiplier * prestige_multiplier

On prestige via LevelGameState.reset_for_prestige():

  1. Current currencies reset to 0
  2. cycle_progress_seconds reset
  3. Buff levels reset to 0
  4. Goal completion state cleared and re-initialized
  5. Research XP and levels reset to 0

See Also

  • core/level_game_state.gd - Generator state storage
  • core/goals/goal_data.gd - Unlock conditions
  • core/prestige/prestige_manager.gd - Multiplier application