WASD movement for the player
While W/A/S/D are held, the controlled creature gets a plain walk order every engine tick toward its position plus the pressed screen direction, as the mouse does while its button is held (every mouse event re-sends a walk to the cursor point); releasing sends the target-less stop order of a released mouse button. W/A/S/D key events are swallowed before the hotkeys see them; their old actions move to G (action slot 3), V (pick up nearby) and K (save game window) for now, configurable in [wasd]. docs/wasd.md: order format, measured mouse behaviour, hotkey map. docs/todo.md: better pathfinder; final bindings for the moved hotkeys. re::ConfigString for string settings. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
52db0f79f9
commit
aa7d49409c
6 files changed
+425
No files matched your search
@@ -0,0 +1,30 @@
|
||||
# To do
|
||||
|
||||
## Better pathfinder (mouse clicks and monsters)
|
||||
|
||||
Replace the game's pathfinding with a more reliable and efficient one, for
|
||||
click-to-move and for monster AI. What we know so far:
|
||||
|
||||
- Walk orders are `cEvent_creature` command 4 with a ground target (+0x18/+0x1c),
|
||||
sent through `cEngine::SendCreatureOrder` (`0x6170d0`), which snaps the
|
||||
target to a walkable point (`0x616b70`) and hands it to
|
||||
`cCreature::ReceiveOrder` (`0x52e400`, vf18, ~6400 decompiled lines).
|
||||
- Far targets (~2000 world units) are rejected or followed badly.
|
||||
- Still to map: the path search itself, the sector/tile collision data it
|
||||
reads, and how monster AI issues its moves.
|
||||
|
||||
## Key bindings moved for WASD movement (temporary)
|
||||
|
||||
W, A and S were game hotkeys. With WASD movement (`src/mods/wasd.cpp`) their
|
||||
actions moved to other keys for now; choose final bindings (and update the
|
||||
in-game texts/tooltips that name the old keys):
|
||||
|
||||
| Key | Action | Temporary key (`[wasd]` in sacred_re.ini) |
|
||||
|---|---|---|
|
||||
| W | action slot 3 (`cEngine::UseActionSlot`, like Q/E/R/B/Space) | G (`ActionKeyW`) |
|
||||
| A | pick up items nearby (creature event 0x113) | V (`ActionKeyA`) |
|
||||
| S | save game window (`UI_WND_SAVEGAME`) | K (`ActionKeyS`) |
|
||||
| D | unbound | - |
|
||||
|
||||
Globally bound letters (engine `0x618130`, UI manager `0x757120`): A B C E F
|
||||
H I L M N O P Q R S T W, Space, ^, digits. Individual windows may use more.
|
||||
@@ -0,0 +1,60 @@
|
||||
# WASD movement (`src/mods/wasd.cpp`)
|
||||
|
||||
## How the game moves the hero
|
||||
|
||||
Movement is a creature order: `cEvent_creature` (vtable `0x88e95c`, 0x44
|
||||
bytes), command 4 = walk, sent with `cEngine::SendCreatureOrder` (`0x6170d0`,
|
||||
`(creature, event)`), which snaps a ground target to a walkable point and
|
||||
passes the order to `creature->vf18` (`cCreature::ReceiveOrder`, `0x52e400`).
|
||||
|
||||
| Offset | Field |
|
||||
|---|---|
|
||||
| +4 | command (4 walk, 0x105 ...) |
|
||||
| +0x10 | target object id (attacks) |
|
||||
| +0x14 | 2: x, y are a ground point; 0: no target |
|
||||
| +0x18 / +0x1c | ground point (world units, same as creature +0x1c / +0x20) |
|
||||
| +0x20 | 1: re-aim while a mouse button is held; 2: skip target snapping |
|
||||
|
||||
The controlled creature's object id is at `cEngine+0x13c`; objects come from
|
||||
`cObjectManager::GetObject` (`0x5fe060`, manager `*0xad3bc0`), cast with
|
||||
`__RTDynamicCast` to `cCreature`. Hero state: `+0xfc` action mode (2 while
|
||||
following a held mouse button), `+0x150` movement (1 walking, 2 arriving,
|
||||
0 standing).
|
||||
|
||||
Mouse, measured with an order log:
|
||||
|
||||
- click (`cEngine::HandleMouseButton` `0x617360`): one walk order to the
|
||||
ground point, then engine flag `+0x54 |= 0x10` (button held);
|
||||
- while held: every mouse event re-sends a plain walk order (+0x20 = 0) to the
|
||||
point under the cursor, dozens per tick; the hero stays in mode 2 and walks
|
||||
smoothly. `cEngine::Tick` (`0x60f1d0`, 10 Hz) additionally sends a re-aim
|
||||
order (+0x20 = 1) per tick after 0.4 s of walking;
|
||||
- release after > 0.5 s: a walk order without target (+0x14 = 0), which stops
|
||||
the hero in place.
|
||||
|
||||
## What the mod does
|
||||
|
||||
Every `cEngine::Tick`, while W/A/S/D are held (and no text field has the
|
||||
focus, no mouse button is held): a plain walk order to hero position +
|
||||
direction x 300 world units (about a cursor's distance). Screen directions in
|
||||
world axes: up (-1,-1), down (1,1), left (-1,1), right (1,-1); combinations are
|
||||
summed and normalised. All keys released: the target-less stop order.
|
||||
|
||||
Dead ends, for the record: re-aim orders (+0x20 = 1) on their own stop the
|
||||
hero after two orders; far targets (2000 units) are rejected or followed
|
||||
badly; targets near the stepwise-updated position make it arrive and stop.
|
||||
|
||||
## Hotkeys
|
||||
|
||||
Keys reach the game as `cEvent_key` (category 4; key at +6/+8, modifiers at
|
||||
+0xa) through the kernel queue to `cEngine::ReceiveEvent` (`0x618130`), which
|
||||
offers them to `cUI_Manager::ReceiveEvent` (`0x757120`) first. Both compare
|
||||
`toupper(key)` (`0x84aa86`). The mod swallows W/A/S/D there (auto-repeat events
|
||||
would trigger the hotkeys) and rewrites the replacement keys into the old
|
||||
letters; the temporary bindings are listed in `docs/todo.md`.
|
||||
|
||||
Hotkeys found: engine A (pick up nearby), P (pause), Q/W/E/R/B/Space
|
||||
(`cEngine::UseActionSlot`), ^ (console), Esc, Ctrl+B/F/X/Z (Z quicksave); UI
|
||||
manager C F H I L M N O S T (S save game window). Arrow keys in
|
||||
`cEngine::ScrollInput` (`0x610650`) walk object #2 or scroll the camera; not
|
||||
reachable in normal play.
|
||||
Reference in new issue
Block a user