All writing

The first two pins in WCW/nWo Revenge only win with a 70-point spirit lead

WCW/nWo Revenge cuts a winning pin to 87 ticks until your opponent has kicked out twice; a 70-point spirit lead over an empty health bar is the way past the cut. The code and the numbers behind both.

For twenty-five years, players of WCW/nWo Revenge have said that the first two pins of a match are safe. The code shows why that is mostly true and where it breaks. Until your opponent has kicked out twice, a hold of 88 ticks or more is cut to 87, three short of the three count. The way past the cut is a spirit lead of at least 70 over an opponent whose health bar is empty, and then even a first cover can win.

For players#

If you played Revenge, you know the pattern. You wear your opponent down, go for the cover, and the referee stops at two. The next cover ends the same way, so players concluded that the game counts your pins and holds the first two off. The code does almost that, and what it counts is your opponent's kick-outs. It also shows the gap in the rule: a spirit lead of at least 70 while their health bar is empty, and the first cover wins.

How a pin is decided#

The moment you cover, the game computes how long your opponent will stay pinned. This hold time is measured in ticks, one tick being one pass of the game's logic loop. The match clock runs on the same counter and advances one second every 30 ticks. The referee also counts once every 30 ticks, so a three count takes 90. If the hold time reaches 90, you win. If it runs out first, your opponent kicks out, which means they escape the pin before the count is finished. How many real frames a tick lasts on a console was not measured.

The cut to 87#

The game also counts how many times each wrestler has kicked out in the current match. While your opponent's count is below two, a hold time of 88 or more is replaced with 87, a count of 2.9, unless the spirit exception below applies. It does not matter how hard the last move hit or which wrestler you chose. After the second kick-out the cut stops, the hold time reflects the damage you have done, and a worn-down opponent finally stays down for three.

The spirit exception#

The spirit meter is the bar under the health bar. It runs from 0 to 100 and drifts back towards 50 on its own. It offers the only way to win with a first cover: your spirit must be at least 70 points higher than your opponent's, and their health bar must be completely empty. When both are true, the game leaves the hold time alone, so the cover wins even though your opponent has not kicked out twice. In a match that means driving your own spirit to the top, draining theirs to the bottom, emptying their health bar, and only then going for the cover. It does not work while your opponent's special is running: the game then reads their health as full, so the bar never counts as empty.

Your spiritTheir spiritGapHold timeResult
50203087 tickskick-out at two
6906987 tickskick-out at two
70070130 tickspinfall on the first cover
902070125 tickspinfall on the first cover
First cover of the match against an opponent with an empty health bar. One point of spirit separates the second row from the third.

Because spirit is always pulled back towards 50, a gap of 70 needs one bar near the top and the other near the bottom, as when a fresh wrestler finishes off an exhausted one. It is rare, and it is the reason a first cover occasionally wins out of nowhere.

What it means in a match#

  • Your first two covers end at two unless your spirit is at least 70 ahead while their health bar is empty.
  • After that, damage pays off. The emptier their health bar, the longer they stay down.
  • The pinned player can fight back. Pressing A, B or the shoulder buttons takes extra ticks off the hold.
  • A running special protects against plain covers. Only the special-move pin described below gets through it.
  • A normal pin has no dice roll. It only feels random because several numbers change at once.

For ROM hackers#

Everything below was read from the disassembly and then confirmed by running the cartridge's own routines in a MIPS interpreter. Addresses are RAM addresses in the US cartridge. The fighting code is an overlay at 0x80090000, whose .text section holds 84,676 instructions, followed by 4,904 words of tables in .data. It is not compressed: every word decodes as a valid instruction, and no 4 KB block exceeds 5.85 bits of entropy per byte, where compressed data sits near 8.

Finding the referee#

