SCRMaps
/
Sign in

Moving a unit yourself: teleporting and walking

MoveUnit is expensive, wipes the order and switches on tile-collision ignoring. Doing it from the struct avoids all three - and lets you pick which of the two you want.

10 min read

Moving a unit is two different jobs: teleport it there, or make it walk there. MoveUnit does only the first, and in exchange it wipes the order, loses the attack target and switches on tile-collision ignoring. From the struct you get both, and none of that.

Walking is the simpler of the two. A unit whose 0x10 moveTargetXY differs from its 0x28 position walks to close the gap, so it is two lines.

const xy = x + (y << 16);
SetMemoryEPD(epd + 0x10/4, SetTo, xy);   // moveTargetXY
SetMemoryEPD(epd + 0x18/4, SetTo, xy);   // nextMovementWaypoint
0x18 is there because some units do not move without it. With both, every unit that can move at all does.

Redirect it mid-walk, though, and the unit shuffles instead of turning. Writing the facing in the same pass fixes it.

const ux, uy = posread_epd(epd + 0x28/4);
const dir = atan2_256(y - uy, x - ux);
SetMemoryXEPD(epd + 0x20/4, SetTo, (dir << 24) + (dir << 8), 0xFF00FF00);
That single masked write touches two fields inside the dword at 0x20.
The two directions inside 0x20
0x21 currentDirection1The direction the unit is facing.
0x23 velocityDirection1The direction the unit is travelling.

Writing only 0x21 turns the picture. Writing both makes the unit set off instantly with no turn animation - smoother than the game's own movement. Set them differently on purpose and a unit faces one way while sliding another, except that when the destination is within roughly 180 degrees of 0x23 the engine uses the real destination.

Four things that follow
명령 대상이 살아남습니다The order target survives, which is how “keep attacking while repositioning” is built.
WASD라면 0x1C도 쓰세요A scheme that pins 0x21 must write 0x1C too, or a unit that stops faces backwards.
컴퓨터의 일반 유닛은 되돌아갑니다A computer's ordinary units carry a return-to-region AI that undoes those writes. Make them heroes, or use the order route.
9~12플레이어와 도어류도 됩니다It works for players 9-12, and on Door-type units that have been made into units.

There is an order-based route - write the destination to 0x58 and set 0x4D to 6, Move - and it is the worse one.

It responds slowly and the destination cannot be changed mid-walk, because 0x58 does not feed 0x18 and 0x1C. Writing 0x4E to 0 restores mid-walk redirection and 0x85 to 0 improves the latency, but measured side by side the two-line form is still faster. And do not mix the two: with 0x58 in play, 0x10 is ignored.

That slowness has a recognisable signature. A damage-font system built on the order route had its font units occasionally scatter in random directions; switching to 0x10/0x18 ended it. If a group of effect units sometimes breaks formation, suspect this.

For teleporting, the field is halt: 0x2C and 0x30 hold where the unit is actually travelling to, as the coordinate times 256. The unit chases halt, not the destination.

SetMemoryEPD (epd + 0x2C/4, SetTo, x << 8);        // halt X
SetMemoryEPD (epd + 0x30/4, SetTo, y << 8);        // halt Y
const xy = x + (y << 16);
SetMemoryEPD (epd + 0x10/4, SetTo, xy);
SetMemoryEPD (epd + 0x18/4, SetTo, xy);
SetMemoryEPD (epd + 0x1C/4, SetTo, xy);
SetMemoryXEPD(epd + 0x20/4, SetTo, 0x14, 0x14);    // 제동 + 이동 / braking + moving
0x14 is 0x4 braking plus 0x10 moving. Braking is what stops it turning first and stops it dead on arrival; moving is the state halt needs. All three waypoint writes are load-bearing - leave one out and the unit walks back to roughly where it was.

If halt is ever left different from the 0x28 position, that unit can never move again - alive, taking orders, silently stuck. Sending it somewhere it cannot reach leaves it in that state, and the only repair is writing halt back equal to position. A unit frozen after a dash is almost always this.

Look the addresses up and you will find 0x18 and 0x1C marked unsupported on Remastered - while the techniques above work, with video. When the two disagree, trust the compiler: eudplib turns a field that would throw an EUD error into a compile error, so if the build passed, the field is reachable. The offset tables are at their best for what a field means.

Area effects and knockbackThree ways to read the struct wrong
Sign in to track your progress