Skip to content

Gameplay Features (Opt-in)

Relevant source files

This page documents gameplay-modifying features that require explicit user enablement. These features alter core game mechanics such as node limits, upgrade purchasing, and currency values. All features covered here are clearly separated from Quality of Life and Visual enhancements to ensure players make informed decisions about their gameplay experience.

For Quality of Life features that don’t affect game balance, see Quality of Life Features. For visual customization options, see Visual Enhancements.


Gameplay features in Taj’s Mod are designed with the following principles:

PrincipleImplementation
Opt-in by DefaultMost gameplay modifiers require user action to enable
Clear SeparationLocated in dedicated “Cheats” tab or clearly marked
Persistent ConfigurationAll settings saved to user://tajs_mod_config.json
Non-destructiveCan be disabled at any time to return to vanilla behavior

Sources: README.md L47-L51

mod_main.gd L626-L628


The following diagram shows how gameplay feature managers integrate with the main orchestrator:

flowchart TD

ModMain["mod_main.gd<br>Main Orchestrator"]
Config["ConfigManager<br>user://tajs_mod_config.json"]
GlobalsState["Globals<br>Game State Variables"]
BuyMax["BuyMaxManager<br>buy_max_manager.gd"]
Cheat["CheatManager<br>cheat_manager.gd"]
Upgrade["UpgradeManager<br>upgrade_manager.gd"]
NodeLimit["node_limit<br>50-2000+/∞"]
BuyMaxStrat["buy_max_strategy<br>0-3 (enum)"]
UpgradeMult["upgrade_multiplier<br>2-100x"]
BuyMaxEnabled["buy_max_enabled<br>bool"]

ModMain --> BuyMax
ModMain --> Upgrade
ModMain --> Cheat
Config --> NodeLimit
Config --> BuyMaxStrat
Config --> UpgradeMult
Config --> BuyMaxEnabled
NodeLimit --> GlobalsState
UpgradeMult --> GlobalsState
BuyMax --> Config
BuyMax --> BuyMaxStrat
ModMain --> BuyMax
ModMain --> BuyMaxEnabled

subgraph subGraph1 ["Configuration Keys"]
    NodeLimit
    BuyMaxStrat
    UpgradeMult
    BuyMaxEnabled
end

subgraph subGraph0 ["Gameplay Managers"]
    BuyMax
    Cheat
    Upgrade
end

Sources: mod_main.gd L406-L420

mod_main.gd L320-L321

mod_main.gd L512-L517


The node limit control allows players to adjust or remove the maximum number of nodes allowed on the board. This directly modifies the Globals.custom_node_limit value that the base game uses for validation.

SettingRangeDefaultConfig Key
Node Limit50-2000400node_limit
Unlimited ModeDisabledSpecial value (10000)

The node limit slider is implemented with custom ∞ support:

sequenceDiagram
  participant SettingsUI Slider
  participant mod_main.gd
  participant ConfigManager
  participant Globals.gd Extension

  SettingsUI Slider->>mod_main.gd: "_add_node_limit_slider()"
  mod_main.gd->>SettingsUI Slider: "add_slider(50-2000)"
  note over SettingsUI Slider: User drags slider
  SettingsUI Slider->>mod_main.gd: "callback(value)"
  mod_main.gd->>ConfigManager: "set_value('node_limit', value)"
  mod_main.gd->>Globals.gd Extension: "custom_node_limit = value"
  note over mod_main.gd: Special ∞ handling
  loop [value >= 2000]
    mod_main.gd->>SettingsUI Slider: "Display ∞"
    mod_main.gd->>Globals.gd Extension: "custom_node_limit = 10000"
    mod_main.gd->>SettingsUI Slider: "Display value"
    mod_main.gd->>Globals.gd Extension: "custom_node_limit = value"
  end

