Alchemy
Loading...
Searching...
No Matches

particle_streams.c

Go to the documentation of this file.
1/// @file
2/// Meteor and Outer Space.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7/// Adds per-channel steps to background colours 1 to 63, capped at 31.
8///
9/// Called once a frame to whiten the colours over a few frames: by
10/// BattleFx_RunParticleStreams from frame 36 of its burst, and by Tiamat's
11/// BattleFx_RunPaletteParticles. Rewrites background palette RAM.
12void Palette_BrightenBgEntries(s32 blueStep, s32 greenStep, s32 redStep) {
13 u16 *color = (u16 *)&BG_PLTT[1];
14 s32 i;
15
16 for (i = 0; i != 63; i++) {
17 s32 blue = (*color >> 10) & 0x1f;
18 s32 green = (*color >> 5) & 0x1f;
19 s32 red = *color & 0x1f;
20
21 blue += blueStep;
22 green += greenStep;
23 red += redStep;
24 if (blue > 31)
25 blue = 31;
26 if (green > 31)
27 green = 31;
28 if (red > 31)
29 red = 31;
30 *color++ = RGB(red, green, blue);
31 }
32}
33
34/// Arms DMA 0 to write one halfword of the table at work->sheet + 0x1f80 into
35/// background colour 0 at each horizontal blank, so the backdrop colour
36/// changes line by line.
37///
38/// Runs each frame as a scheduler callback (order 0x4fe) that
39/// BattleFx_RunParticleStreams adds for its rise and removes after it; the
40/// rise rewrites the 160 colours, its heat lines, every frame. Stops DMA 0
41/// and sets it up again, so the table is read from line 0.
44 volatile u16 *channel = REG_DMA0;
45 Dma_Stop(channel);
46 Dma_Set(work->sheet + 0x1f80, (void *)BG_PLTT, DMA_HBLANK_HALFWORD_PER_LINE,
47 (volatile u32 *)channel);
48}
49
50/// A formation rises out of a dissolving starfield and bursts into embers and
51/// flashes: the particle stream in mode 0, with one spawned object rising.
52///
53/// Abilities: Meteor (scene kind 11).
56}
57
58/// The user leaps up, and two objects rise out of a dissolving starfield and
59/// burst into embers and flashes: the particle stream in mode 1, in the
60/// lightning bolt's colours.
61///
62/// Abilities: Outer Space (kind 384).
65}
66
67/// The burst's embers, 512 in PARTICLES after its 128 flashes.
68#define PARTICLE_STREAMS_EMBERS (&PARTICLES[128])
69
70#define PARTICLE_STREAMS_RISE_FRAMES 192 ///< frames, at most, of the rise
71#define PARTICLE_STREAMS_BURST_FRAMES 54 ///< frames of the burst
72
73/// The mote pictures in the sheet: two sets, MOTE_SET_BYTES apart.
74#define PARTICLE_STREAMS_MOTE_CELLS 0x3200
75
76/// The stream runs in two halves. The rise dissolves the battle map into a
77/// starfield, then for up to PARTICLE_STREAMS_RISE_FRAMES lifts a formation of
78/// objects while motes, orbiting sparks and falling drops are drawn into the
79/// map buffer over a heat-tinted scanline palette. The burst then switches to
80/// a blended half-scale canvas and throws embers, screen motes and growing
81/// flashes from the origin for PARTICLE_STREAMS_BURST_FRAMES shaking frames.
82///
83/// Particle slots: the burst's flashes use PARTICLES 0 to 127 and its embers
84/// the 512 after them (PARTICLE_STREAMS_EMBERS); work->particles holds the
85/// rising motes (0 to 31) and the flames (32 to 47).
86///
87/// Called by BattleFx_RunMeteor (mode 0) and BattleFx_RunOuterSpace (mode 1).
88/// The rise shows Ram_MapCellBuffer on BG1 through
89/// BattleFx_FlushPendingGraphicsTransfer, scrolls BG2 with
90/// BattleFx_AdvanceBg2OnInterval and colours the backdrop with
91/// BattleFx_ArmPaletteHBlankDma, and removes all three after; it also moves
92/// the projection centre down to line 240 and sets the background view's
93/// active flag while it runs. The burst sets BG2 back to the half-scale
94/// canvas and ends the canvas layer. Releases the formation objects it
95/// spawned (mode 1's on frame 48 of the burst).
97 s32 mode) {
98 volatile u32 fill;
99 u8 offsets[128];
100 void **cache;
101 void *canvas;
102 DrawRectangle draw;
103 s32 direction;
104 struct BattleEffectWork *work;
105 void *colors = (void *)BG_PLTT;
106
107 /// Starts a flame in the first free particle slot from 32 to 47; called
108 /// for each drop that reaches rows 94 and 95. A flame is never drawn.
109 void ParticleStreams_SpawnFlame(s32 x, s32 y, s32 velocityX) {
110 s32 i;
111
112 for (i = 0; i != 16; i++) {
113 struct EffectStep *flame = &work->particles[32 + i];
114
115 if (flame->variant == -1) {
116 flame->variant = 0;
117 flame->x = x;
118 flame->y = y;
119 flame->velocityX = velocityX;
120 break;
121 }
122 }
123 }
124
125 /// Starts a mote in the first free particle slot from 0 to 31. Nothing
126 /// calls it: the rise starts its motes inline.
127 UNUSED void ParticleStreams_SpawnMote(s32 x, s32 y) {
128 s32 i;
129
130 for (i = 0; i != 32; i++) {
131 struct EffectStep *mote = &work->particles[i];
132
133 if (mote->variant == -1) {
134 mote->variant = 0;
135 mote->x = x;
136 mote->y = y;
137 break;
138 }
139 }
140 }
141
142 struct SpritePlacement position;
143 s32 vector[3];
144 struct EffectPosition spot;
145 struct EffectPosition *screenPosition;
146 struct EffectPosition point;
147 struct SpriteScale scale;
148 s32 frame;
149 s32 i;
150
151 cache = &gBattleFxWork[1];
152 canvas = cache[0];
153 work = cache[-1];
154
155 // Begin: in mode 1 the user leaps up with a sound. The stream's direction
156 // is 1 when the mode 1 user stands on side 1, otherwise -1.
157 work->effect = effect;
159 /* FAKEMATCH: test through direction so CSE retains the mode reload in this
160 * arm; testing mode directly, 2 of 1532 instructions differ in tbs-en. */
161 direction = mode;
162 if (direction == 1) {
163 struct MotionObject *object =
165
166 object->velocityY = 0xa0000;
167 object->verticalMotionStrength = 0x91eb;
168 ObjectGroup_UpdateMembers(work->effect->actor, -1, 2, -1, 0);
170 direction = work->effect->side == 1 ? mode : -1;
171 } else {
172 direction = -1;
173 }
175 PLTT_BACKDROP = 0;
176 *(u16 *)&BG_PLTT[1] = 0;
182 // The rising formation: two animated objects in mode 1, otherwise one
183 // spawned object.
184 if (mode == 1) {
185 for (i = 0; i != 2; i++) {
186 struct AnimationObject *object =
188
189 work->objects[i] = object;
190 if (object != 0) {
191 object->flags = 0;
193 work->objects[i]->image.priority = 3;
194 }
195 }
196 } else {
197 BattleFx_SpawnObjects(1, 381, 3);
198 }
199 // The starfield: load the flame sheet (and in mode 1 the bolt's palette),
200 // fill the screen map, give palette entries 128 to 190 random bright
201 // colours and scatter 256 random dots over the 128x128 canvas.
203 if (mode == 1)
204 Iwram_CopyWords(colors,
206 128);
207 fill = 0x01010101;
208 Dma_Set((void *)&fill, Ram_MapCellBuffer, DMA_FILL_WORDS(0x2000), REG_DMA3);
210 WaitFrames(1);
211 REG_BLDCNT = 0;
212 REG_BG2PA = Q_8_8(1);
217 for (i = 0; i != 63; i++) {
218 s32 red = (Random16() & 15) + 16;
219 s32 green = (Random16() & 15) + 16;
220 s32 blue = (Random16() & 15) + 16;
221
222 ((u16 *)&BG_PLTT_COLOR(8, 0))[i] = RGB(red, green, blue);
223 }
224 fill = 0;
225 Dma_Set((void *)&fill, canvas, DMA_FILL_WORDS(0x1000), REG_DMA3);
226 for (i = 0; i != 256; i++) {
227 s32 x = Random16() & 127;
228 s32 y = Random16() & 127;
229 s32 shade = (Random16() & 63) + 64;
230
231 ((u8 *)canvas)[((y / 8 * 16 + x / 8) * 8 + (y & 7)) * 8 + (x & 7)] = shade;
232 }
233 Iwram_CopyWords((void *)BG_CHAR_BLOCK(1), canvas, CANVAS_BYTES);
234 // Dissolve: start the background scroll, then erase the map from the top
235 // in ragged columns, each lagging by one of 128 random offsets of 0 to 63
236 // rows. The erased band grows faster every frame until it passes row 191.
237 gProjection.centerY = 240;
239 work->bg2x = 0;
240 work->bg2y = 0;
241 work->scrollTimer = 0;
242 work->scrollInterval = 2;
243 work->scrollStepX = direction << 7;
244 work->scrollStepY = 256;
248 for (i = 0; i != 128; i++)
249 offsets[i] = Random16() & 63;
250 {
251 s32 limit = 0;
252 s32 step = 1;
253 s32 row = 0;
254
255 do {
256 limit += step / 2;
257 step += 4;
258 for (; row != limit; row++) {
259 s32 x;
260
261 for (x = 0; x != 256; x++) {
262 s32 y = row - offsets[x & 127];
263
264 if (y >= 0)
265 if (y <= 127)
266 Ram_MapCellBuffer[((y / 8 * 32 + x / 8) * 8 + (y & 7)) * 8 +
267 (x & 7)] = 0;
268 }
269 }
271 } while (limit <= 191);
272 }
273 // The rise: blend the map over the backdrop, colour the backdrop line by
274 // line from the heat lines, and draw motes, orbit sparks and drops into the
275 // map for up to PARTICLE_STREAMS_RISE_FRAMES frames. A or B skips ahead
276 // after frame 16 in mode 1, after frame 4 otherwise. The backdrop's scroll
277 // is restored afterwards.
279 REG_BLDALPHA = BLEND_ALPHA(16, 16);
280 {
281 s32 savedX = gBgScroll[1].x;
282 s32 savedY = gBgScroll[1].y;
283 // Two independent absolute slot reads grow native EN from 0xe38 to 0xe48.
284 void **slots = &gWorkSlot[HEAP_SLOT_BATTLE_BACKGROUND];
285 struct BattlePresentationTransition *presentation = slots[0];
286
287 gBgScroll[1].x = 0;
288 gBgScroll[1].y = 32;
292 // Each copy darkens every pixel of the map by 2 levels (four bytes of 2
293 // in one word, as the other darkening effects write theirs).
296 EFFECT_FREE_PARTICLES(i, work->particles, 64);
297 presentation->active = 1;
298 work->frame = 0;
299 frame = 0;
300 do {
301 s32 angle = frame << 8;
302 /* FAKEMATCH: count fixed in r2 keeps the division temp canonical in cse
303 * for the compare and +3, as in the reference; unpinned, 10 instructions
304 * differ in tbs-en. */
305 register s32 count asm("r2") = work->frame;
306 /* FAKEMATCH: work's copy in r0; else it and the 0x778c reload swap r0/r1.
307 * As an ordinary base, 8 of 1532 instructions differ in tbs-en. */
308 register u8 *base asm("r0") = (u8 *)work;
309 s32 heat = count / 4;
310 u16 *line;
311 s32 size;
312 s32 x;
313 s32 y;
314
315 /* FAKEMATCH: count read and base passed through keep count's load apart
316 * from the division temp, with no sched2 barrier, so the mode reload
317 * lands after movs r2, #252 as in the reference. */
318 asm("" : "=r"(base) : "0"(base), "r"(count));
319 line = (u16 *)(base + 0x1f80);
320 if (mode == 1) {
321 if ((gKeysRepeat & (KEY_A | KEY_B)) && frame > 16)
322 break;
323 } else {
324 if ((gKeysRepeat & (KEY_A | KEY_B)) && frame > 4)
325 break;
326 }
327 {
328 s32 hold;
329
330 /* FAKEMATCH: hold takes r7 across the call, so heat takes r4 and its
331 * sp+8 caller-save as in the reference; as a plain call, 354
332 * instructions differ in tbs-en. */
333 asm("" : "=r"(hold));
334 /* FAKEMATCH: r6 is clobbered across the call. */
335 asm("" : : : "r6");
336 if (frame == 0)
338 /* FAKEMATCH: hold's use after the call. */
339 asm("" : : "r"(hold));
340 }
341 // The heat lines, the 160 backdrop colours that
342 // BattleFx_ArmPaletteHBlankDma streams in one per scanline: black on
343 // lines 0 to 14 and 135 to 159, and between them a ramp, blue first
344 // and then green, that brightens as the rise goes on.
345 for (i = 0; i != 15; i++)
346 *line++ = 0;
347 for (; i != 135; i++) {
348 s32 green = i - 16;
349 /* FAKEMATCH: reuse blue for the biased signed quotient. A
350 * separate quotient coalesces with level; the explicit bias
351 * keeps the native r3 copy and shift (four register rows). */
352 s32 blue = green;
353 /* FAKEMATCH: level in r2; as an ordinary local, 42 of 1532
354 * instructions differ in tbs-en. */
355 register s32 level asm("r2");
356
357 if (green < 0)
358 blue += 3;
359 blue >>= 2;
360 level = blue + heat;
361 blue = level - 32;
362 green = level - 80;
363
364 CLAMP(blue, 0, 31);
365 CLAMP(green, 0, 31);
366 *line++ = RGB(green >> 1, green, blue);
367 }
368 for (; i != 160; i++)
369 *line++ = 0;
370 if (direction == 1)
371 x = frame / 4;
372 else
373 x = 64 - frame / 4;
374 y = 96 - frame;
375 // Place the formation (both objects in mode 1), drifting with the
376 // stream and growing each frame.
377 position.groundHeight = 0;
378 position.height = 0xff0000;
379 if (mode == 1) {
380 size = angle + 0xa000;
381 scale.x = size;
382 scale.y = size;
383 position.x = (x << 16) + 0x500000;
384 position.y = (64 - y) << 16;
385 Object_ApplyProjectedPlacementFar(work->objects[0], &position, &scale,
386 0);
387 Object_ApplyProjectedPlacementFar(work->objects[1], &position, &scale,
388 0);
389 } else {
390 size = angle + 0x10000;
391 scale.x = size;
392 scale.y = size;
393 position.x = (x << 16) + 0x600000;
394 position.y = (96 - y) << 16;
395 Object_ApplyProjectedPlacementFar(work->objects[0], &position, &scale,
396 0);
397 }
398 // A new mote rises from a random point on the lower half of a circle
399 // of radius 30 * size beneath the formation.
400 for (i = 0, y = 32 - y; i != 32; i++) {
401 struct EffectStep *mote = &work->particles[i];
402
403 if (mote->variant == -1) {
404 s32 angle = (Random16() & 0x7fff) + 0x4000;
405
406 mote->variant = 0;
407 mote->x = ((x + 96) << 16) + Trig_Sin(angle) * 30 / 65536 * size;
408 mote->y = (y << 16) - Trig_Cos(angle) * 30 / 65536 * size;
409 break;
410 }
411 }
412 // The seven orbit sparks, 8x8, turning with the frame and lifting
413 // with it.
414 point.x = 0;
415 point.y = 0;
416 point.depth = 0x2000000;
420 SceneTransform_ApplyYaw(frame << 8);
421 for (i = 0; i != 7; i++) {
422 SET_VECTOR(vector, (gParticleStreams_OrbitPoints[i][0] / 2) << 16,
423 (gParticleStreams_OrbitPoints[i][1] + frame) << 16,
424 (gParticleStreams_OrbitPoints[i][2] / 2) << 16);
425 EffectPosition_ProjectPoint(vector, screenPosition = &spot);
426 screenPosition->x = Q_16_16_TO_INT(screenPosition->x) + 128;
427 screenPosition->y = Q_16_16_TO_INT(screenPosition->y) + 60;
428 draw(Ram_MapCellBuffer, work->sheet + 0x1f40, screenPosition->x - 4,
429 screenPosition->y - 4, 8, 8);
430 }
431 if (direction == 1)
432 x = frame / 4 - 16;
433 else
434 x = 16 - frame / 4;
435 // The seven falling drops, 24x24; a drop reaching rows 94 and 95
436 // becomes a flame instead.
437 y = frame - 96;
438 for (i = 0; i != 7; i++) {
439 s32 drop = gParticleStreams_DropPoints[i][1] + y;
440
441 if (drop <= 93)
442 draw(Ram_MapCellBuffer, work->sheet + 0x1c80,
443 gParticleStreams_DropPoints[i][0] + x - 12, drop - 12, 24, 24);
444 else if (drop <= 95)
445 ParticleStreams_SpawnFlame(
446 (gParticleStreams_DropPoints[i][0] + x) << 16, drop << 16, 1);
447 }
448 for (i = 0; i != 32; i++) {
449 struct EffectStep *mote = &work->particles[i];
450
451 // A rising mote shows six 32x32 cells, moving up and against the
452 // stream, then frees its slot.
453 if (mote->variant >= 0) {
454 draw(Ram_MapCellBuffer, work->sheet + (mote->variant << 10),
455 Q_16_16_TO_INT(mote->x) - 16, Q_16_16_TO_INT(mote->y) - 16, 32,
456 32);
457 mote->x -= direction * 0x14000;
458 mote->y -= 0x50000;
459 mote->variant++;
460 if (mote->variant == 6)
461 mote->variant = -1;
462 }
463 }
465 frame++;
466 work->frame++;
467 } while (frame != PARTICLE_STREAMS_RISE_FRAMES);
468 WaitFrames(1);
469 presentation->active = 0;
473 gBgScroll[1].x = savedX;
474 gBgScroll[1].y = savedY;
475 }
477 // The burst, PARTICLE_STREAMS_BURST_FRAMES frames: switch to the blended
478 // half-scale display, load the blast
479 // sheet and seed 32 screen motes, 128 flashes and 512 embers, the flashes
480 // and embers leaving the origin with random velocities.
482 REG_BG2PA = Q_8_8(0.5);
483 REG_BG2X = 0;
484 REG_BG2Y = 0xfffff000;
485 REG_BLDALPHA = BLEND_ALPHA(16, 16);
491 for (i = 0; i != 32; i++) {
492 struct EffectStep *mote = &work->particles[i];
493
494 mote->x = Random16() & 127;
495 mote->y = (Random16() & 127) + 127;
496 }
497 for (i = 0; i != 128; i++) {
498 struct EffectStep *flash = &PARTICLES[i];
499
500 SET_POSITION(flash, 0, 0, 0);
501 SET_VELOCITY(flash, ((Random16() & 255) - 127) << 12,
502 (Random16() & 255) << 11, ((Random16() & 255) - 127) << 12);
503 flash->variant = 0;
504 }
505 for (i = 0; i != 512; i++) {
506 struct EffectStep *ember = &PARTICLE_STREAMS_EMBERS[i];
507
508 SET_POSITION(ember, 0, 0, 0);
509 SET_VELOCITY(ember, ((Random16() & 255) - 128) << 13,
510 (Random16() & 255) << 11, ((Random16() & 255) - 128) << 13);
511 ember->variant = 0;
512 }
514
515 // The burst shakes while the formation keeps climbing and growing. The
516 // background brightens from frame 36; on frame 48 the mode 1 objects are
517 // released and the battle shows the damage.
518 for (frame = 0; frame != PARTICLE_STREAMS_BURST_FRAMES; frame++) {
519 s32 size = (frame + 0x1d0) << 8;
520 struct BattleCamera *camera = gCameraWork;
521 s32 elapsed = frame - 16;
522 struct SpriteScale scale;
523 s32 x;
524 s32 y;
525 s32 grow;
526
527 if (elapsed > 19)
529 if (frame == 0)
531 if (frame == 40)
533 if (frame == 48) {
534 if (mode == 1) {
538 }
540 }
542 for (i = 0; i != 64; i++) {
543 // The first 64 embers, sized by depth and falling under gravity; one
544 // that falls to height 20 restarts there with a new velocity.
545 struct EffectStep *ember = &PARTICLE_STREAMS_EMBERS[i];
546
547 if (ember->y >= 0) {
548 s32 size;
549
550 EffectPosition_ProjectPoint(&ember->x, &point);
551 point.x >>= 1;
552 if (point.depth <= 159)
553 point.depth = 160;
554 if (point.depth > 799)
555 point.depth = 799;
556 size = 9 - (point.depth - 160) / 64;
557 draw(canvas,
558 work->sheet +
559 (gBattleFx_MoteCells[size - 1] + (i & 1) * MOTE_SET_BYTES) +
561 point.x - size / 2, point.y - size, size, size * 2);
562 EffectStep_AdvanceWithGravity3D(ember, 64, -0x2000);
563 if (ember->y <= 0x140000) {
564 ember->x = 0;
565 ember->z = 0;
566 ember->y = 0x140000;
567 SET_VELOCITY(ember, ((Random16() & 63) - 32) << 15,
568 (Random16() & 63) << 13, ((Random16() & 63) - 32) << 15);
569 }
570 }
571 }
572 for (i = 0; i != 64; i++) {
573 struct EffectStep *mote = &work->particles[i];
574 // 64 screen motes rise 8 pixels a frame plus their index's low three
575 // bits, wrapping back to row 128 above the top.
576 u32 rise = i & 7;
577 s32 size = rise + 3;
578
579 draw(canvas,
580 work->sheet +
581 (gBattleFx_MoteCells[size - 1] + (i & 1) * MOTE_SET_BYTES) +
583 mote->x - size / 2, mote->y - size, size, size * 2);
584 mote->y = mote->y - rise - 8;
585 if (mote->y < -10)
586 mote->y = 128;
587 }
588 for (i = 0; i != 64; i++) {
589 // The first 64 flashes, three more released each frame from frame 17:
590 // seven growing cells, two frames each, then a restart at height 20
591 // with a random depth and upward speed.
592 struct EffectStep *flash = &PARTICLES[i];
593
594 if (i / 3 < elapsed && flash->y >= 0) {
595 EffectPosition_ProjectPoint(&flash->x, &point);
596 point.x >>= 1;
597 if ((u32)flash->variant <= 13) {
598 s32 cell = flash->variant / 2;
599
600 draw(canvas, work->sheet + gParticleStreams_FlashCells[cell],
601 point.x - gParticleStreams_FlashSizes[cell] / 2,
602 point.y - gParticleStreams_FlashSizes[cell] / 2,
605 }
606 flash->variant++;
607 if (flash->variant == 14) {
608 flash->y = 0x140000;
609 flash->x = 0;
610 flash->z = ((Random16() & 255) - 127) << 16;
611 SET_VELOCITY(flash, 0, (Random16() & 255) << 11, 0);
612 flash->variant = 0;
613 } else {
615 }
616 }
617 }
618 if (direction == 1)
619 x = frame / 2 + 24;
620 else
621 x = 56 - frame / 2;
622 y = 64 - frame * 2;
623 grow = (frame << 8) + 0x20000;
624 position.groundHeight = 0;
625 position.height = 0xff0000;
626 if (mode == 1) {
627 scale.x = size;
628 scale.y = size;
629 position.x = (x << 16) + 0x600000;
630 position.y = (96 - y) << 16;
631 Object_ApplyProjectedPlacementFar(work->objects[0], &position, &scale, 0);
632 Object_ApplyProjectedPlacementFar(work->objects[1], &position, &scale, 0);
633 } else {
634 scale.x = grow;
635 scale.y = grow;
636 position.x = (x << 16) + 0x600000;
637 position.y = (96 - y) << 16;
638 Object_ApplyProjectedPlacementFar(work->objects[0], &position, &scale, 0);
639 }
640 work->shakeFrames = 1;
641 Camera_ApplyShake(8, 8);
643 }
646 if (mode == 0)
649}
650
651#undef PARTICLE_STREAMS_EMBERS
652#undef PARTICLE_STREAMS_RISE_FRAMES
653#undef PARTICLE_STREAMS_BURST_FRAMES
654#undef PARTICLE_STREAMS_MOTE_CELLS
void * gBattleFxWork[]
struct BattleCamera * gCameraWork
@ COMPOSITE_MAX
BattleEffectDrawRectangle DrawRectangle
s32 BattleFx_BuildBlitter(s32 slot, s32 widthShift, s32 heightShift, s32 flags, u32 mode)
Writes a drawing routine for the canvas into heap slot slot, built from the template BattleFx_Composi...
Definition blitter.c:281
void BattleFx_ProcessPendingGraphicsTransfer(void)
Copies the canvas to VRAM once the effect has finished drawing a frame (transferPending): the 128x128...
Definition canvas.c:103
void BattleFx_EndCanvasLayer(void)
Closes the canvas layer: plays the closing sound, restores BG1's scroll and the projection centre,...
Definition canvas.c:490
void BattleFx_FlushPendingGraphicsTransfer(void)
Copies a full-screen picture to VRAM once the effect has finished drawing a frame: the 0x7800 bytes o...
Definition canvas.c:158
void BattleFx_WipeCanvas(s32 mode, s32 value)
Wipes the whole canvas to one colour with a ragged edge: each row (or column) lags a random 0 to 63 p...
Definition canvas.c:27
void BattleFx_ConfigureEffectDisplay(void)
Puts the battle screen back into the display state every effect starts from and ends with: no blendin...
Definition display.c:16
void BattleFx_AdvanceBg2OnInterval(void)
Slides the affine BG2 in steps: once every scrollInterval frames, writes the work block's reference p...
Definition display.c:56
void Resource_LoadAndDecompress(s32 id, void *dst, s32 skipPalette, s32 copyPalette)
Decompresses a resource whose first 128 bytes may be a palette.
static __inline__ void Dma_Set(const volatile void *source, volatile void *destination, u32 control, volatile u32 *channel)
Starts a DMA transfer: stores the source, destination and control words into channel's registers with...
Definition dma.h:62
void ObjectGroup_UpdateMembers(s32 actorId, s32 palette, s32 animation, s32 timerSlot, s32 timerFrames)
Updates every animation group of one battler's object.
Definition dispatch.c:254
void BattleFx_SetupBlendedDisplay(void)
Shows the BG1 battle background behind a cleared canvas: clears the canvas buffer and the 16 KiB of V...
Definition dispatch.c:217
void BattleFx_SelectLivingTargets(struct BattleEffectArgument *effect)
Shows the battle objects of every unit with HP left on the targets' side: the enemies (units 128 to 1...
Definition dispatch.c:184
What every part of the battle effect object shares: its includes, macros and frame-loop helpers.
#define EFFECT_PRESENT_FRAME(work)
Ends a frame of a canvas effect: marks the canvas ready for the transfer callback,...
#define DMA_FILL_WORDS(n)
DMA control word that fills n words from one fixed source word.
#define EFFECT_SET_TRANSFER(work, mode, value)
Sets how the canvas transfer treats what is left in the canvas after each copy: mode with value (see ...
@ CANVAS_COPY
copy as drawn
@ CANVAS_COPY_AND_CLEAR
copy, then fill the canvas with transferValue
@ CANVAS_COPY_AND_DARKEN
copy, then darken the canvas by transferValue
#define CANVAS_BYTES
The canvas: 128x128 pixels, one byte each, in its heap slot and in VRAM at BG_CHAR_BLOCK(1).
#define EFFECT_CALLBACK_ORDER
The scheduler order of every per-frame effect callback (Scheduler_AddOrUpdateCallback sorts the frame...
#define MOTE_SET_BYTES
The bytes of one set of the ten mote cells: 2 * (1 + 4 + ... + 100).
static void Dma_Stop(volatile u16 *channel)
Stops a DMA channel: clears its repeat and start timing bits, then its enable bit,...
#define EFFECT_SHOW_DAMAGE(hitSound)
Lets the battle show the damage: resumes its paused playback, which plays hitSound (an SE_ id; 0 keep...
#define EFFECT_START_TRANSFER(work, mode, value)
Sets the transfer, then starts copying the canvas to VRAM once a frame.
#define EFFECT_FREE_PARTICLES(i, particles, count)
Marks particles[0] to particles[count - 1] free: a particle whose variant is -1 is not drawn or moved...
#define EFFECT_LOAD_BLITTER(slot, flags, mode)
Builds a blitter for the 128x128 canvas (1 << 7 pixels each way) in work slot slot: BattleFx_BuildBli...
#define EFFECT_VIEW_FROM_CAMERA(camera)
Starts a frame's 3D projection from the battle camera: resets the transform, then looks from camera->...
#define EFFECT_BEGIN_NARROW_CANVAS(bgControl)
Opens the canvas layer at the canvas's own width, one texel per pixel, where BattleFx_BeginCanvasLaye...
static s32 * EffectPosition_Coordinates(struct EffectPosition *position)
Returns the position's three coordinates as an array.
Definition effect_step.h:68
s16 gParticleStreams_DropPoints[][2]
Where the seven drops fall, in pixels.
u16 gParticleStreams_FlashCells[]
s16 gParticleStreams_OrbitPoints[][3]
The seven sparks that orbit the rising formation.
u16 gBattleFx_MoteCells[]
Mote cells: particle sheets hold ten, cell n (from 0) n + 1 pixels wide and twice that tall.
u16 gParticleStreams_FlashSizes[]
void BattleFx_SpawnObjects(s32 entryCount, s32 source, u32 priority)
Creates the effect's animation objects in gBattleFxWork's objects.
Definition eruption.c:220
struct BattleObj * GetBattleObjectSlotFar(s32 objectId)
Far call to BattleObjGet.
void BattleActor_CommitPlacementFar(void)
Far call to BattleObjPut.
s32 AnimationObjects_SelectAnimationFar(struct AnimationObject *state, s32 flags)
struct AnimationObject * ResourceObject_CreateFar(s32 id)
void Object_ApplyProjectedPlacementFar(struct AnimationObject *sprite, const struct SpritePlacement *position, const struct SpriteScale *scale, s32 facing)
Far call to Render_ApplyProjectedPlacement.
void ResourceObject_ReleaseFar(struct AnimationObject *sprite)
void AudioCommand_PlayFar(s32 id)
s32 Trig_Cos(s32 angle)
s32 Trig_Sin(s32 angle)
void WaitFrames(s32 frames)
The game's frame loop: runs frames frames and returns.
Definition frame.c:97
#define SPRITE_SECOND_PART
Definition resource.h:14
void Camera_ApplyShake(s32 rangeX, u32 rangeY)
Shakes the battle view while gBattleFxWork's shakeFrames lasts, moving BG1 and the projection centre ...
Definition hail.c:364
@ HEAP_SLOT_BATTLE_EFFECT
Definition heap_state.h:42
@ HEAP_SLOT_BATTLE_BACKGROUND
Definition heap_state.h:45
@ HEAP_SLOT_BLITTER
Definition heap_state.h:46
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
#define Q_8_8(n)
The BG2/BG3 affine matrix entries are signed 8.8 fixed point: texels stepped per screen pixel.
Definition io_reg.h:59
#define BGCNT_CHAR_BASE(block)
Definition io_reg.h:25
#define BGCNT_256_COLORS
Definition io_reg.h:27
#define BGCNT_PRIORITY(n)
Definition io_reg.h:24
#define DMA_HBLANK_HALFWORD_PER_LINE
Definition io_reg.h:228
#define RGB(r, g, b)
A 15-bit colour from its red, green and blue levels (0 to 31 each), as the palette stores it: blue in...
Definition io_reg.h:164
#define BG_CHAR_BLOCK(n)
Definition io_reg.h:166
#define REG_DMA0
Definition io_reg.h:151
@ KEY_B
Definition io_reg.h:244
@ KEY_A
Definition io_reg.h:243
#define REG_BG2X
Definition io_reg.h:65
#define PLTT_BACKDROP
Definition io_reg.h:155
#define BLDCNT_EFFECT_BLEND
weighted by REG_BLDALPHA
Definition io_reg.h:131
#define BLDCNT_TGT2_ALL
Definition io_reg.h:140
#define REG_DMA3
Definition io_reg.h:153
#define REG_BG2Y
Definition io_reg.h:66
#define BLEND_ALPHA(top, bottom)
A REG_BLDALPHA value: top and bottom are the two targets' weights, out of 16.
Definition io_reg.h:145
#define BGCNT_SCREEN_BASE(block)
Definition io_reg.h:28
#define BLDCNT_TGT1_BG1
Definition io_reg.h:124
#define REG_BG2CNT
Definition io_reg.h:21
#define REG_BLDALPHA
Definition io_reg.h:142
#define BG_PLTT
Definition io_reg.h:157
#define REG_BG2PA
Definition io_reg.h:61
#define REG_BLDCNT
Definition io_reg.h:119
#define REG_BG1CNT
Definition io_reg.h:20
#define BG_PLTT_COLOR(palette, color)
Definition io_reg.h:158
#define BGCNT_WRAP
Affine backgrounds only: wrap around instead of showing the backdrop.
Definition io_reg.h:30
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
#define SET_VELOCITY(p, vx, vy, vz)
Definition macros.h:18
#define SET_POSITION(p, px, py, pz)
Sets the position or the velocity of a particle, a piece of debris or an object in one statement.
Definition macros.h:16
#define SET_VECTOR(v, x, y, z)
Sets the x, y and z of a three-part vector: a position about to be projected, a per-frame step,...
Definition macros.h:12
#define CLAMP(v, low, high)
Keeps v within low to high, the low bound tested first.
Definition macros.h:23
struct BgScroll gBgScroll[]
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
void Runtime_ReleaseHeapBlock(s32 slot)
#define PARTICLE_STREAMS_EMBERS
The burst's embers, 512 in PARTICLES after its 128 flashes.
#define PARTICLE_STREAMS_BURST_FRAMES
frames of the burst
void BattleFx_RunMeteor(struct BattleEffectArgument *effect)
A formation rises out of a dissolving starfield and bursts into embers and flashes: the particle stre...
void BattleFx_RunOuterSpace(struct BattleEffectArgument *effect)
The user leaps up, and two objects rise out of a dissolving starfield and burst into embers and flash...
#define PARTICLE_STREAMS_RISE_FRAMES
frames, at most, of the rise
#define PARTICLE_STREAMS_MOTE_CELLS
The mote pictures in the sheet: two sets, MOTE_SET_BYTES apart.
void BattleFx_ArmPaletteHBlankDma(void)
Arms DMA 0 to write one halfword of the table at work->sheet + 0x1f80 into background colour 0 at eac...
void BattleFx_RunParticleStreams(struct BattleEffectArgument *effect, s32 mode)
The stream runs in two halves.
void Palette_BrightenBgEntries(s32 blueStep, s32 greenStep, s32 redStep)
Adds per-channel steps to background colours 1 to 63, capped at 31.
void EffectStep_AdvanceWithGravity3D(struct EffectStep *step, s32 damping, s32 gravity)
Moves a particle one frame in three dimensions: adds its velocity, then gravity to its vertical speed...
Definition positions.c:29
s32 EffectPosition_ProjectPoint(const void *point, struct EffectPosition *position)
Projects a point in the current transform onto the screen, 16 pixels higher, and returns the projecti...
Definition positions.c:64
struct Projection gProjection
#define Ram_MapCellBuffer
Definition ram_buffer.h:10
char ResourceId_BlastSheet
char ResourceId_LightningBoltSheet
char ResourceId_FlameSheetB
s32 Scheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 order)
Schedules callback with order, or gives a task already running it the new order, and re-sorts the tab...
Definition scheduler.c:102
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define SE_156
Definition songs.h:151
#define SE_141
Definition songs.h:134
#define SE_HEAVY_IMPACT
Definition songs.h:127
#define SE_145
Definition songs.h:138
void * gWorkSlot[]
An animated sprite: its image and shadow, scale, rotation, size and up to four animation layers.
Definition animspr.h:108
struct AnimationSpritePart image
Definition animspr.h:109
u16 priority
2 when created
Definition animspr.h:100
The battle camera: its eye, the focus it turns about, and its pitch, yaw and distance.
The command shared by an effect's caller, dispatcher and handlers.
s32 actor
the user's unit id
s32 side
1 when the targets are the party, 0 for enemies
The running battle effect's work: its canvas image, 64 particles, the display registers it stages and...
s32 frame
frame counter some effects keep, from 0
s32 shakeFrames
shake frames left; Camera_ApplyShake counts down
s32 bg2x
BG2's reference point, written to BG2X and BG2Y by Display_ApplyBg2Reference and BattleFx_AdvanceBg2O...
struct AnimationObject * objects[16]
the effect's animation objects
s32 transferMode
How the canvas transfer callbacks treat the canvas after each copy (enum CanvasTransferMode in effect...
s32 scrollStepY
added to BG1 or BG2 y at each step
s32 scrollTimer
frames since the last interval scroll step
struct BattleEffectArgument * effect
the command being run
s32 scrollStepX
added to BG1 or BG2 x at each step
s32 scrollInterval
frames between interval scroll steps
struct EffectStep particles[64]
free while variant is -1
struct MotionObject * object
NULL once released.
The battle background's work slot as the camera reads it: the yaw the camera eases toward and the fra...
s32 active
BattleBackgroundView's busy, at the same offset.
u16 y
pixels
Definition map_scroll.h:65
A point projected onto the screen, with its depth.
Definition effect_step.h:46
s32 y
screen pixels
Definition effect_step.h:59
s32 depth
projected depth, larger further away
Definition effect_step.h:60
s32 x
screen pixels
Definition effect_step.h:58
A moving point of an effect: its position, its velocity and a value each effect uses its own way (a s...
Definition effect_step.h:13
s32 velocityX
16.16 fixed-point pixels per frame
Definition effect_step.h:28
s32 z
16.16 fixed-point pixels
Definition effect_step.h:26
s32 variant
each effect's own: a size, a countdown, -1 for idle
Definition effect_step.h:31
s32 x
16.16 fixed-point pixels
Definition effect_step.h:24
s32 y
16.16 fixed-point pixels
Definition effect_step.h:25
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
s32 velocityY
16.16 fixed-point pixels per frame
Definition motobj.h:32
s32 centerY
screen pixels
Definition project.h:17
A sprite's screen position and its two vertical offsets, in 16.16 pixels.
s32 x
screen x of the sprite's centre
s32 y
screen y at the ground; sets the depth slot
s32 groundHeight
how far the shadow is raised above y
s32 height
how far the image is raised above y
Horizontal and vertical sprite scale; 0x10000 is the original size.
void * Resource_GetTableEntry(s32 index)
Returns the ROM address of resource index from the resource directory.
Definition system.c:150
void SceneTransform_ApplyYaw(s32 angle)
Rotates gTransform about the Y axis by angle.
Definition transform.c:113
void SceneTransform_ApplyPosition(const s32 *position)
Translates gTransform by position (x, y, z in 16.16).
Definition transform.c:145
void Render_ResetTransformState(void)
Allocates the one-level save area (heap slot HEAP_SLOT_TRANSFORM_STACK), clears gTransformStackDepth ...
Definition transform.c:19
void SceneTransform_ApplyRoll(s32 angle)
Rotates gTransform about the Z axis by angle.
Definition transform.c:129
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
#define EFFECT_CLIP_BOUNDS
Clips overflow on all four sides.
Definition effect.h:224
#define Q_16_16_TO_INT(v)
Definition effect.h:231
#define PARTICLES
The map cell buffer (gMapCellBuffer), which the effects borrow, has two views here: Ram_MapCellBuffer...
Definition effect.h:221