9#define THOR_PARTICLES ((struct EffectStep *)(Ram_MapCellBuffer + 0xc58))
12#define THOR_SPRITES_CELLS 0x1800
15#define THOR_MOTE_CELLS 0x6000
17#define THOR_PARTICLE_COUNT 910
18#define THOR_DIMMED_DOTS 10000
19#define THOR_DIMMED_DOT_BYTES MOTE_SET_BYTES
20#define THOR_DUSK_FRAMES 170
21#define THOR_LIGHTNING_FRAMES 192
23#define THOR_BOLT_SIZE 72
24#define THOR_BOLT_BYTES (THOR_BOLT_SIZE * THOR_BOLT_SIZE)
31#define THOR_LAUNCH_SPARKS(spark, index, px, py, angleExpr, max) \
34 for (index = 0, spark = THOR_PARTICLES; index != THOR_PARTICLE_COUNT; \
36 if (spark->variant == 0) { \
41 speed &= Random16(); \
46 spark->velocityX = (Trig_Sin(angle) * speed) >> 7; \
47 spark->velocityY = -((Trig_Cos(angle) * speed) << 1) >> 7; \
48 spark->variant = (Random16() & 7) + 32; \
49 if (++spawned == (max)) { \
69 static s16 points[6][2] = {
70 {8, 135}, {184, 135}, {128, 135}, {96, 32}, {96, 32}, {64, 135},
114 for (i = 0, offset = 0; i != 8; i++) {
159 for (i = 0; i != 16; i++) {
161 ramp[31 - i] = i * 8 + 3;
165 if (ramp[31 - i] > 63) {
206 s32 sinkFrame = frame - 128;
207 if (sinkFrame > 22) {
210 SET_VECTOR(position, 0, -sinkFrame << 17, 0x2000000);
211 size = (sinkFrame >> 2) + 2;
221 SET_VECTOR(scale, frame * 0x1800 - 0xd9400, scale[0], scale[0]);
224 SET_VECTOR(scale, 0x10000 - sinkFrame * 3 * 0x400, scale[0], scale[0]);
239 for (i = 0; i != 6; i++) {
240 SET_VECTOR(point, (points[i][0] - 96) << 16, 0,
241 (points[i][1] - 96) << 16);
243 screen[i].
x = (screen[i].
x >> 17) + 64;
244 screen[i].
y = (screen[i].
y >> 16) + 60;
246 for (i = 0; i != 3; i++) {
247 dotCount = count * 2 - i * 48 - 256;
252 for (j = 0; j != dotCount; j++) {
253 s32 x = screen[i * 2].
x +
256 s32 y = screen[i * 2].
y +
290 if (dotCount > 128) {
293 for (i = 0; i != dotCount; i++) {
294 s32 dotSize = size + 1;
296 point[2] = -(
Trig_Cos(i << 9) * 96);
298 screen[0].
x = (screen[0].
x >> 17) + 64;
299 screen[0].
y = (screen[0].
y >> 16) + 60;
305 screen[0].
x - dotSize / 2, screen[0].
y - dotSize, dotSize,
315 if ((
u32)(frame - 151) <= 16) {
317 s32 beamHeight = (frame - 151) * 20 + 44;
324 for (i = 1; i != 10; i++) {
325 if (inset + i <= 15) {
326 blit[0](canvas, &ramp[inset + i], inset + 48 + i, 16 - i,
327 32 - inset * 2 - i * 2, 1);
330 for (i = 0; i != beamHeight; i++) {
339 asm(
"" :
"+r"(fullWidth));
340 blit[0](canvas, ramp + inset, inset + 48, i + 16, fullWidth - inset * 2,
346 canvas, work->sheet, 32, (frame - 151) * 20 - 12, 32, 96);
351 canvas, work->sheet, 64, (frame - 151) * 20 - 12, 32, 96);
385 formationX = 0x500000;
386 formationY = 0x400000;
395 for (i = 0; i != 16; i++) {
411 stormFrame = frame - 80;
412 if ((
u32)stormFrame <= 59 && !(frame & 7)) {
421 for (j = 0; j != 1; j++) {
422 s32 start = j * 128 + 8;
423 if (frame >= start && frame < j * 128 + 17) {
424 if (frame >= j * 128 + 9 && frame < j * 128 + 12) {
425 blit[0](canvas, work->sheet, 36, 0, 48, pillarY);
427 if (frame >= j * 128 + 12 && frame < start + 8) {
428 blit[0](canvas, work->sheet + (48 * 112), 36, 0, 48, 112);
430 if (frame == start + 2) {
432 (
Random16() & 0x7fff) - 0x4000, 512);
450 if ((
u32)stormFrame <= 63) {
454 for (i = 0; i != 6; i++) {
455 if (frame == i * 8 + 80) {
460 if (frame >= i * 2 + 80) {
461 if (frame < i * 2 + 82) {
471 if (frame == i * 2 + 80) {
490 moteX = (
Trig_Sin(angle) * (radius + 8)) >> 16;
491 mirrorX = moteX + 72;
492 moteY = 32 - ((
Trig_Cos(angle) * (radius + 8)) >> 16);
527 spark->
x = mirrorX << 16;
528 spark->
y = moteY << 16;
555 if (spark->
y > 0x780000) {
557 }
else if ((
u32)spark->
x <= 0x7effff && spark->
y >= 0) {
558 s32 x = spark->
x >> 16;
559 s32 y = spark->
y >> 16;
572 formationSpeedX = 0x40000;
573 formationSpeedY = -0x4000;
576 formationX += formationSpeedX;
577 formationY += formationSpeedY;
578 formationSpeedX = formationSpeedX * 60 / 64;
579 formationSpeedY = formationSpeedY * 60 / 64;
586 if ((
u32)(frame - 16) <= 127) {
587 s32 formationScreenX;
588 for (i = 0, formationScreenX = formationX >> 17; i != 3; i++) {
591 s32 x = (((
Trig_Sin(angle) * 8)) >> 16) + formationScreenX -
616 for (i = 0; i != 9; i++) {
623#undef THOR_MOTE_CELLS
624#undef THOR_PARTICLE_COUNT
625#undef THOR_DIMMED_DOTS
626#undef THOR_DIMMED_DOT_BYTES
627#undef THOR_DUSK_FRAMES
628#undef THOR_LIGHTNING_FRAMES
631#undef THOR_BOLT_BYTES
632#undef THOR_LAUNCH_SPARKS
633#undef THOR_SPRITES_CELLS
@ SPRITE_COLOR_WHITE
solid colour 15, white
@ POSE_DAMAGE
taking damage
BattleEffectDrawRectangle DrawRectangle
#define EFFECT_FOR_EACH_TARGET(i, effect)
Loops i over the effect's targets, effect->actors[0] to effect->actors[effect->count - 1]: the loops ...
void BattleFx_ProcessPendingGraphicsTransfer(void)
Copies the canvas to VRAM once the effect has finished drawing a frame (transferPending): the 128x128...
void BattleFx_EndCanvasLayer(void)
Closes the canvas layer: plays the closing sound, restores BG1's scroll and the projection centre,...
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...
void BattleFx_ConfigureEffectDisplay(void)
Puts the battle screen back into the display state every effect starts from and ends with: no blendin...
void BattleFx_AdvanceScrollOnInterval(void)
Scrolls BG1 by (scrollStepX, scrollStepY) once every scrollInterval frames.
void Resource_LoadAndDecompress(s32 id, void *dst, s32 skipPalette, s32 copyPalette)
Decompresses a resource whose first 128 bytes may be a palette.
void ObjectGroup_UpdateMembers(s32 actorId, s32 palette, s32 animation, s32 timerSlot, s32 timerFrames)
Updates every animation group of one battler's object.
void BattleFx_SetupBlendedDisplay(void)
Shows the BG1 battle background behind a cleared canvas: clears the canvas buffer and the 16 KiB of V...
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...
What every part of the battle effect object shares: its includes, macros and frame-loop helpers.
#define EFFECT_SHOW_WIDE_CANVAS(top)
Shows the canvas: the effect display mode, BG2 stretched to twice its width (the 128-pixel canvas sho...
#define EFFECT_DRAW_MOTE(draw, canvas, sheet, x, y, size)
Particle sheets hold ten mote cells, 1x2 to 10x20 pixels.
#define EFFECT_PRESENT_FRAME(work)
Ends a frame of a canvas effect: marks the canvas ready for the transfer callback,...
#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_FADE
copy, keeping 50% or 75% (transferValue) of each pixel in the canvas for the next frame
#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 EFFECT_SHOW_DAMAGE(hitSound)
Lets the battle show the damage: resumes its paused playback, which plays hitSound (an SE_ id; 0 keep...
#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_CAP_LEVEL(level, cap)
Caps a colour level at cap, and at 0 from below.
#define EFFECT_END_FRAME(work)
The usual end of an effect frame: counts down the targets' flash timers (ObjectGroup_TickMemberTimers...
#define EFFECT_BEGIN_NARROW_CANVAS(bgControl)
Opens the canvas layer at the canvas's own width, one texel per pixel, where BattleFx_BeginCanvasLaye...
u8 gBattleFx_GlintCellHeights[]
u16 gBattleFx_MoteCells[]
Mote cells: particle sheets hold ten, cell n (from 0) n + 1 pixels wide and twice that tall.
u16 gBattleFx_GlintCells[]
u8 gThor_TargetPalettes[]
The colours a target flashes when a bolt strikes it, chosen at random: white, black,...
u8 gBattleFx_GlintCellWidths[]
u8 gThor_SmokeFlips[]
Flip flags for the smoke puffs, chosen at random.
void BattleFx_SpawnObjects(s32 entryCount, s32 source, u32 priority)
Creates the effect's animation objects in gBattleFxWork's objects.
void BattleMotion_ApplyVariantMotionFar(s32 id, s32 variant)
void BattleBackground_LoadFar(s32 mode, s32 resource, s32 level)
void ResourceObject_ReleaseFar(struct AnimationObject *sprite)
void AudioCommand_PlayFar(s32 id)
void Camera_ApplyShake(s32 rangeX, u32 rangeY)
Shakes the battle view while gBattleFxWork's shakeFrames lasts, moving BG1 and the projection centre ...
@ HEAP_SLOT_BATTLE_EFFECT
@ HEAP_SLOT_BLITTER_ALTERNATE
@ HEAP_SLOT_BATTLE_BACKGROUND
@ HEAP_SLOT_BATTLE_CANVAS
void BattleFx_RunImpactBurst(s32 formation, s32 x, s32 y)
Opens an impact flash and scatters sparks and fragments, keeping the effect's objects in formation fo...
void BattleFx_PlaceFormationObjects(s32 formation, s32 x, s32 z)
Arranges work->objects in a formation; x and z are its origin in 16.16 pixels.
#define Q_8_8(n)
The BG2/BG3 affine matrix entries are signed 8.8 fixed point: texels stepped per screen pixel.
#define BGCNT_CHAR_BASE(block)
#define BGCNT_PRIORITY(n)
#define BLEND_ALPHA(top, bottom)
A REG_BLDALPHA value: top and bottom are the two targets' weights, out of 16.
#define BGCNT_SCREEN_BASE(block)
#define BGCNT_WRAP
Affine backgrounds only: wrap around instead of showing the backdrop.
static s32 Iwram_RatioMulQ14(s32 divisor, s32 value)
All calls go through this layer.
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
static s32 Iwram_FillWords(void *destination, s32 size, u32 value)
#define Iwram_MulQ16(left, right)
volatile u32 gKeysRepeat
Pressed keys, repeating while held: after 19 frames, then every 6.
#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,...
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
void Runtime_ReleaseHeapBlock(s32 slot)
void EffectStep_AdvanceWithGravity2D(struct EffectStep *step, s32 damping, s32 gravity)
Moves a particle one frame on the screen: adds its velocity, then gravity to its vertical speed,...
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...
void Graphics_UpdatePhasePalette(s32 frame, s32 redPhase, s32 greenPhase, s32 bluePhase)
Rebuilds the background palette's first ramp as a grey ramp whose red, green and blue each sway with ...
struct Projection gProjection
#define Ram_MapCellBuffer
char ResourceId_TornadoSheet
char ResourceId_ParticleSpritesB
char ResourceId_CrystalSheet
char ResourceId_ParticleSpritesC
char ResourceId_LightFanSheet
char ResourceId_VioletLightningSheetB
char ResourceId_DuskCloudsBackdrop
char ResourceId_VioletMoteSheet
char ResourceId_ParticleSpritesA
char ResourceId_LightningPillarSheet
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...
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
The battle background's work slot as the background code reads it: its display mode (2 draws it as an...
s32 busy
while set, BattleCamera_SetRange leaves BG1's scroll
The command shared by an effect's caller, dispatcher and handlers.
s16 actors[8]
the targets' unit ids, count of them
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
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
A point projected onto the screen, with its depth.
A moving point of an effect: its position, its velocity and a value each effect uses its own way (a s...
s32 velocityX
16.16 fixed-point pixels per frame
s32 variant
each effect's own: a size, a countdown, -1 for idle
s32 x
16.16 fixed-point pixels
s32 y
16.16 fixed-point pixels
s32 velocityY
16.16 fixed-point pixels per frame
void * Resource_GetTableEntry(s32 index)
Returns the ROM address of resource index from the resource directory.
#define THOR_DIMMED_DOTS
the darker copies of the dot pictures
#define THOR_PARTICLE_COUNT
particles in THOR_PARTICLES
#define THOR_LAUNCH_SPARKS(spark, index, px, py, angleExpr, max)
Launches up to max sparks from (px, py), 16.16, into the free slots (variant 0) of THOR_PARTICLES,...
void BattleFx_RunThor(struct BattleEffectArgument *effect)
The scene plays in two parts on the effect canvas.
#define THOR_LIGHTNING_FRAMES
frames of the lightning part
#define THOR_BOLTS
violet bolts after the pillar
#define THOR_MOTE_CELLS
The violet mote in the second part's sheet.
#define THOR_DUSK_FRAMES
frames, at most, of the dusk part
#define THOR_BOLT_SIZE
each of the three bolt pictures is 72x72
#define THOR_DIMMED_DOT_BYTES
bytes in each darker copy
#define THOR_PARTICLES
910 sparks from Ram_MapCellBuffer + 0xc58; the smoke pictures come before them.
#define THOR_SPRITES_CELLS
The particle sprites, after the light fan pictures.
#define EFFECT_BLITTERS
The work slots read as blitters: EFFECT_BLITTERS[HEAP_SLOT_BLITTER] and EFFECT_BLITTERS[HEAP_SLOT_BLI...
#define EFFECT_CLIP_BOUNDS
Clips overflow on all four sides.
DrawRectangle BlitterPair[2]
A blitter pair: [0] built in HEAP_SLOT_BLITTER and [1] in HEAP_SLOT_BLITTER_ALTERNATE (BattleFx_Fetch...