Entry 130
"The field's weather: rain, snow, fireflies and the rest of WORLD::Draw"
Documented in The story maps - EVENTAREA01 (area 13), EVENTAREA02 (area 15), EVENTAREA03 (area 43), EVENTAREA07 (area 16), EVENTAREAB0 (the boss arenas) and EVENTAREAB8 (Kyvia's disc), Leaving the town - Kite in a field and its dungeon, Field generation.
Filescrates/piney-world/src/field_ambient.rscrates/piney-world/src/field_firefly.rscrates/piney-world/src/firefly.rscrates/piney-world/src/field_area.rscrates/piney-world/src/field_world.rscrates/piney-world/src/lib.rscrates/piney-world/examples/ambient_probe.rscrates/piney-data/src/anim.rscrates/piney-data/src/field/render.rscrates/piney-data/src/field/mod.rscrates/piney-game/src/fx.rscrates/piney-game/src/fx/ambient.rscrates/piney-game/src/area.rscrates/piney-game/src/main.rstools/test_field_ambient_rs.pydocs/engine/field.mddocs/engine/field-walk.md
The port's fields drew their ground, objects, lake and sky, and nothing
else WORLD::Draw does: no rain, no snow, no fireflies at night, no steam
over type 0's lava, none of the servers' travellers crossing the sky. This
entry ports all of it, checked against the game frame by frame, and draws
it in the field.
What the game draws
WORLD::Init and Generate make the pieces and Draw / DrawEffect
step and draw them every frame, all from fieldrand except type 7's
fires, which turn with ccRand. field.md,
"Weather and ambient pictures", has the whole listing. In short:
- Snow. 100 or 200
SNOWs falling roundWORLD_MAN's centre (types 5 and 6); type 0's 16 embers rise from the ground. - Rain. 50 drops with their splashes. In a storm there are also bolts on the horizon, and a flash of the screen with thunder every 900-1,499 frames.
- Smoke. Type 7's fires smoke on even frames. Type 0's vents steam in bursts of eight.
- The 2D smoke. Types 2, 3, 5 and 6 drift big translucent puffs of
TEX_sfsmo1across the screen for a few seconds now and then. - The heat haze. Types 0-3 draw a model ahead of the player whose texture is the picture drawn so far, so the horizon shimmers.
- Fireflies. Five
FIREFLYs at night, or glyph trails when hacked. Type 9 has fifteenFIREFLY2s instead. - TOBJ. One field in seven gets the server's traveller.
- BIRD. A hawk over the dungeon entrance by day in type 10.
- The lens flare.
The game's slips
Each of these is kept, because the random draws depend on them.
- Rain placement.
DrawRainsetsWORLD+0x1c where it meant the drop's own "placed" flag, so all 50 drops are placed again every frame (100 draws). - Snow height. A flake's height asks
GetHeight(x, y != -500). - Snow at Init. The flakes made in
Initask for heights before the map exists, which is the heap's garbage in the game (zeros in eemu and here). They also fall round a centreGOnever set. - BIRD's far test. It adds
d.ytwice where it meantd.ysquared. - The 2D smoke's transparency. It is an int, so the fade out takes a single frame.
- The bolt's offset. A negative offset is converted as unsigned.
- Type 9's
FIREFLY2. It takes its height at the offset instead of the place.
The port
piney_world::field_ambient. Makes the pieces with the field. Each frame it hands back the pictures as a list ofOps in the game's order: sprites, smoke puffs, masks, models, sounds and the flash.field_firefly.FIREFLY(its splines areFRAC2's natural spline).firefly. Gains type 9'sFIREFLY2path.FieldArea. Carriesfieldrandon fromGenerate, keeps the drawing's function statics across fields, and draws the haze, TOBJ, BIRD and the 2D smoke.AreaFx. A newFieldFx::field_ambientdraws theccEffs, each made once as itsInitleft it. The puffs queue foreffSmoke, and the sounds and flash go out with the area's events.
Three things came to light while wiring it up.
- The haze's model.
OBJ_sfzair00is an ExtObj. Its model is found through the target, and the posed object is picked by that model, not by name. - TOBJ's "fog" is a shadow. The two
ccDrawEnvfields TOBJ sets are read byccShadowModel::Draw(main 0x001412b0) as the shadow's length and transparency. The fog lives elsewhere (+0xb8..+0xd8,SetFog). - Where the fires come from. They are set by
SetSpecialObjinEntryGimmick, which the port's fields don't have yet. The runtime finds them as the field is made: each chip object'sOBJ_roc1fireandOBJ_roc3firenode in its animation, plus the object'swp. The nodes are matched by name, because the file holds two objects of each name. The smoke rises from the braziers' tops in the shot.
piney-game --mode field:14/TYPE,ROW[,HACK[,SEED]] puts another field's
type, weather row, hack flag and seed into story area 14's WORLD_MAN, for
looking at any weather.
Checked
tools/test_field_ambient_rs.py(new). It runs the game'sInit,GenerateandDrawin eemu against theambient_probeexample, over every field type and background row, hacked and not, on a random server and seed, with the player and camera walking. It comparesfieldrand's counts, everythingInitandGeneratemade, and every frame's pictures in order along with thefieldrandandccRandcounts. It ran 124 cases of 1,000 frames with 0 mismatches. Every snow, rain, storm, flare, firefly and ember sprite showed up, as did the masks, puffs, sounds, flash, bird, haze and TOBJ.- Shots. Rain, a storm, heavy and light snow, night with fireflies, type 9 at night, the bird, type 7's fires, type 0's steam and haze, hacked, and the 2D smoke.
- The workspace's tests, clippy, fmt, and
test_evarea_rsfor the sharedFIREFLY2all pass.
EntryGimmickin a field. It isn't ported. In the game its draws (SetFood,SetMagicCircle,SetSpecialObj) come after the weather's first frames, so from then on the port's weather draws are offset from the game's by them. - The depth shades.WORLD_MAN's twoccBufferSamplingdepth shades need the z buffer as a texture, which the renderer lacks. - TOBJ's shadow and sounds. Neither is drawn or played. - The smoke puffs. They start a frame late, at the next effect task. - Balloon and Ω's runners. The balloon's cloth scroll and Ω's runners aren't seen in a shot, since the story's server is Δ. - The lens flare. It is left above the picture by the follow camera, and the eye view fails its camera test at the player's own place. No shot shows it.