Skip to content

Game logic

Alexandre 'kidev' Poumaroux edited this page Oct 21, 2026 · 7 revisions

Game logic

How Legion TD 2 computes the numbers it shows or pays and the choices it makes for players, as of game version 26.10. The power score and the MVP score come from MvpScore in Natives.dll; the other rules come from the map's rules in server_triggers.dll and the map's data files. ProLeak's local server plays each of them as described here. The values the game keeps in its code rather than its data files are read from game version 26.10a by tools/GameTables.

Contents

Power score

The power score drives the scoreboard's stack rank, the shutdown bounty and the team gold split. The game takes it at the start of a wave and again as its rewards are given.

PowerScore = NetWorth + PowerScoreValueOffset
           - IncomeGainedThisWave
           + 1.25 * (Mythium + MythiumSentForNextWave)
           + IncomeMultiplier
           + ExtraPowerScore + ExtraPowerScoreFromMastermind + ExtraPowerScoreFromFighters
           + ExtraPowerScoreOnWave[wave]
           + 25                 # wave 1 only
           + 0.08 * Gold        # wave 2 only
           + PlaystyleBias
           + ClassicIncomeBias
  • NetWorth is the value of the player's fighters, plus gold in hand, gold spent on workers and ExtraNetWorth.

  • IncomeGainedThisWave is the income now, less the income the player had as the last wave spawned. It is 0 on wave 1 and during sudden death.

  • MythiumSentForNextWave is the mythium already sent to the next wave (on wave 21, the mythium sent during wave 21's battle phase).

  • IncomeMultiplier weighs the income held as the last wave spawned (I) by the waves left to earn it, with w the wave number:

    I * (3.49 + 1.38  * (1 - e^(0.06  * (w + 1))))    # 1v1
    I * (3.49 + 0.403 * (1 - e^(0.108 * (w + 1))))    # 4v4 full
    I * (3.49 + 0.8   * (1 - e^(0.08  * (w + 1))))    # otherwise

    "4v4 full" means all eight seats are playing; a 2v2 or an uneven game takes the last line.

  • PlaystyleBias covers the Mastermind playstyles whose income changes at wave 10. With v the wave number (plus one while the wave's rewards are being given), up to v = 11, mapped linearly from v = 2 to v = 11 and held at both ends:

    Playstyle At v = 2 At v = 11
    Castle +15 +150
    Cartel -13 -130
    Champion -4 -42
  • ClassicIncomeBias takes off the matchmaking income bonus (B), only while IncomeMultiplier is above 0. k is 2 in classic special mode 9 and 0 otherwise:

    -((3.49 + 0.403 * (1 - e^(0.108 * (w + 1)))) * B + B * (w - k))

The factor that weighs I in IncomeMultiplier, by wave (orange 1v1, blue 4v4 full, green otherwise):

%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#e6b44c, #4c9be6, #6cc24a"}}}}%%
xychart-beta
    x-axis "Wave" [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21]
    y-axis "Factor" -0.5 --> 3.5
    line [3.31, 3.12, 2.89, 2.64, 2.36, 2.03, 1.67, 1.27, 0.81, 0.29, -0.30]
    line [3.39, 3.27, 3.12, 2.94, 2.71, 2.42, 2.07, 1.62, 1.08, 0.40, -0.44]
    line [3.35, 3.19, 3.00, 2.77, 2.51, 2.20, 1.84, 1.41, 0.91, 0.33, -0.36]
Loading

Shutdown bounty

When a player's lane leaks, the other team is paid that player's shutdown bounty, at most once per player per wave. A player has a bounty only when their team is ahead.

The bounty of a player p on a wave, from the power scores of that wave:

flowchart TD
    A[Power scores of the wave] --> B[Average of each team]
    B --> C{Higher average}
    C -- ahead --> D["Pot: |avgLeft - avgRight| / 5.75 * players"]
    C -- behind --> X[No bounty]
    D --> E["Weight: max(0, PowerScore - avgBehind)"]
    E --> F[Pot times the share of the weights, down to 25]
Loading
  1. Average the power scores of the playing players of each team (seats 1 to 4, 5 to 8). The team whose average is higher (left on a tie) is ahead; the other team's players have no bounty. Neither team has any when a team has nobody playing, in co-op games and on wave 1.

  2. The ahead team's pot is |avgLeft - avgRight| / 5.75 times its number of playing players.

  3. Each player of the ahead team weighs max(0, PowerScore - avgBehind), where avgBehind is the other team's average. If the weights add up to 0, nobody has a bounty.

  4. p gets the pot times their share of the weights, rounded down to a multiple of 25:

    bounty = 25 * floor(pot * weight[p] / sum(weights) / 25)

Paying it, each player of the other team receives

round(bounty * receivingTeamSize * TeamGoldMultiplier(receiver))

The team gold multiplier splits team gold by power score. It is taken again each time a wave finishes spawning (0.25 until the first one). On the classic map a team of 3 takes 0.33 each, a team of 2 takes 0.5 each and a player alone takes 1. A team of 4 uses s = clamp(lowestPowerScore / sumOfTeamPowerScores, 0.1, 1):

Player Classic map 2v2 map
Richest 5/3 * s - 1/6 5 * s - 2
Poorest 1.5 - 5 * s 3 - 5 * s
Others 5/3 * s - 1/6 1

On the classic map the richest and poorest shares meet at 0.25 as the team evens out (orange richest, blue poorest):

%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#e6b44c, #4c9be6"}}}}%%
xychart-beta
    x-axis "s" [0.10, 0.13, 0.16, 0.19, 0.22, 0.25]
    y-axis "Share" 0 --> 1
    line [0.00, 0.05, 0.10, 0.15, 0.20, 0.25]
    line [1.00, 0.85, 0.70, 0.55, 0.40, 0.25]
Loading

On the 2v2 map, s is clamped from 0.4 instead of 0.1, and a player alone takes 1. Where two players tie, the first one checked takes the richest or poorest share.

The attacker of the player shut down earns a shutdown factor of paid / 1.1^(wave - 1), where paid is the total gold the other team received. The MVP score uses the sum of these factors without the last wave's.

Leak gold

When a lane leaks, each of its wave units still alive pays out in its own way as it dies. The wave's row in the map data sets the shares:

Wave Leaker's share back The same, one against one Catch Hourglass
1 0.75 0.90 0.10 0.20
5 0.66 0.76 0.10 0.34
10 0.18 0.36 0.10 0.94
11 0.05 0.25 0.10 1.12
15 0.05 0.05 0.10 2.04
21 0.05 0.05 0.10 4.02

The fields are goldbountyleakleakerpercent, leakpercent1v1, goldbountyleakkillpercent and goldbountyleakhgpercent, and every wave has its own values; the table shows some.

%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#e6b44c"}}}}%%
xychart-beta
    title "Hourglass share by wave"
    x-axis "Wave" [1, 5, 10, 11, 15, 21]
    y-axis "Share of the bounty" 0 --> 4.5
    bar [0.20, 0.34, 0.94, 1.12, 2.04, 4.02]
Loading

Where the bounty of a leaked unit goes as it dies:

flowchart LR
    U["Leaked unit dies (bounty B)"] --> H["Other team: round(B * hourglass)"]
    U --> L["Leaker: round(B * share)"]
    U --> K{Killed by}
    K -- a unit --> KU["Killer: B * catch"]
    K -- a king --> KK["King's team: round(0.10 * B)"]
Loading

As a leaked unit with bounty B dies:

  1. The other team shares the hourglass gold, round(B * hourglass) (half of that one against one). Each of its players takes the gold times their team gold multiplier (see Shutdown bounty) times a weight, rounded. The leaker's attacker takes at least 1.

    Teams Leaker's attacker Others
    4 against 4 2.68 0.44
    3 against 3 1.98 0.51
    2 against 2 1.34 0.66
    Any other 1 1
  2. The leaker gets round(B * share) back. A player whose worker score is below the game's average gets more:

    share = min(1, leakerShare + 2.5 * (1 - w))      # when w < 1

    w is the player's worker score over the average of every player's. The worker score is the power score, plus 50 for each worker, plus ExtraNetWorth, taken with the power scores.

  3. The unit's killer earns its bounty times the catch share. When a king kills it, round(0.10 * B) goes to the king's team instead: each player takes it times their team gold multiplier and the "Others" weight above, and the leaker's share back is added to the leaker's part.

Waves 10 and 20 hold a boss with a fixed part C of its bounty (goldbountybossconstfactor: 25 and 50). With L the boss's share of life left as it leaked, the hourglass gold and the share back use C + L * (B - C) in place of B.

Target choice

A unit looks for a target every 0.5 seconds among the enemies within 1.2 times its radius plus its acquisition range, and keeps its target in between. Each candidate gets a score, and the lowest wins. A game mode can replace the choice.

A king (or any other building) scores a target by the hits it needs to kill it:

score = (100 * hits + 100 * life / maxLife) / threat
        + 1000 + distance^2          # out of range only

hits is ceil(life / attack), with the king's upgrades in its attack. With Giant Slayer each hit counts attack + 0.24 * lifeLeft. threat is the target's effectivethreat; a merged mercenary of Giga Mercs counts once for each mercenary it stands for.

Any other unit adds these terms:

Term Value
Dead target 100000
Out of range 10000 + 10 * distance
Health 10000 for a target out of range or unhurt. Otherwise, for a wave unit or a mercenary, 10000 - 2 * missing / typeLife; for a fighter, 9000 - 5000 * missing / typeLife.
Distance to the cave Wave units and mercenaries only, for a target in range: how far the target's fighter (or the fighter that summoned it) stands from the top of its lane, up to 20. A Great Boar or Red Eyes counts 14 further, a Sea Serpent or Deepcoiler 6.5 nearer.
Back of the send For a mercenary target in range whose spawnbias is 0.75 or more: 5 up to wave 3, falling to 0 at wave 8.
Tie break For a target in range: 0.01 * distance when the two units touch (less than 1.05 apart beyond both radii), otherwise 10 * distance. A Sea Serpent or Deepcoiler target counts at least 60.

missing is the type's base life less the target's life now. A fighter therefore goes for the most hurt enemy in range. A wave unit weighs a fighter's distance to the top of the lane (up to 20) against ten times its own distance to that fighter.

Purchase queues

A shift-click, or a click without enough mythium or gold, queues a mercenary, a worker or a king upgrade. The server tries the queues when the resources change, at these moments only:

  • Mercenaries: in the build phase, when mythium rises past a multiple of 20. The dearest type goes first, and the queue stops at the first one it cannot pay for.
  • King upgrades: in the build phase, when mythium changes and is 20 or more. The dearest goes first, as many as mythium pays for.
  • Workers: when gold crosses a multiple of 50, either way. One of each queued kind is trained, the dearest first, as gold allows.

A mythium gain that ends between 410 and 3000 (both left out) tries neither mercenaries nor king upgrades. As the wave spawns, the mercenary queue sends what mythium pays for (the dearest first, passing over any it cannot pay for), the king upgrades are tried once more, and both queues empty. The worker queue stays from one wave to the next.

Recommended value

After each wave's rewards, and at the end of each sudden death wave, the server sets each player's extra recommended value. The HUD adds it to the next wave's own recommended value. It is what the player's attacker can send next:

extra = 1.5 * (M + T * r * 0.1 * W) + 0.1 * G
  • M is the attacker's mythium plus the mythium they already sent for the next wave (in sudden death also their waiting mercenaries). A player without an attacker uses the other team's average, and a player alone their own.
  • T is the next wave's build time in seconds, and r and W the attacker's mythium gather rate (1 by default) and workers. G is the attacker's gold.
  • Around waves 11 to 13 the legion spells' extra values are added, and from wave 20 the growth of sudden death: R * (1.1^g - 1), rounded, with R the wave's recommended value and g the number of sudden deaths on the 2v2 map, or twice that plus 2 on the classic map.
  • After wave 10 a bot's extra is at most 25 * wave.

The result is rounded to tens. Allies see the new values at once, and enemies as the mercenaries warp to the lanes.

MVP score

Each team's MVP is the player with the highest MVP score at the end of the game. The score is truncated to a whole number:

MvpScore = 1.0 * WavesSavedFactor(you)
         + 1.0 * WavesSavedFactor(your attacker)
         + 1.0 * MythiumSpentOnKingUpgrades
         - 5.0 * LeakPercentValue(you)
         + 5.0 * LeakPercentValue(the player you send to)
         + 3.0 * LeakCaughtPercentValue(you)
         + 4.0 * ShutdownGoldEarnedFactor(you)
         - 4.0 * ShutdownGoldEarnedFactor(your attacker)
         + SpreadTheWealth

The code also lists the end value, total mythium, leak values and the power score, each weighed 0. In classic special mode 11 the weights become 0.2 * TotalMythium, -5 * LeakPercentValue, 3 * LeakCaughtPercentValue and -4 * ShutdownGoldEarnedFactor(your attacker), plus the Spread the Wealth term.

  • WavesSavedFactor(N) adds, over waves k from 1 to N, the mythium the player kept unsent as wave k's mercenaries warped to the lanes, weighed by how early that was:

    WavesSavedFactor(N) = sum(MythiumKept[k] * 1.17^(21 - k) / 7 for k in 1..N)
  • LeakPercentValue adds, for each wave a player's lane leaked, the share of the wave's bounty still alive when the lane fell, as a percentage. An enemy counts its bounty less the part its lost life already paid. The wave's bounty leaves out mercenaries; a wave with no bounty uses its hit points instead.

  • LeakCaughtPercentValue adds, for each leaked enemy a player kills, the bounty that kill catches as a percentage of the leaking player's wave bounty.

  • SpreadTheWealth is 5 * wave + 15 if the player took the Spread the Wealth spell, and the same amount taken off if their cross partner did.

Auto Power send

The Auto Power choice of the send menu spends the player's mythium (20 or more) as each wave's rewards come, and again as the wave spawns, after which the choice goes back to saving. Past wave 1, the send at the spawn happens only when Auto Power sent at that wave's rewards, or a powerful mercenary is already sent or queued.

It spends in steps of the Snail's cost. Each step picks the mercenary with the best score among those the player can buy, with at most 8 of one type for the wave:

  • 10, less 0.02 for each place the mercenary takes in the wave's preference list (mercpref in its row); 8 for a mercenary not in the list.
  • Plus (cost / 20 - min(20, mythium / 20)) / 4, so a dearer mercenary scores higher.
  • Less 0.4 for each of the same type already sent, from wave 10.
  • Less 0.5 (20 from wave 10) when the send would leave 20 to 39 mythium.
  • Plus the fit with the defending build, from its fighters' values by attack type, armor type and role (damage, tank, area damage, scaling, healing), each as a share of the build's value:
    • The mercenary's attack against the build's armors, and the build's attacks against the mercenary's armor: the average damage multiplier away from 1, weighted by the mercenary's role (tank, melee or ranged, from its spawnbias).
    • From wave 8, melee and ranged mercenaries gain against a build with little damage, tanks against one with much. Tanks gain 1.5 on the ranged waves (8, 11, 15, 19).
    • Area damage over 15% of the build favors Safety Mole, Honey Bear and Hermit (less on waves 6, 10, 13, 18 and 20) and ranged mercenaries; below it Honey Bear and Hermit lose 1.5.
    • Scaling over 30% favors melee and ranged mercenaries, and Pack Leader by 2.
  • Plus the game's own preferences for single mercenaries:
Mercenary Bonus
Powerful mercenaries (below) 8
Giant Snail 20
Robo, with 59 mythium or less, up to wave 3 0.5 (in place of the powerful bonus)
Brute, with 60 to 79 mythium 3.5
Ogre, up to wave 10 2.5
Imp, on wave 7 -1
Shaman 50 on wave 21, 15 on wave 20, 3 on waves 15 and 18, -2 otherwise
Witch, from wave 10 1.5 * n
Mimic, before wave 17 5 * n
Four Eyes, from wave 10 1.5 * (1 - n), plus 12 times the healing share
Centaur 1.5 times the melee share
Ghost Knight 2 times the build's damage per second over its value
Siege Ram 1.5 times the ranged share

n is the build's fighter count over 30, at most 1. Safety Mole and Pack Leader lose 2.5 when the other is already sent, and a second support mercenary (Safety Mole, Pack Leader, Hermit, Shaman) of a type scores 0.

The powerful mercenaries are Brute, Centaur, Four Eyes, Ghost Knight, Hermit, Honey Bear, Imp, Kraken, Mimic, Needler, Ogre, Pack Leader, Robo, Safety Mole, Shaman, Siege Ram and Witch.

Proc chances

An ability that procs on a chance rolls 1 to 100 against the chance in whole percent: 15.9% procs on rolls up to 15. Bash, Evasion and Shadowbreeder use a pseudo random roll instead. It starts at a small chance C and adds C after each miss, back to C after a proc, so procs come at the stated rate but more evenly:

Stated chance C
5% or less 0.2%
10% 1.47%
15% 3.22%
20% 5.57%
25% 8.47%
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#e6b44c"}}}}%%
xychart-beta
    title "Pseudo random step C by stated chance"
    x-axis "Stated chance (%)" [5, 10, 15, 20, 25]
    y-axis "C (%)" 0 --> 10
    bar [0.2, 1.47, 3.22, 5.57, 8.47]
Loading

Above 5%, C is the value whose average proc rate equals the stated chance. The 26.10 rows of some of these abilities count hits instead (every so many attacks), with no roll.

Mastermind draws

A Mastermind offer holds 11 fighters from every legion, drawn in this order:

flowchart LR
    G[Guaranteed fighters] --> R[3 damage dealers, 3 tanks]
    R --> P[One per missing roll group]
    P --> W[The rest by roll weight]
    W --> S[Sorted by gold cost]
Loading
  1. The guaranteed fighters (a Lock In).
  2. Three damage dealers of different attack types and three tanks of different armor types, no more than two of one tier. A type is picked as likely as the number of fighters that have it.
  3. One fighter for each roll group the offer still lacks, the groups taken in random order: tier 1, arcane, fortified or natural, swift or natural, magic, pierce, impact, tier 6, tier 4 or 5, tier 2 and tier 3. The groups are the mm_groups flags of the fighters' rows.
  4. The rest by roll weight: each fighter holds mm_roll_weight tickets, drawn without return. Past three tier 6 fighters, tier 6 holds none.

The offer is shown sorted by gold cost. A reroll keeps six fighters and draws five more, at most one of tier 1.

Within each step a fighter is picked as likely as its pick weight against the others' 1. Step 2 picks the damage dealers and tanks by the role weights instead. Pick weights:

Fighter Weight
Antler 0.4
Bazooka 0.7
Chained Fist 0.5
Fire Lord 0.65
Gargoyle 0.35
Goblin Copter 0.8
Golden Buckler 0.05
Grarl 0.35
Holy Avenger 0.0001
Pirate Skeleton 0.0001
Pollywog 0.3
Proton 0.1
Radiant Halo 0.1
Seedling 0.5
Slime Larva 0.2
Warg 0.25
Yozora 0.55

Role weights:

Fighter Weight
Bazooka 1
Priestess Of The Abyss 1
Proton 1
Radiant Halo 1
Seedling 1

Some rules leave fighters out of a whole draw by chance:

Fighters Chance to be left out When
Seedling 50% on the 2v2 map, for Fiesta
Seedling, Eggsack and Dwarf Banker 75% on the classic map
Crab Warlock 88% under 2000 Elo

Aristocrat's offer holds a second tier 2 and a second tier 6 check. Swarm's starts with its tier 1 fighters, then draws without tier 1, one damage dealer and one tank, with its own groups and no pick weights.

Announcements

The game announces swings of the spectators' win chance across the screen:

  • Game changer and Power play: as the scoreboard refreshes before a wave's rewards, from wave 4, when the west's chance moved by 0.25 or more since the last refresh. Game changer when the favourite changed, Power play otherwise.
  • Not even close: 0.3 seconds after a side clears its enemies, when its king is low and was hurt this wave (with left and taken in percent, left * 20 - taken < 30 and taken > 0.1). Once a wave.

One announcement shows every 2.5 seconds at most. The sandbox's -wave command stops them for the rest of the game.

Sudden death

After wave 21 the game plays wave 21 again, as sudden death; the HUD shows wave 21 plus the number of sudden deaths. Players earn no income. Each sudden death gives every wave unit one more Indomitable stack (more attack speed and less damage taken) and shows it 5% larger. The recommended value grows as described in Recommended value; as a sudden death wave ends, the mythium sent for it stops counting toward it.

At the end of the fourteenth sudden death, 30 Dire Toads appear at the west king's waypoint, whatever the teams.

stateDiagram-v2
    direction LR
    Wave21: Wave 21
    SD: Sudden death n (wave 21 again, n Indomitable stacks)
    Toads: 30 Dire Toads at the west king
    Wave21 --> SD: no king fell
    SD --> SD: n + 1
    SD --> Toads: end of n = 14
Loading

Previous: Publishing plugins | Next: Developer options

Clone this wiki locally