The slider implementation includes:

  • Custom label updates showing current/max nodes
  • ∞ symbol display when slider reaches 2000
  • Immediate application to Globals.custom_node_limit
  • Persistence through config save

Sources: mod_main.gd L551-L557

mod_main.gd L153-L155

The node counter label displays real-time information:

Nodes: 247 / 400

When at or near limit, the label color changes to warn the player.

Sources: mod_main.gd L541-L548

mod_main.gd L183-L184


The Buy Max system adds a split-button UI to upgrade tabs that allows bulk purchasing of upgrades using one of four configurable strategies. The system is implemented as a standalone manager that injects itself into the game’s upgrade UI.

flowchart TD

ButtonsPanel["ButtonsPanel/ButtonsContainer<br>Vanilla upgrade tab UI"]
SplitButton["BuyMaxContainer<br>Split button UI"]
MainBtn["BuyMaxButton<br>Buy Max"]
StrategyBtn["StrategyButton<br>▼ dropdown"]
BuyMaxMgr["BuyMaxManager<br>buy_max_manager.gd"]
StrategyEnum["Strategy enum<br>ROUND_ROBIN|CHEAPEST_FIRST|EXPENSIVE_FIRST|TOP_TO_BOTTOM"]
GetPanels["_get_active_upgrade_panels()<br>Find visible upgrades"]
FilterTokens["Filter token upgrades<br>currency:token excluded"]
DispatchStrat["Match strategy<br>_buy_round_robin() etc"]
UpgradePanels["upgrade_panel instances<br>can_purchase() / _on_purchase_pressed()"]
Currency["Globals.currencies<br>money|research"]

MainBtn --> BuyMaxMgr
StrategyBtn --> BuyMaxMgr
BuyMaxMgr --> GetPanels
DispatchStrat --> UpgradePanels

subgraph subGraph3 ["Game Integration"]
    UpgradePanels
    Currency
    UpgradePanels --> Currency
end

subgraph subGraph2 ["Execution Layer"]
    GetPanels
    FilterTokens
    DispatchStrat
    GetPanels --> FilterTokens
    FilterTokens --> DispatchStrat
end

subgraph subGraph1 ["Manager Layer"]
    BuyMaxMgr
    StrategyEnum
    BuyMaxMgr --> StrategyEnum
end

subgraph subGraph0 ["UI Layer"]
    ButtonsPanel
    SplitButton
    MainBtn
    StrategyBtn
    ButtonsPanel --> SplitButton
    SplitButton --> MainBtn
    SplitButton --> StrategyBtn
end

Sources: extensions/scripts/utilities/buy_max_manager.gd L1-L451

The system provides four distinct strategies for bulk purchasing:

StrategyBehaviorUse Case
Round RobinBuys 1 level of each upgrade in rotationEven distribution across all upgrades
Cheapest FirstAlways purchases the cheapest available upgradeMaximize number of purchases
Most ExpensiveBuys the most expensive affordable upgradePrioritize high-impact upgrades
Top to BottomMaxes out upgrades in UI orderSequential completion

Sources: extensions/scripts/utilities/buy_max_manager.gd L12-L31

Each strategy is implemented as a separate method that operates on filtered upgrade panels:

flowchart TD

Start["_execute_buy_max()"]
GetPanels["_get_active_upgrade_panels()<br>Get visible panels"]
Filter["Filter out token upgrades<br>currency_key != 'currency:token'"]
Dispatch["Match strategy"]
RR["_buy_round_robin()<br>Group by currency<br>Buy 1 from each in loop"]
CF["_buy_cheapest_first()<br>Find cheapest.can_purchase()<br>Buy until none affordable"]
EF["_buy_expensive_first()<br>Find most expensive<br>Buy while affordable"]
TB["_buy_top_to_bottom()<br>For each panel in order<br>Max out before next"]
UpdateUI["panel.update_all()<br>panel._on_purchase_pressed()"]
Notify["Signals.notify.emit()<br>Bought X upgrades"]

