Entry 118
"Smoke and dust: effSmoke, the enemies' feet, a gold goblin's run and an idol opening"
Filescrates/piney-effect/src/dust.rscrates/piney-effect/src/lib.rscrates/piney-effect/examples/particle_probe.rscrates/piney-battle/src/enemy_motion.rscrates/piney-battle/examples/battle_probe/enemy_motion.rscrates/piney-battle/examples/battle_probe/spawn.rscrates/piney-world/src/combat/dust.rscrates/piney-world/src/combat/mod.rscrates/piney-world/src/combat/stage.rscrates/piney-world/examples/dust_probe.rscrates/piney-game/src/fx.rscrates/piney-game/src/session.rstools/test_effect_particle_rs.pytools/test_dust_ctrl_rs.pydocs/engine/effects.mddocs/engine/particles.mddocs/engine/battle.md
The battle's rules already raised three dust calls, and nothing drew them:
Call::DustCtrl, from the races'exclusive()and their footstep notes;Call::Dust, a gold goblin running;Out::DustRing, an idol opening (116 left it).
All three end in effSmoke, which was not ported either.
effSmoke and the dust (piney_effect::dust)
effSmoke(main 0x001ce300) is one particle on effect.cpp's staticccpgSmoke. Its life is shortened by up to half at random, and it takes the velocity, size and fades it is given, plus a random turn.ccEnemyEffDust(gcmn 0x0043a3e0) makes n puffs at random headings (ccRandF(pi)), 10 s out, flying out and up.ccEnemyEffDustRing(gcmn 0x0043a590) makes n puffs evenly round from a random start, r out. Under 4 it is the plain dust instead.- The character overload (0x0043a7a0) places the ring at the character's feet (FW2LW) plus its turned offset.
The enemies' feet (piney_world::combat::dust)
ccEnemyDustCtrl keeps a node per ccEnemyDustInfo row with the last
frame bucket it fired in. ctrl(obj, flag) fires a row when:
- the enemy is shown, its
anmNumis the row's (2 and 3 match either), and itsframeNumis inside the row's window; - and either:
- on a note, for rows with
every0; - every frame, when the window is one frame;
- once per bucket of
everyframes otherwise.
- on a note, for rows with
The rules now send what ctrl reads with the call (DustAt: the rows,
dispSW, eneSmoke, anmNum, frameNum, pos, dirc). The rules'
harnesses print only the flag, so they still match.
The controller draws nothing random. The runtime runs it in the effects'
pass over the frame's shows (Combat::fx_call), in order: a race
constructor's Out::Dust sets the nodes, and each DustCtrl is followed
by the Show::DustRings it raised. fx.rs starts:
- those rings;
- the gold goblin's dust (FW2LW, then
ccEnemyEffDust(p, 1, size, 6, eneSmoke), arguments checked in itsexclusive()); - the idol's ring (
(0, 800, -530), 4, 100, 8, 30, 132).
Checked
test_effect_particle_rs.py'stest_smoke_and_dust. The game'seffSmoke,ccEnemyEffDustand both rings run in eemu over the real particle system, besideparticle_probe. The machine'sgenrandand the probe's are now the same MT19937 seeded alike. Ten cases in towns and fields: random sizes, lives, textures and ring counts, a character turned, the puffs run out. 904 frames of every particle's whole state match. The whole particle harness (15,263 frames) and the skill harness still pass.tools/test_dust_ctrl_rs.py(new). It lays a controller out in eemu over three races' real tables and a made-up one (rows of anm 2 and 3, a one-frame window), and runs the game'sctrlfor 3000 steps each: animations changing, frames advancing, notes,dispSWoff now and then.dust_proberuns the port'sctrlalongside. Every step's rings match, and every row fires somewhere.event_3_plays_its_fightsnow also asserts dust. The portal's goblin (row 130, type 1) has one row, its fall (anm 10, frame 35), and the fight raises exactly that one ring.- The workspace's tests, clippy and fmt pass.
effSmoke's other callers are not ported: the Grunties (ccPGuso),WORLD::DrawSteamandDrawEffect,ccGimSymbol,ccEnemyBrPart::explode,ccDogand the bosses' back dashes. The party's running dust (ccEffPawSmoke) is a separate function and is not ported. - No shot of the dust yet. The one fight in the session tests raises a single ring as the goblin falls.