Arcane-Arena

Warlock in the real Warcraft III: measured behaviour

These are measurements from playing the real map in Warcraft III on this PC. Their purpose is to let the browser remake match the original’s feel. Each section covers one test: the numbers (in frames, then seconds), what I saw, and how it compares with docs/research.md.

The measurements come from two sources:

Important: the installed map is not the one research.md describes.

Setup and method

Game and map

Capture

Analysis

Converting pixels to game units

Summary for the remake

Behaviour Measured in WC3 Notes
Walk speed 210 u/s exactly (2.10 u per 0.01 s in the log) There is no acceleration and no deceleration: the unit starts at full speed and stops dead.
Where the engine does its turning Once every 0.03 s per unit, at a phase of its own Each unit has its own 0.03 s “step”. A new order waits 0–0.03 s for the next step.
Turn rate 0.6 = 0.6 radians per 0.03 s step (34.4° per step, 1146°/s) This is the logical heading, which decides where the unit walks.
Propulsion window 60°, tested against the heading before that step’s turn If the check passes, the unit walks during the step along the new heading.
Walking starts after (standing, turn θ) Step 1 for θ ≤ 60°, 2 for ≤ 94°, 3 for ≤ 129°, 4 for ≤ 163°, 5 for ≤ 180° 180°: the unit walks after 0.12–0.15 s, first leaning 8° off the line, then straight.
Model rotation A separate, slower display facing: 4°, 8°, then at most 11.5° per step (0.2 rad) GetUnitFacing and the drawn model use this one. They lag, so after a 180° order the unit slides backwards for about 0.35 s.
Order → first movement in the LAN videos (no turn needed) 8–10 frames (0.13–0.17 s) The engine part is only 0–0.03 s. The rest is the LAN command delay and input/draw time.
Order → movement in the LAN videos, 180° turn 16–19 frames (0.27–0.32 s), mean 17.5 frames (0.29 s) Engine part 0.12–0.15 s, which matches the step model.
Direction change while walking Translation stops at once on a new order, then resumes on the first step that passes the window 90°: 0.03–0.06 s with no progress, then one step cutting the corner 21° short. 180°: a 0.12–0.15 s stop. Re-clicking the same direction costs a hitch of up to 0.03 s.
Arrival Stops dead 10.7–12.1 u short of the clicked point; the order ends No slow-down.
Fireball cast start Instant if already facing. Otherwise on the step after the heading reaches the target exactly. Logged at 30°: 0.046 s, 90°: 0.107 s, 180°: 0.179 s.
Fireball launch At the start of the cast (“begins casting”), then a 0.300 s cast point in which the unit is locked Right-clicking during the wind-up did not cancel it.
Fireball flight 30 u per 0.03 s = 1000 u/s, 33 steps The hit test (radius 75 in data) runs once per 30 u step. The logged hit came at 60 u.
Fireball cooldown 5.0 s from the spell-effect event, so about 5.3 s launch to launch The icon agrees.
Knockback Hit: Δv = 0.03·D·(100+M) units per step, where M is damage taken including this hit. Then ×0.9600 per 0.03 s Total slide = 24·Δv = 0.72·D·(100+M): 539 u (M=7), 756 u (M=50), 1008 u (M=100) for a 7-damage fireball.
Lava 1.0 damage every 0.100 s in round 1, +1 damage taken per tick Regen of 0.5 HP/s continues in lava.
Arena A square that does not shrink over time It shrinks only when a warlock dies or a player leaves.
Camera Distance 1650, angle of attack 304° (56° down), FOV 70°, rotation 90° This is the WC3 default. The target sits on the ground (z −128 here).

1. 180° turn from standing

Method.

  1. Walk the warlock in one direction and let it stop, so its facing is known.
  2. Right-click far directly behind it.
  3. Repeat with 90° and 0° (straight-ahead) controls.

Delay from order to the first visible step:

Turn Samples (frames) Mean
0° (already facing) 10, 8, 10 9.3 frames = 0.16 s
90° 13, 9, 13, 9 11 frames = 0.18 s
about 130–150° 18, 15 16.5 frames = 0.28 s
180° 17, 19, 18, 16 (plus 16 from an unknown start facing) 17.5 frames = 0.29 s

What I saw:

Compared with research.md:

180° order: the model is still facing away while the unit already slides toward the target

180° order, 60 fps frames 80–135. From frame 95 the warlock slides right (east, toward the click) while its model is still facing west and then north. It only faces east from about frame 122.

Engine log: how turning really works

The log answers the open question from the first version of this note. A unit has two facings.

1. The heading. This is the direction the unit steers by.

2. The display facing. This is what GetUnitFacing returns and what the model shows.

Measured on standing turns (turn rate 0.6, window 60°; the order is at step 0):