Start --> GetPanels
GetPanels --> Filter
Filter --> Dispatch
Dispatch --> RR
Dispatch --> CF
Dispatch --> EF
Dispatch --> TB
RR --> UpdateUI
CF --> UpdateUI
EF --> UpdateUI
TB --> UpdateUI
UpdateUI --> Notify

Sources: extensions/scripts/utilities/buy_max_manager.gd L255-L399

for each currency_type:
while any_purchase_in_group:
for each panel in group:
if panel.can_purchase():
panel._on_purchase_pressed()

This ensures even distribution within each currency group (money, research).

Sources: extensions/scripts/utilities/buy_max_manager.gd L291-L323

while true:
cheapest_panel = null
cheapest_cost = INF
for each panel:
panel.update_all()
if panel.can_purchase() and panel.cost < cheapest_cost:
cheapest_panel = panel
cheapest_cost = panel.cost
if cheapest_panel:
cheapest_panel._on_purchase_pressed()
else:
break

Sources: extensions/scripts/utilities/buy_max_manager.gd L326-L351

The Buy Max button is injected into the existing upgrade tab UI:

Injection Point: HUD/Main/MainContainer/Overlay/.../upgrades_tab/ButtonsPanel/ButtonsContainer

The split button consists of:

  • Main Button: Executes buy max with current strategy
  • Dropdown Button: Opens strategy selection menu

Both buttons use the TabButton theme type variation to match the vanilla UI styling.

Sources: extensions/scripts/utilities/buy_max_manager.gd L112-L169

Config KeyTypeDefaultDescription
buy_max_enabledbooltrueShow/hide Buy Max button
buy_max_strategyint0 (Round Robin)Selected strategy enum value

Sources: mod_main.gd L505-L509

extensions/scripts/utilities/buy_max_manager.gd L52-L54


The Upgrade Manager extends the base game’s upgrade system to support bulk purchasing with modifier keys. This allows players to buy multiple levels of an upgrade in a single action.

The upgrade multiplier is controlled by a slider in the General settings tab:

ParameterValue
Range2-100x
Default10x
Increment1
Modifier KeyCtrl

When Ctrl is held while clicking an upgrade button, the game attempts to purchase multiple levels equal to the configured multiplier.

Sources: mod_main.gd L512-L517

The multiplier value is stored in the extended Globals:

Globals.custom_upgrade_multiplier = int (2-100)

This value is read by the base game’s upgrade purchase logic when the Ctrl modifier is detected.

Sources: mod_main.gd L513-L516

Config KeyTypeDefaultPurpose
upgrade_multiplierint10Number of levels to buy with Ctrl

Changes to the slider immediately update both the config and the Globals state.

Sources: mod_main.gd L512-L517


The Cheats Panel provides direct manipulation of game currencies and resources. It is located in a dedicated “Cheats” tab to clearly separate it from legitimate gameplay features.

flowchart TD

SettingsUI["SettingsUI<br>settings_ui.gd"]
CheatTab["Cheats Tab<br>money.png icon"]
CheatMgr["CheatManager<br>cheat_manager.gd"]
Buttons["Currency Modifier Buttons<br>±10% Money/Research/Tokens"]
GlobalsCurrency["Globals.currencies<br>Dictionary"]

SettingsUI --> CheatTab
CheatTab --> CheatMgr
CheatMgr --> CheatTab
Buttons --> GlobalsCurrency

Sources: mod_main.gd L626-L628

The Cheats Panel is implemented by CheatManagerScript and provides:

  • Currency Modification: Direct addition/subtraction of currencies
  • Percentage-based Adjustments: ±10% buttons for money, research, and tokens
  • Debug Integration: Values logged to debug tab when debug mode is enabled

The exact implementation is contained in the cheat_manager.gd script’s build_cheats_tab() method, which constructs the UI dynamically.

