Skip to content

Spell04 Dynamic Scaling

Brandon edited this page Oct 6, 2026 · 1 revision

Part 4: Dynamic Scaling Spells (Play Other Cards)

← Part 3: Unit Stat Upgrades | Next: Part 5: Card Triggers →

In this lesson, we explore dynamic scaling—effects that calculate their magnitude based on statistics tracked during combat.

We will create Play Other Cards, a 2-Ember spell that grants a target unit +2 Attack for every card played during the current battle. You will learn how CardTraits modify upgrades and how to configure tracked statistics.


1. Asset Setup

Download the custom card art:

  • Download Art: PlayOtherCardsSprite.png
  • Save Location: Save it to your mod project under textures/PlayOtherCardsSprite.png.

2. Complete JSON Definition

In Plugin.cs, add "json/spells/PlayOtherCards.json" to your AddMergedJsonFile call. Then create json/spells/PlayOtherCards.json and add:

{
  "$schema": "https://github.com/Monster-Train-2-Modding-Group/Trainworks-Reloaded/releases/latest/download/schema.json",
  "cards": [
    {
      "id": "PlayOthercards",
      "cost": 2,
      "names": {
        "english": "Play Other Cards"
      },
      "descriptions": {
        "english": "Apply +[trait0.power][attack] per card played this battle."
      },
      "rarity": "rare",
      "targets_room": true,
      "targetless": false,
      "class": "ClassBanished",
      "card_art": "@PlayOtherCardsCardArt",
      "pools": [
        "MegaPool"
      ],
      "traits": [
        "@PlayOtherCardsScalingTrait"
      ],
      "effects": [
        "@ApplyScaledUpgrade"
      ]
    }
  ],
  "effects": [
    {
      "id": "ApplyScaledUpgrade",
      "name": "CardEffectAddTempCardUpgradeToUnits",
      "target_mode": "drop_target_character",
      "target_team": "both",
      "param_upgrade": "@PlayOtherCardsUpgrade"
    }
  ],
  "traits": [
    {
      "id": "PlayOtherCardsScalingTrait",
      "name": "CardTraitScalingUpgradeUnitAttack",
      "param_tracked_value": "any_card_played",
      "param_entry_duration": "this_battle",
      "param_int": 2
    }
  ],
  "upgrades": [
    {
      "id": "PlayOtherCardsUpgrade",
      "bonus_damage": 0,
      "upgrade_will_be_scaled_by_non_magic_power_trait": true
    }
  ],
  "game_objects": [
    {
      "id": "PlayOtherCardsCardArt",
      "type": "card_art",
      "extensions": {
        "card_art": {
          "sprite": "@PlayOtherCardsSprite"
        }
      }
    }
  ],
  "sprites": [
    {
      "id": "PlayOtherCardsSprite",
      "path": "textures/PlayOtherCardsSprite.png"
    }
  ]
}

3. What’s New in This Recipe

Trait-Based Scaling Interception

Unlike traits have a keyword (such as CardTraitIgnoreArmor - Piercing), CardTraitScalingUpgradeUnitAttack does not add a Keyword to the card:

  • It modifies the upgrade applied by @ApplyScaledUpgrade.
  • It reads the tracked in-game statistic and adds tracked_stat * param_int to bonus_damage of the upgrade.
"traits": [
  {
    "id": "PlayOtherCardsScalingTrait",
    "name": "CardTraitScalingUpgradeUnitAttack",
    "param_tracked_value": "any_card_played",
    "param_entry_duration": "this_battle",
    "param_int": 2
  }
]
  • param_tracked_value: Specifies the battle statistice to monitor ("any_card_played" increments every time any card is played).
  • param_entry_duration: Sets the monitoring time window:
    • "this_turn": Gets the value of the statistic as of this turn. The value resets at the start of each new turn.
    • "previous_turn": Get the value of the statistic from the previous turn.
    • "this_battle": Gets the cumulative count of the statistic for the current battle (used here).
  • param_int: The scaling multiplier (adds +2 attack per recorded event).

Important

Scaling traits of this type are specifically built for Spells. Attaching them to Monster cards can cause undefined behavior and bugs.


Upgrades as Scaling Templates

"upgrades": [
  {
    "id": "PlayOtherCardsUpgrade",
    "bonus_damage": 0,
    "upgrade_will_be_scaled_by_non_magic_power_trait": true
  }
]
  • bonus_damage: 0: The default of any integer property is 0, so this could be left out, here for emphasis.
  • upgrade_will_be_scaled_by_non_magic_power_trait: true: A flag for the upgrade that that this upgrade's parameters are modified by a scaling trait. This ensures that other mechanics that add upgrades to cards (like Reform) don't reset the scaled value back to 0.

Description Replacement Tokens

"descriptions": {
  "english": "Apply +[trait0.power][attack] per card played this battle."
}
  • [trait0.power]: Dynamically pulls the param_int value (2) from the first trait (trait0) listed on the card.
  • [attack]: Replaced by the Attack icon.

4. Testing Your Card

  1. Build your solution and deploy the updated mod files to BepInEx/plugins/<YourMod>/.
  2. Launch Monster Train 2 and verify no JSON errors appear in the BepInEx console log.
  3. Start a battle with Play Other Cards in hand or deck:
    • Play several other cards first.
    • Inspect Play Other Cards: the dynamic description will update to show the current scaled attack buff.
    • Play it onto a friendly unit and verify that the attack gained matches (cards_played * 2).

Next Steps

Now that you can build dynamically scaled spells, continue to Part 5: Card Triggers (Pyre Sharpener) to build cards that activate automatically from hand without being cast.

Clone this wiki locally