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.
Overview
Section titled “Overview”Gameplay features in Taj’s Mod are designed with the following principles:
| Principle | Implementation |
|---|---|
| Opt-in by Default | Most gameplay modifiers require user action to enable |
| Clear Separation | Located in dedicated “Cheats” tab or clearly marked |
| Persistent Configuration | All settings saved to user://tajs_mod_config.json |
| Non-destructive | Can be disabled at any time to return to vanilla behavior |
Sources: README.md L47-L51
System Architecture
Section titled “System Architecture”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
Node Limit Control
Section titled “Node Limit Control”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.
Configuration
Section titled “Configuration”| Setting | Range | Default | Config Key |
|---|---|---|---|
| Node Limit | 50-2000 | 400 | node_limit |
| Unlimited Mode | ∞ | Disabled | Special value (10000) |
Implementation Details
Section titled “Implementation Details”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
Usage Example
Section titled “Usage Example”The node counter label displays real-time information:
Nodes: 247 / 400When at or near limit, the label color changes to warn the player.
Sources: mod_main.gd L541-L548
Buy Max System
Section titled “Buy Max System”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.
Architecture
Section titled “Architecture”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
Purchase Strategies
Section titled “Purchase Strategies”The system provides four distinct strategies for bulk purchasing:
| Strategy | Behavior | Use Case |
|---|---|---|
| Round Robin | Buys 1 level of each upgrade in rotation | Even distribution across all upgrades |
| Cheapest First | Always purchases the cheapest available upgrade | Maximize number of purchases |
| Most Expensive | Buys the most expensive affordable upgrade | Prioritize high-impact upgrades |
| Top to Bottom | Maxes out upgrades in UI order | Sequential completion |
Sources: extensions/scripts/utilities/buy_max_manager.gd L12-L31
Strategy Implementation
Section titled “Strategy Implementation”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
Round Robin Algorithm
Section titled “Round Robin Algorithm”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
Cheapest First Algorithm
Section titled “Cheapest First Algorithm”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: breakSources: extensions/scripts/utilities/buy_max_manager.gd L326-L351
UI Integration
Section titled “UI Integration”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
Configuration
Section titled “Configuration”| Config Key | Type | Default | Description |
|---|---|---|---|
buy_max_enabled | bool | true | Show/hide Buy Max button |
buy_max_strategy | int | 0 (Round Robin) | Selected strategy enum value |
Sources: mod_main.gd L505-L509
extensions/scripts/utilities/buy_max_manager.gd L52-L54
Upgrade Manager (Modifier Keys)
Section titled “Upgrade Manager (Modifier Keys)”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.
Multiplier System
Section titled “Multiplier System”The upgrade multiplier is controlled by a slider in the General settings tab:
| Parameter | Value |
|---|---|
| Range | 2-100x |
| Default | 10x |
| Increment | 1 |
| Modifier Key | Ctrl |
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
Global State
Section titled “Global State”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
Configuration
Section titled “Configuration”| Config Key | Type | Default | Purpose |
|---|---|---|---|
upgrade_multiplier | int | 10 | Number 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
Cheats Panel
Section titled “Cheats Panel”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.
Architecture
Section titled “Architecture”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
Features
Section titled “Features”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
Safety Considerations
Section titled “Safety Considerations”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)
Configuration and Persistence
Section titled “Configuration and Persistence”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
Persistence Table
Section titled “Persistence Table”| Feature | Config Key | Applied To | Load Phase |
|---|---|---|---|
| Node Limit | node_limit | Globals.custom_node_limit | _ready() |
| Buy Max Enabled | buy_max_enabled | BuyMaxManager visibility | _setup_for_main() |
| Buy Max Strategy | buy_max_strategy | BuyMaxManager.current_strategy | setup() |
| Upgrade Multiplier | upgrade_multiplier | Globals.custom_upgrade_multiplier | _build_settings_menu() |
Sources: mod_main.gd L153-L155
extensions/scripts/utilities/buy_max_manager.gd L52-L54
Initialization Flow
Section titled “Initialization Flow”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
extensions/scripts/utilities/buy_max_manager.gd L46-L76
Summary
Section titled “Summary”Gameplay features in Taj’s Mod follow a consistent pattern:
- Manager-based Architecture: Each feature implemented as a standalone manager
- Config-driven: All settings persisted through ConfigManager
- Global State Integration: Critical values stored in extended Globals
- UI Injection: Features integrate into existing game UI non-destructively
- 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