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
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);
| 0x21 currentDirection1 | The direction the unit is facing. |
|---|---|
| 0x23 velocityDirection1 | The 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.
| 명령 대상이 살아남습니다 | 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
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