Turn Walks from step First walking direction (logged) Step model
0° 1 0.0° step 1, 0.0°
15° 1 14.8° step 1, 15.1°
30° 1 30.0° step 1, 30.1°
45° 1 34.1° step 1, 34.4°
60° 2 59.8° on the edge: step 1 or 2
75° 2 68.2° step 2, 68.8°
90° 2 68.7° step 2, 68.8°
105° 3 102.9° step 3, 103.1°
120° 3 103.8° step 3, 103.1°
135° 4 135.0° step 4, 135.3°
150° 4 137.3° step 4, 137.5°
165° 5 165.1° step 5, 165.3°
180° 5 171.8° step 5, 171.9°
−45°, −90°, −150° 1, 2, 4 −34.3°, −68.8°, −137.3° the same, mirrored

2. 90° turns and zig-zags

Method. I walked north, then right-clicked alternately left and right, every 0.45 s. A path plot with one dot per frame showed the result.

Path shape.

Timing per direction change (angles converted to world directions with the camera fit, ±5°):

Click frame Direction change Pause at the corner Click → new heading
250 about 76° none 10 frames
298 about 152° stopped about 6 frames (3–4 ticks) 13 frames
346 about 113° stopped about 3 frames 10 frames
395 about 94° stopped about 3 frames 13 frames
444 about 89° stopped 2–3 frames 10 frames
491 about 84° none 9–11 frames

What this shows:

Zig-zag: straight legs with sharp corners

Zig-zag test. One dot per frame, labelled with frame numbers. The legs are straight and the corners are sharp.

Compared with research.md: “never speeds up or slows down on normal ground” is confirmed.

Engine log: turning while walking

The warlock walked east at full speed. After 1 s it got a new move order at an angle θ.

3. Walking speed

Measured speed.

Straight walk timings.

Size on screen.

What the camera shows.

4. Cast point (Fireball, labelled “Firebolt” in 0.99, hotkey G)

Method. I pressed G, which shows a blue circular area reticle on the cursor, and left-clicked a target at 0°, 90° and 180° from the warlock’s facing. The target click draws the same green confirmation arrows as a move order.

Timings:

Case Click Fireball appears Click → fireball Cooldown starts (icon) Launch → cooldown
0°, already facing (cast_bc) 97 106 9 frames = 0.15 s 124 18 frames = 0.30 s
90° (cancel_a) 95 about 109–113 about 14–18 frames 128 about 18 frames
180°, target behind (cast_a) 223 242 19 frames = 0.32 s 259 17 frames = 0.28 s

What I saw:

Fireball flight:

180° cast: the click at frame 223, the fireball at 242, the model still facing away

180° cast, frames 222–253. The target was clicked at frame 223. The fireball appears at frame 242. The flame streak grows toward the target (left) while the model is still part-way through its turn.

Engine log: when the cast starts

The warlock stood facing east and was ordered to cast Fireball 500 u away at an angle θ. The cooldown was not always reset between trials, so only every second trial cast.

θ Order → “begins casting” “Begins casting” → “starts the effect” Fireball object first logged
0° 0.000 s (same tick) 0.300 s +0.018 s
30° 0.046 s 0.300 s +0.014 s
60° 0.062 s 0.300 s +0.010 s
90° 0.107 s 0.300 s +0.006 s
120° 0.148 s 0.300 s +0.002 s
150° 0.168 s 0.300 s +0.028 s
180° 0.179 s 0.300 s +0.024 s

Compared with research.md:

Item research.md Measured / 0.99 data
Cast point 0.3 s, fireball at the end of it 0.3 s exists, but the fireball comes out at its start
Does it turn first? Yes Yes, quickly
Does a right-click cancel it? Yes No, in practice
Cooldown 4.8 s 5.0 s

5. Knockback

Method.

Results:

Hit M after the hit Formula slide Measured Decay per tick (fit)
1 7 539 u about 549 u (899 px across, 92 px down, rows 420–512) 0.9597
2 14 575 u diagonal (869 px across, 277 px down): within about 5% of 575 u 0.9592
3 21 610 u about 610 u (1174 px, rows 789–861) 0.9595

How it slows down.

Direction and interaction with walking.

Knockback slide: positions at the hit and 0.25–2.5 s after

Hit 1, the victim drawn at the hit and at +0.25, 0.5, 0.75, 1.0, 1.5 and 2.5 s. The fireball came from the right. Half the slide is done in the first 0.5 s.

Engine log: exact knockback

The logger set Player 2’s damage taken (its mana), then hit it from 160 u away. Scripted hits used UnitDamageTarget. Real hits used a Fireball cast by red. The table gives the first logged step and the victim’s knockback velocity from the map’s own variables.

Damage D Damage taken before M after the hit (logged) First step (u per 0.03 s) 0.96 × 0.03·D·(100+M) Slide 0.72·D·(100+M)
7 0 7 21.571 21.571 539 u
7 25 32 26.611 26.611 665 u
7 43 50 30.240 30.240 756 u
7 75 82 36.691 36.691 917 u
7 93 100 40.319 40.320 1008 u
3 0 3 8.899 8.899 222 u
14 0 14 45.964 45.965 1149 u
14 50 64 66.124 66.125 1653 u
7, real Fireball 0 / 43 / 93 7 / 50 / 100 21.571 / 30.240 / 40.320 the same 539 / 756 / 1008 u

Compared with research.md:

6. Lava

Method. I walked into the lava and stood in it for about 6 s, then walked out. I read the HP and mana text every frame.

