Mörsergranate's explosion crashed twice reading the colour of a particle with a huge life (sacred.exe+0x361b54). Particles with life >= 256 or the unset fourth row are switched off before drawing; logged cases were all row 3 with garbage sizes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.9 KiB
Dwarf arts: Kanonenschuss and Mörsergranate
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,19hat0x517389, 25 steps of 40 = 1000 range. Hostile targets getcEvent_creature5 from0x51768d. - 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)at0x517709(pushes from0x5176f8), then the stun ordercEvent_creature3 with +0x14 = 100, sent bycall [eax+18h]at0x5177aa(returns to0x5177ad). - The stun is the knockback.
cCreature::ReceiveOrder0x52e400case 3: first the resistancevf24(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::Updatebranch0x594c82moves 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 byCreateAtat0x517855(target in ebx), resisted or not. - Mörsergranate: the grenade (type 0x3fa) lands and creates
TYPE_FX_GRENADEIMPACT(0x3fc), which gathers its targets withcObjectManager 0x5ff820(called from0x5ab400at0x5ab63d): a creature is hit when its distance is below the impact's size (150, type table0x428bb0) plus its own type's size.
The mod (src/mods/dwarfarts.cpp)
- The HIT_A motion is jumped over (
0x5176f8:jmppast the call). - The push step at
0x594debcallsPushStepThunk: creatures the cannon stunned (order 3 from0x5177ad, 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 (
0x5145d0case 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 at0x5169fa(cEventFX::Construct0x41e0a0, 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.