Sources: mod_main.gd L26

mod_main.gd L627

The Cheats tab is:

  • Clearly labeled with a money icon
  • Separated from other settings tabs
  • Documented as opt-in gameplay modification
  • Reversible (values can be reduced back to legitimate amounts)

All gameplay features persist their state through the ConfigManager system:

flowchart TD

UserAction["User Modifies Setting"]
ConfigMgr["ConfigManager.set_value()"]
JSONFile["user://tajs_mod_config.json"]
GlobalsState["Globals Variables"]
ManagerState["Manager Properties"]
GameRestart["Game Restart"]
LoadConfig["ConfigManager.load_config()"]
RestoreState["Apply Saved Values"]

UserAction --> ConfigMgr
ConfigMgr --> JSONFile
ConfigMgr --> GlobalsState
ConfigMgr --> ManagerState
GameRestart --> LoadConfig
LoadConfig --> JSONFile
LoadConfig --> RestoreState
RestoreState --> GlobalsState
RestoreState --> ManagerState
FeatureConfig KeyApplied ToLoad Phase
Node Limitnode_limitGlobals.custom_node_limit_ready()
Buy Max Enabledbuy_max_enabledBuyMaxManager visibility_setup_for_main()
Buy Max Strategybuy_max_strategyBuyMaxManager.current_strategysetup()
Upgrade Multiplierupgrade_multiplierGlobals.custom_upgrade_multiplier_build_settings_menu()

Sources: mod_main.gd L153-L155

mod_main.gd L332-L333

extensions/scripts/utilities/buy_max_manager.gd L52-L54

mod_main.gd L512-L517

sequenceDiagram
  participant ModLoader
  participant mod_main._ready()
  participant ConfigManager
  participant BuyMaxManager.setup()
  participant Globals Extension

  ModLoader->>mod_main._ready(): "_ready()"
  mod_main._ready()->>ConfigManager: "get_value('node_limit')"
  ConfigManager-->>mod_main._ready(): "400"
  mod_main._ready()->>Globals Extension: "custom_node_limit = 400"
  note over mod_main._ready(): Wait for Main node
  mod_main._ready()->>mod_main._ready(): "_setup_for_main()"
  mod_main._ready()->>BuyMaxManager.setup(): "setup(tree, config)"
  BuyMaxManager.setup()->>ConfigManager: "get_value('buy_max_strategy')"
  ConfigManager-->>BuyMaxManager.setup(): "Strategy.ROUND_ROBIN"
  BuyMaxManager.setup()->>BuyMaxManager.setup(): "current_strategy = 0"
  BuyMaxManager.setup()->>BuyMaxManager.setup(): "_inject_buy_max_button()"
  mod_main._ready()->>mod_main._ready(): "_build_settings_menu()"
  mod_main._ready()->>ConfigManager: "get_value('upgrade_multiplier')"
  ConfigManager-->>mod_main._ready(): "10"
  mod_main._ready()->>Globals Extension: "custom_upgrade_multiplier = 10"

Sources: mod_main.gd L115-L163

mod_main.gd L278-L340

extensions/scripts/utilities/buy_max_manager.gd L46-L76


Gameplay features in Taj’s Mod follow a consistent pattern:

  1. Manager-based Architecture: Each feature implemented as a standalone manager
  2. Config-driven: All settings persisted through ConfigManager
  3. Global State Integration: Critical values stored in extended Globals
  4. UI Injection: Features integrate into existing game UI non-destructively
  5. Clear Separation: Cheats and gameplay modifiers isolated in dedicated tabs

This architecture ensures gameplay modifications are:

  • Toggleable without restart (where possible)
  • Persistent across sessions
  • Clearly communicated to users
  • Reversible to vanilla behavior

Sources: mod_main.gd L1-L1844

extensions/scripts/utilities/buy_max_manager.gd L1-L451

extensions/scripts/utilities/config_manager.gd