Eingraben becomes ground-targeted; after its own case the dwarf moves to the end of Phasenverschiebung's walk towards the point (stops before walls and cliffs). The barrier's bonus lasts 3 s and its lock in place (effect kind 0x3a) is dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
7.1 KiB
Markdown
127 lines
7.1 KiB
Markdown
# Dwarf arts: Kanonenschuss, Mörsergranate, Eingraben
|
||
|
||
## Requests (2026-10-25 / 2026-10-26)
|
||
|
||
- Kanonenschuss (art 0x43f, `gui_spells_kanone`): "remove the knockback,
|
||
instead it can be just a stun" (chosen: no push, only a stun); the range
|
||
increased for the wider view; the stun particles not on targets that
|
||
avoided the stun. The game's stun resistance stays (2026-10-26: "we dont
|
||
ignore anything, the skill is fine for now").
|
||
- Mörsergranate (art 0x43e, `gui_spells_moerser`): "the radius of the
|
||
explosion should increase every 5 skill levels".
|
||
|
||
## Measured
|
||
|
||
- The cannon's code is the combat move function `0x5145d0`, case 0x43f. Its
|
||
ray: `cmp edi,19h` at `0x517389`, 25 steps of 40 = 1000 range. Hostile
|
||
targets get `cEvent_creature` 5 from `0x51768d`.
|
||
- Stun chance `0x4fc810(level, creature)` = level × 5 / creature level × 100
|
||
(`UI_STAT_STUNNCHANCE`). On a successful roll: `0x5936e0(MOTION_HIT_A 0xaf,
|
||
3.0, 0.25)` at `0x517709` (pushes from `0x5176f8`), then the stun order
|
||
`cEvent_creature` 3 with +0x14 = 100, sent by `call [eax+18h]` at
|
||
`0x5177aa` (returns to `0x5177ad`).
|
||
- The stun *is* the knockback. `cCreature::ReceiveOrder` `0x52e400` case 3:
|
||
first the resistance `vf24(0x50)` (`0x55d0a0`: flag +0x4f0 & 0x1000 resists
|
||
2 in 3, effect 0x35d a percentage); otherwise push left +0x24d = 100, flag
|
||
+0x200 |= 0x20000, attacker +0x259, ResetToIdle. `cCreature::Update` branch
|
||
`0x594c82` moves a creature with that flag away from the attacker and lowers
|
||
the push left by each step (`0x594deb`), measured about 100 units in 0.3 s;
|
||
at 0 the flag is cleared.
|
||
- The impact effect `TYPE_FX_DWARF_SHOOT_IMPACT` (0x47f) is created on every
|
||
hit target by `CreateAt` at `0x517855` (target in ebx), resisted or not.
|
||
- Mörsergranate: the grenade (type 0x3fa) lands and creates
|
||
`TYPE_FX_GRENADEIMPACT` (0x3fc), which gathers its targets with
|
||
`cObjectManager 0x5ff820` (called from `0x5ab400` at `0x5ab63d`): a creature
|
||
is hit when its distance is below the impact's size (150, type table
|
||
`0x428bb0`) plus its own type's size.
|
||
|
||
## The mod (`src/mods/dwarfarts.cpp`)
|
||
|
||
- The HIT_A motion is jumped over (`0x5176f8`: `jmp` past the call).
|
||
- The push step at `0x594deb` calls `PushStepThunk`: creatures the cannon
|
||
stunned (order 3 from `0x5177ad`, kept with an end time) move by 0 and keep
|
||
their push left above 0 for 1.5 s, so they stand still, then carry on.
|
||
- The impact effect is created only on targets in the stun state.
|
||
- The ray gets 45 steps (1800); confirmed to reach across the widened view.
|
||
- The impact's gather call gets a radius of size × (1 + 0.1 × (level / 5)),
|
||
with the owner's Mörsergranate level (`game::ArtLevel`). The growth 0.1 per
|
||
step is our choice; not yet seen in the game (Borf's level is 2).
|
||
|
||
## Mörsergranate impact marker (asked 2026-10-25, done 2026-10-26)
|
||
|
||
"Show exactly where the grenade will land and its explosion radius, a red
|
||
circle with low alpha on the ground."
|
||
|
||
Measured:
|
||
- The landing point is decided at launch (`0x5145d0` case 0x43e): the
|
||
target's position, or, closer than 200, a point 200 from the dwarf with a
|
||
+-15 jitter. It goes to the new grenade (type 0x3fa) in cEventFX 0x96,
|
||
constructed at `0x5169fa` (`cEventFX::Construct` 0x41e0a0, thiscall, ret
|
||
0x44: code, owner id, target id, position area / x / y / level, ...).
|
||
- The impact gathers its targets at exactly that point, on several frames.
|
||
The grenade object stays about 30 s after the explosion.
|
||
- Ground -> screen: `0x622700` (world units -> world pixels, the isometric
|
||
plane), then (pixel - camera +0x14/+0x18) / zoom +0xb60 + screen centre
|
||
(floating texts 0x41e546). Checked with the hero: the screen centre.
|
||
- The world view draws the ground (`0x62d530`, ground quad list), then the
|
||
objects.
|
||
|
||
Mod: the construct call notes grenade, owner, landing point and radius
|
||
(`ImpactRadius`, shared with the hit check); after `0x62d530` a disc (alpha
|
||
0x40) with a 2 px rim (alpha 0xa0) is drawn there, without depth test, until
|
||
the impact of that owner's grenade at that point gathers its targets.
|
||
|
||
Tooltip (2026-10-26, "the skills tooltip does not show the current radius"):
|
||
a game::Art tooltip filter adds "Explosionsradius: N" after the last value
|
||
line of each level section (current level, and the next level's in the skill
|
||
book), in that line's colour, from the same `ImpactRadiusAt(level)` as the
|
||
hit check and the marker.
|
||
|
||
## Grenade impact crash (2026-10-26)
|
||
|
||
Crashes at sacred.exe+0x361b54 (2026-10-26 00:12 and 22:39) in the particle
|
||
drawer `0x7613e0`, called by `cParticleSystem_grenadeimpact::Render` (vf04
|
||
0x7b66b0): colour = table +0x20d0 at row (+0x3d) * 256 + life (+0x2c), and a
|
||
particle had a life of over 500000. Guard (`mods/guards.cpp`): live particles
|
||
with life >= 256 or row >= 3 are switched off before drawing. Logged in the
|
||
next session: 5 particles, all row 3, life 255, garbage sizes (e.g. 190555,
|
||
4.6e-40): the explosion emits into a fourth row whose emitter parameters it
|
||
never sets (vf10 0x7b6980 fills three rows at +0x30d0). No crash since.
|
||
|
||
## Eingraben: the dwarf's escape (request 2026-10-28)
|
||
|
||
"I want it to be the Dwarfs option to Teleport/Escape. The Skill will cast a
|
||
protective barrier around the Dwarf (current visual effect), clear him of all
|
||
movement impending effects and then teleport to the position marked by the
|
||
cursor (if possible). The Teleport is visually shown by the dwarf going
|
||
underground and coming out again at target position." Range: the visible
|
||
area; the barrier is the skill's current defensive bonus for 3 s; digging in
|
||
and out 1 s each; "he should be able to see the target location", compared
|
||
to the battlemage's Phasenverschiebung; the original lock in place goes.
|
||
|
||
Found in the code:
|
||
- Spells run in `cCreature::CastSpell` (0x5222c0, thiscall (cast), ret 4;
|
||
cast +0x08 / +0x0c the ground point, +0x20 the spell id). Eingraben is
|
||
spell 0x39 (`gui_moves_eingraben`, launch type 5 around the caster).
|
||
- Case 0x39 creates object type 0x480 at the caster with cEventFX 0x9d (owner
|
||
and target the caster) and plays sound 0x840: the barrier, which follows
|
||
the dwarf.
|
||
- Case 1 (Phasenverschiebung, launch type 3) walks from the caster towards the
|
||
target in steps of 10 while the cell is passable (`cWorld::IsPassable`
|
||
0x636b60) and keeps the last point a creature can stand on
|
||
(`cWorld::CanStand` 0x636eb0); a wall or cliff in the way ends the walk.
|
||
|
||
Logged (2026-10-28): the barrier adds, all with art 0x39, kind 0x3a value 0
|
||
from its particles (0x7b9602), the lock in place (the dwarf was stuck 2-3 s),
|
||
and kind 2 value 0.5 plus kinds 7..0xa value 30 from its update (0x5b5862..),
|
||
the defensive bonus (resistances up while it lasts).
|
||
|
||
Mod (`mods/dwarfarts.cpp`): Eingraben's definition +0x3c becomes 3 (a point);
|
||
after the original case the dwarf is teleported to the end of
|
||
Phasenverschiebung's walk towards the point (the cursor keeps it within the
|
||
visible area). The effect hook (`aurarecast.cpp`, `KeepEffect`) drops kind
|
||
0x3a for art 0x39 and cuts the art's other effects to 3 s. Confirmed
|
||
2026-10-28: aimed, stops before walls and cliffs, casts at once at the screen
|
||
edge, the barrier moves with him, no lock, bonus for 3 s. Open: clearing
|
||
slows and stuns, 1 s digging in and out.
|