Results:

Engine log. The warlock walked from (900, 0) east into the lava, then back to the centre.

The arena:

Compared with research.md:

Item research.md 0.99
Lava damage 9 HP/s 10 HP/s in round 1, rising 1 HP/s per round
Damage taken from lava Half the lava damage The full lava damage
Arena shape Circle Square
Shrinking Every 15·√alive s Only on a death or leave

7. Other things that make it feel like WC3

8. Map and engine data (v0.99 script and object data)

These values come from unpacking Warlock 099.w3x and the 1.26 MPQ archives.

Warlock unit h000 (based on the Peasant):

Property Value
Speed 210
Turn rate 0.6
Propulsion window 60°
Orientation interpolation 0
Cast point / backswing 0.3 / 0.51 s
Collision 25
HP / regen 100 / 0.5 per second
Max mana 10000 (used as damage taken)
Armour Divine 0
Model BloodelfWizard, scale 0.92

Movement loop. SystemPeriodic runs every 0.03 s. For each warlock:

  1. Read the engine position.
  2. Apply link, collision, thrust and shield effects.
  3. v *= 0.96, then pos += v. At the ±4096 walls the velocity is reflected.
  4. SetUnitX/SetUnitY. This does not interrupt the unit’s order.

Warlock collision.

Knockback. On EVENT_UNIT_DAMAGED from another player:

  1. mana += D
  2. v += (100 + mana)·D·0.03·q, radially away from the damage source (the projectile)

Fireball (A001, based on Blizzard):

Rounds.

Engine constants (Units\MiscData.txt):

Constant Value
ReactionDelay 0.25
CloseEnoughRange 100
AttackHalfAngle 0.5

MiscGame.txt clamps unit speed to between 150 and 400. No data file defines turn-rate units, acceleration or order latency. Those come from the engine code, and the engine log in sections 1–2 measures them:

The map also carries two injected chat cheat packs. They are inactive unless someone types their activation strings.

9. The WC3 movement pattern, as a model for the remake’s engine

WC3 applies the same pattern to every ground unit. Only the per-unit numbers differ: speed, turn rate (umvr) and propulsion window (uprw). The model below was checked against 80 logged move trials:

It also matched all 7 cast trials.

per unit:  speed (u/s), turnRate (rad per step), propWindow (deg), castPoint (s)
STEP = 0.03 s; each unit has its own step phase (so a new order waits 0-0.03 s)

on move order(target):
    walking = false                         # translation stops immediately, even for 0 deg

every STEP (logic):
    want = angle(target - pos)
    ok   = |wrap(want - heading)| <= propWindow      # tested BEFORE this step's turn
    heading += clamp(wrap(want - heading), -turnRate, +turnRate)
    walking  = ok                                    # walk this step along the NEW heading

every sim tick (0.01 s or finer):
    if walking: pos += dir(heading) * speed * dt     # full speed at once, no acceleration
    if |target - pos| <= ~11 u: stop dead, order done

on point-target spell order:
    if heading already equals want: cast starts this tick
    else: turn as above without walking; cast starts on the step after heading == want
    "begins casting" -> Warlock launches its projectile here
    castPoint (0.3 s) later: "starts the effect", cooldown starts, the unit is free again
    orders given during the cast point wait for it (a right-click does not cancel it)

display (model yaw, and GetUnitFacing):
    chases heading once per STEP: 0.07 rad, then 0.14 rad, then at most min(turnRate, 0.2) rad per step,
    covering about 60-75% of the remaining angle per step at the end
    -> after a 180 deg order the model faces the new way ~0.5 s later, so the unit slides backwards

Warlock script on top (every 0.03 s, not interpolated):
    on hit: M += D;  v += 0.03 * D * (100 + M) * q * unit(victim - source)
    v *= 0.96;  pos += v                              # total slide = 24 * |dv|
    lava: every 0.1 s on a lava tile: HP -= 1 + 0.1*(round-1), M += the same

What to copy for the remake

  1. Heading and walking. Two numbers, turnRate per 0.03 s and a 60° propulsion window, give WC3’s “walk almost at once, stop briefly on sharp turns” feel. With 0.6 rad per step, a 90° turn delays walking by one step and a 180° turn by four steps.
  2. The model’s lag is a separate, cosmetic layer. Copy it if you want the WC3 look: units turn visibly after they start moving.
  3. Order delay. The engine’s own delay is 0–0.03 s. The 0.13–0.15 s seen in multiplayer is network delay. A browser remake can choose one; about 0.1 s reads as “WC3”.
  4. Snap only script motion to 33 Hz. Walking is smooth in WC3. Knockback and projectiles are not.

10. Status, tools and what is left

Done.

The logger is in docs/wc3-instrumentation/. It covers the JASS that gets spliced into the map, the map builder and the log parsers. The Warlock map itself is not committed. The builder reads it from the Warcraft III folder.

Not done.

  1. Single-player click latency.
    • Clicks sent by the automation tool stalled WC3’s main loop, so the video and the log could not be lined up.
    • A human clicking while the logger runs, with a 60 fps recording, would settle it.
  2. Sound. I did not capture audio.