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.mddescribes.
research.mdwas written from Warlock v1.02.- The copy on this PC is
Maps/Download/Warlock 099.w3x: Warlock 0.99 by Zymoran and Deme[SanD].Warlock_099.w3xis the same file.- Its script is plain World Editor output, not obfuscated, so I could read every rule directly.
- Several rules differ from v1.02: collision, the knockback formula, lava damage, the arena shape and shrinking, and the economy. See section 8.
- Everything measured below agrees with the 0.99 script.
Game and map
war3.exe 1.26.0.6401), windowed.Capture
ddagrab (desktop duplication) at 60 fps, cropped to the game’s client area.Analysis
walk_north, turn180_a, turns_b, turns_c, turns_d, zigzag_a, cast_a, cast_bc,
cancel_a, cancel_b, lava_a, kb_hit1, kb_hit2, kb_hit3. They were not committed.Converting pixels to game units
Horizontal walking speed in pixels changes linearly with the screen row. At the health-bar row it measured:
| Screen row | Walking speed |
|---|---|
| 247 | 5.30 px/frame |
| 458 | 5.87 px/frame |
| 589 | 6.21 px/frame |
| 987 | 7.05 px/frame |
| 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). |
Method.
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, 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.
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 |
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:
SetUnitX/SetUnitY once every
0.03 s. The same is true of fireballs.
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.
The warlock walked east at full speed. After 1 s it got a new move order at an angle θ.
The start steps and first directions were identical to the standing turns, in all 16 trials:
| θ | Pause before walking again | First step direction |
|---|---|---|
| 0–45° | Up to the next step, 0–0.03 s | Straight, or 34.4° when θ = 45° |
| 60–90° | 0.03–0.06 s | 60°, or 68.8° when θ is 75–90° |
| 105–120° | 0.06–0.09 s | 103° |
| 135–150° | 0.09–0.12 s | 135–137.5° |
| 165–180° | 0.12–0.15 s | 165–172° |
Measured speed.
The two rulers give walking speeds of:
| Ruler | Walking speed |
|---|---|
| Knockback hit 1 (539 units) | 206 u/s |
| Knockback hit 3 (610 units) | 207 u/s |
| Knockback hit 2 (575 units, diagonal, less reliable) | 220 u/s |
| Fireball flight (960 units from the caster’s centre to where it vanished) | 212 u/s |
umvs 210).Straight walk timings.
Size on screen.
What the camera shows.
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:
FireballCast runs on EVENT_PLAYER_UNIT_SPELL_CAST (“begins casting”).
The cooldown starts at the spell-effect event, after the cast point.cancel_b).
So the move order waited out the cast point instead of interrupting it. In a second try (cancel_a)
the right-click landed 0.32 s after the target click, after the launch.
Fireball flight:

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.
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 |
SPELL_CHANNEL) and “begins casting” (SPELL_CAST) fire in the same tick.SPELL_EFFECT), “finishes” and “stops casting” all fire exactly 0.300 s
later. That gap is the cast point.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 |
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.
SetUnitX/Y on top of the engine walk, so a victim can walk while sliding.
The two vectors add.
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.
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 |
Answer to “knockback at 0, 50 and 100 damage taken”, for a 7-damage fireball, where M counts the hit:
| Damage taken, including the hit | Slide | Compared with a fresh warlock |
|---|---|---|
| 7 (fresh) | 539 u | 1× |
| 50 | 756 u | 1.40× |
| 100 | 1008 u | 1.87× |
If 50 or 100 is the damage taken before the hit, the slides are 791 u and 1043 u. research.md’s “roughly doubles at 100” holds.
Compared with research.md:
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:
Half-width = (8 + floor(alive/2) − 0.5) × 128:
| Alive | Half-width |
|---|---|
| 2 | 1088 |
| 12 | 1728 |
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 |
BloodelfWizard.mdl, scale 0.92) swings round smoothly behind the
logical heading. The rate limits are in section 1.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:
v *= 0.96, then pos += v. At the ±4096 walls the velocity is reflected.SetUnitX/SetUnitY. This does not interrupt the unit’s order.Warlock collision.
Knockback. On EVENT_UNIT_DAMAGED from another player:
Fireball (A001, based on Blizzard):
Rounds.
-N to set the number of rounds; the screen stays black until then.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.
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
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.Done.
docs/wc3-frames/:
turn180-model-lags.pngcast180.pngzigzag-path.pngknockback-slide.pngThe 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.
Logs\claude_N.txt in the Warcraft III folder, as Preload files.TimerGetElapsed, so I
re-ran everything.It adds these chat commands. Only red can use them.
| Command | What it does |
|---|---|
-cl exp1 |
Standing turns every 15° |
-cl exp2 |
Turns while walking |
-cl exp3 |
Standing casts |
-cl exp4 |
Sweep of turn rates 0.1–3.0 |
-cl exp5 |
Sweep of propulsion windows 1–180° |
-cl exp6 |
Scripted knockback at several damage-taken levels |
-cl exp7 |
Real Fireball knockback at damage taken 0, 43 and 93 |
-cl exp8 |
Lava |
-cl cam, -cl cam0 |
Log the camera fields, and centre the camera |
-cl ts X, -cl pw X |
Set the turn rate, or the propulsion window in degrees |
-cl ne X |
Set Player 2’s damage taken |
-cl dump |
Write the log out now |
Not done.