Searching for the number three would find many candidates and prove nothing, so I searched for what a referee does: notice a cover, then count. One flag in the wrestler record, 0x400, is set by exactly one routine and read by exactly one other. The reader, at 0x800B8D8C, runs once per tick and scans the four wrestler slots for that flag. It stores the pinned slot in the byte at 0x800EB46F, where −1 means nobody, next to the visible count at 0x800EB46E. To count, it calls a clock helper at 0x800DA850 with a period of 30. Run 200 times against the real memory image, the helper reaches a count of 1 at tick 30, 2 at tick 60 and 3 at tick 90.

The hold-time formula#

The hold time comes from a seven-way switch at 0x800B6DEC, with one case per kind of hold. The pin is case 1, at 0x800B6F64:

0x800B6F64, the pin case
hold = 110
     + attacker.spirit / 4
     + 3 * holds[victim]
     - life(victim)
     - victim.spirit / 2
hold = max(0, hold)

if hold >= 90 and victim.spirit >= 90:
    hold = 87

The caller then raises anything below 15 to 15. holds[victim], at 0x800FADD2, counts the pins this wrestler has been in. It is incremented in a delay slot before the formula runs, so even the first cover adds 3 ticks. life(), at 0x800BF2FC, returns the victim's health, or their maximum health while their special is running (flag 0x00080000). Maximum health is never zero or small, so the formula goes far below zero and the hold lands on the floor of 15. That is why a wrestler in special mode cannot be pinned by a plain cover.

The routine also has a cap of its own: a result of 90 or more against a victim with spirit of 90 or higher becomes 87. A differential test against the ROM caught me leaving it out. For players it is a second defence, because with your spirit at 90 or above a normal cover cannot pin you.

Victim's healthCoverHold timeCount reachedResult
255first150kick-out before one
60first551kick-out at one
30first852kick-out at two
0first87, cut from 1152kick-out at two
0second87, cut from 1182kick-out at two
0third1213pinfall
Attacker spirit 50, victim spirit 20. Every value was returned by the cartridge's own routine.

The cut in the code#

Right after the hold time is stored, the pin routine applies the rule at 0x800CA920. It finds the pinned slot through the byte at 0x800FADB8 and reads a second counter, escapes at 0x800F9B80, which counts clean kick-outs. A count of two or more skips to the end, and so does a spirit gap of 70 or more while life() is zero. Otherwise a hold of 88 or more becomes 87. The listing is abridged:

0x800CA920, abridged
800CA924   lb    $v0, 0x800FADB8         slot = whoever is pinned
800CA934   lh    $v0, 0x800F9B80[slot]   v0 = escapes[slot]
800CA938   slti  $v0, $v0, 2             v0 = (escapes < 2)
800CA93C   beq   $v0, $zero, 800CA99C    if not v0: goto done

800CA954   lh    $v0, 20($v0)            v0 = attacker.spirit
800CA958   lh    $v1, 20($a0)            v1 = victim.spirit
800CA95C   subu  $v0, $v0, $v1           v0 = attacker.spirit - victim.spirit
800CA960   slti  $v0, $v0, 70            v0 = (gap < 70)
800CA964   bne   $v0, $zero, 800CA980    if v0: goto trim
800CA96C   jal   0x800BF2FC              v0 = life(victim)
800CA978   blez  $v0, 800CA99C           if life <= 0: goto done

800CA988   lh    $v0, 24($v1)            v0 = victim.hold_timer
800CA98C   slti  $v0, $v0, 88            v0 = (hold < 88)
800CA990   bne   $v0, $zero, 800CA99C    if v0: goto done
800CA994   addiu $v0, $zero, 87          v0 = 87
800CA998   sh    $v0, 24($v1)            victim.hold_timer = 87

Since life() reports maximum health for a wrestler whose special is running, the spirit exception never applies to them. The two counters, holds and escapes, each store one halfword per wrestler, are indexed by the same slot byte and are cleared at the bell by the same five-instruction block. Each is touched at exactly four places in the overlay. escapes is incremented at 0x800CAD50, only after a clean kick-out, and both increments sit inside the pin routine, so escaping a submission does not count. Neither address appears as an immediate value: the code builds a pointer with lui and addiu, adds the slot and loads at offset zero, so a search that resolves a lui plus an offset reports both counters as unused.

Shortcuts and the special-move pin#

Two shortcuts at 0x800CA830 run before the formula. With match-rule bit 0x0020 off, every hold lasts 5 ticks and the referee never reaches one. The same bit gates the kick-out counter, so no setting allows pins while freezing it. A victim with flag 0x100 gets exactly 30 ticks, a one count, when rule bit 0x0100 is off. The menu labels of both bits live in an overlay that is not loaded with the match code, so I know their effects but not their names.

The only dice roll in a pin sits between the formula and the rule, at 0x800CA8C8. If the victim is in state 0x3F, the cover that follows a move, and the attacker's special is running, the game calls roll(500), a 50.1 % chance. On success it writes a hold of 30,000 ticks that nobody escapes. The rule still cuts it to 87 before the second kick-out unless the spirit exception applies. This roll is the one way to pin a wrestler whose special is running or whose spirit is 90 or more. I have not worked out which moves lead into state 0x3F.

Mashing#

While a wrestler is pinned, the routine at 0x800CAA70 lowers the hold timer by one each tick. A press of A, B or a shoulder trigger (button mask 0xC030) takes one extra tick off, and a stronger input takes two. When the timer drops below zero, the wrestler kicks out and escapes goes up by one.

InputTicks off per tickEscapes at tickCount reachedResult
Nothing11223pinfall
Steady tapping2612kick-out at two
Fast mashing3411kick-out at one
Third cover against a victim with no health left, hold time 121. The controller routine registers a press at most every third tick, so real mashing falls between the rows.

The spirit meter#

Moves change spirit through 0x800BF62C, which clamps it to the range 0 to 100 and does nothing while the meter is frozen. Every 120 ticks, 0x800BF700 pulls the meter towards 50: it loses one point above 50, gains two from 31 to 49 and gains three below 31. Reaching 100 makes the special available and freezes the meter for 600 ticks, after which it is released at 70. Firing the special freezes it for 600 ticks and reaching 0 freezes it for 300, and both release it at 50. While the special runs, every limb also reports a flat condition of 50 instead of its worn-down value.

Damage#

A hit is resolved at 0x800B68A0 through five helper routines, and none of them draws a random number:

0x800B68A0, a hit
condition = 50 if attacker.special_active else attacker.limb[move.limb]

part1 = (condition + 50) * move.base / 100
part2 = (attacker.attack[limb] - defender.defence[limb]) * move.base / 10
part3 = (attacker.spirit - defender.spirit) / 20
total = max(0, part1) + max(0, part2) + max(0, part3)
if attacker.special_active:  total *= 1.2
total *= level_scale[difficulty]           # 0.5 to 1.33

defender.health     -= total               # floor 0
defender.max_health -= total / 4           # permanent, floor 128
defender.limb[limb] -= move.limb_damage    # floor 0

The hold-time formula subtracts the victim's health, so every point of damage adds a tick to your next pin. Lost maximum health never comes back, and a worn limb weakens every later move the wrestler makes with it.

The same formula settles another old belief. Running every fighter's real move table through it puts Scott Norton first of 62, and the ranking has a post of its own.

Where the game rolls dice#

A random number generator is short, calls nothing else and keeps its state in one fixed location. Running every function of that shape ten times leaves one candidate, reached through a wrapper at 0x800D4204 that is called from 136 places:

0x800D4204, a number from 0 to 999
repeat:
    state = state * 0x5D588B65 + increment
    v = (state & 0x000FFFFF) / 1000
until v < 1000
return v

So roll(n) should succeed with probability (n+1)/1000, and 20,000 throws per value through the cartridge's own routine agree:

nHits out of 20,000MeasuredPredicted
0200.10 %0.10 %
2505,05125.25 %25.10 %
5009,99949.99 %50.10 %
99920,000100.00 %100.00 %
Four of the eight values tested.

Of the 136 calls, 81 pass a fixed number, most often 500 (44 times) and 250 (seven times). Another 53 compute their argument, nearly all of them in the opponent AI. The roll that looks most like the pin sits in the routine at 0x800BF338 and fires when a health bar reaches zero. In match types with one option bit set it is a single roll(250) the first time a wrestler is beaten to zero; in the others it is roll(500) every time. Success sets a flag that later sends the tag partner into the ring to break up a pin or submission. That roll only decides whether help arrives.

The other five AKI games#

AKI made six wrestling games for the Nintendo 64, and they share a lot of code. The spirit cap inside the hold-time routine is in all six: the same five instructions compare the hold with the bar, load the victim's spirit, compare it with 90 and return a number three short. I matched the shape of the instructions rather than the constants and swept each game's whole match code, 84,676 to 109,380 instructions, for other copies.

GameYearBarCut toKinds of holdPin counter
WCW vs. nWo World Tour199790877not determined
Virtual Pro-Wrestling 64199790877not determined
WCW/nWo Revenge199890877global table, 3 ticks per step
WWF WrestleMania 2000199990879not determined
Virtual Pro-Wrestling 2200090 and 18087 and 1759not determined
WWF No Mercy2000908711wrestler record, 2 ticks per step
Kinds of hold is the number of cases in the hold-time switch. The pin is case 1 in every game.

Only Virtual Pro-Wrestling 2 has a second copy. It tests against 180 and returns 175 when one flag is set, which is the same rule with the referee's clock doubled.

No Mercy has a pin counter too, kept in the wrestler's record. Exactly four of its instructions touch it, and they only read it in the pin, add one to it and clear it at the bell. The same search found nothing in the other four games, but it also missed Revenge's counter until I widened it, so those rows stay open. No Mercy's full hold-time formula is decoded as well:

TermWCW/nWo RevengeWWF No Mercy
Starting number11095, plus a four-step ladder of 10/15/20/25
Attacker's spiritdivided by 4divided by 5
Pin counter3 per step2 per step
Victim's healthsubtracted wholesubtracted halved
Victim's spiritdivided by 2divided by 3
Recent damagenot in the sumthe mean of the last 30 hits, above 15
A running specialmaximum health substitutednot read

No Mercy averages a 30-entry log of each wrestler's recent hits and adds whatever exceeds 15, so a wrestler who has just taken a beating stays down longer. It never reads the special flag in the pin. Both formulas matched the cartridges' own routines in the interpreter, over 839 cases for Revenge and 2,925 for No Mercy.

The Python model#

The whole fight logic is available as revenge-pin.py, with the ROM address of each part, and python3 revenge-pin.py prints a self-check against the measured values. In 20,000 random combinations of health, spirit, earlier pins and special state, the model and the cartridge's routine never disagreed. A second run through Unicorn, an independent emulator, agreed on every hold time.

What this does not show#

  • The cut applies to pinfalls only. Submissions, count-outs and other results go through their own routines.
  • Ticks are passes of the game loop. The 30, 60 and 90 are exact relative to each other and to the match clock, but nothing here is claimed about real seconds.
  • Whether a hold of exactly 89 reaches three depends on whether the referee or the pin update runs first within a frame.

The legend told half the story. The game does stop early pins on purpose: until your opponent has kicked out twice, a hold of 88 ticks or more becomes 87. The other half is the way past it, a 70-point spirit lead over an opponent whose health bar is empty, which skips the cut and can win on the first cover. It does not apply while that opponent's special is running, because the game then reads their health as full. Around that rule the engine is plain arithmetic, with a single coin flip saved for the special-move pin. That suits a wrestling game. Real matches seldom end the moment someone runs out of energy. They end on a two count the whole arena thought was three, and this cartridge was written to produce exactly that.