Alchemy
Loading...
Searching...
No Matches

vortices.c

Go to the documentation of this file.
1/// @file
2/// Froth and Whirlwind.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7#define FROTH_MOTE_CELL 0xc00 ///< the mote picture in the sheet
8#define FROTH_FIRST_TARGET 32 ///< the first target seat in work->particles
9/// The motes set up in work->particles, before the target seats: no row of
10/// gVortices_Counts may ask for more.
11#define FROTH_MOTES 30
12
13/// The tornado pictures follow the six glint cells (gBattleFx_GlintCells) in
14/// the sheet: 40x32 sections, the top and bottom ones' three frames
15/// interleaved, then the middle one's.
16#define WHIRLWIND_TORNADO_CELLS 0xc56
17#define WHIRLWIND_SECTION_BYTES (40 * 32)
18
19/// Motes fly out of the top of the user, hang, and from 48 frames after each
20/// appears home in on the targets in turn; each that reaches the ground strikes
21/// in a burst, flashing and knocking back its target, while the camera swings
22/// round over frames 17 to 63.
23///
24/// Abilities: Froth, Froth Sphere, Froth Spiral (kind 10).
25///
26/// effect->variant picks the volley from gVortices_Counts (motes and frames)
27/// and how hard the screen shakes.
28///
29/// work->particles 0 to 29 are the motes, battle positions in 16.16 until a
30/// mote strikes and then its burst's canvas pixels; from 32, one seat for
31/// each target. The first 30 bytes of Ram_MapCellBuffer mark the motes that
32/// have struck. Loads the vortex palette into the first 64 background
33/// colours, sets REG_BLDALPHA and work->shakeFrames, and turns the camera
34/// through Camera_ApplyPhasedDelta (work->cameraDelta and cameraPhase),
35/// which it removes before it returns.
37 struct EffectPosition screenPosition;
38 struct BattleEffectWork *work;
39 void *canvas;
40 BlitterPair draw;
41 u8 *palette;
42 struct MotionObject *source;
43 struct MotionObject *object;
44 struct EffectStep *point;
45 struct EffectStep *seat;
46 struct EffectStep *target;
47 struct BattleCamera *camera;
48 s32 frame;
49 s32 y;
50 s32 i;
51 s8 *flags;
52
53 // Nonzero once a mote has struck.
54 flags = (s8 *)Ram_MapCellBuffer;
57 work->effect = effect;
60 Iwram_CopyWords((void *)BG_PLTT, palette, 128);
61 palette += 128;
62 Resource_DecodeType01(palette, work->sheet);
67 REG_BLDALPHA = BLEND_ALPHA(15, 15);
69 source = GetBattleObjectSlotFar(work->effect->actor)->object;
70 y = source->y + BattleUnit_GetEffectHeightFar(work->effect->actor);
71 // The motes start at the top of the user, flying out up to 4 pixels a
72 // frame across and up to 2 up; variant -1 means no burst yet.
73 for (i = 0; i != FROTH_MOTES; i++) {
74 point = &work->particles[i];
75 SET_POSITION(point, source->x, y, source->z);
76 SET_VELOCITY(point, ((s32)((Random16() & 255) - 127) << 16) >> 5,
77 ((s32)((Random16() & 127) - 16) << 16) >> 6,
78 ((s32)((Random16() & 255) - 127) << 16) >> 5);
79 point->variant = -1;
80 flags[i] = 0;
81 }
82 // Where each target stands, on the ground.
84 seat = &work->particles[FROTH_FIRST_TARGET + i];
85 object = GetBattleObjectSlotFar(work->effect->actors[i])->object;
86 SET_POSITION(seat, object->x, 0, object->z);
87 }
88 work->cameraDelta = 0;
89 work->cameraPhase = 0;
91 // Trails keep 75% of each pixel a frame.
94
95 for (frame = 0;
97 frame++) {
98 // The camera swings 0x180 of yaw a frame over frames 17 to 63.
100 if (frame >= 17 && frame < 64)
101 work->cameraDelta = 0x180;
102 else
103 work->cameraDelta = 0;
104 // 16 frames before the end the battle shows the damage, with sound 132
105 // on each hit.
106 if (frame == gVortices_Counts[work->effect->variant][FROTH_FRAMES] - 16)
109 for (i = 0; i != gVortices_Counts[work->effect->variant][FROTH_MOTE_COUNT];
110 i++) {
111 point = &work->particles[i];
112 if (frame > i * 2 && flags[i] == 0) {
113 EffectPosition_ProjectPoint(point, &screenPosition);
114 screenPosition.x >>= 1;
115 CLAMP(screenPosition.depth, 160, 0x31f);
116 draw[0](canvas, work->sheet + FROTH_MOTE_CELL, screenPosition.x - 6,
117 screenPosition.y - 12, 12, 24);
118 point->x += point->velocityX;
119 point->y += point->velocityY;
120 point->z += point->velocityZ;
121 }
122 // Mote i appears on frame 2i; 48 frames later it starts to home in on
123 // its target, damped until frame 2i + 85, and strikes on reaching
124 // the ground.
125 // Mote i goes to target i modulo the target count; seats are on the
126 // ground (y 0), so a mote strikes when it falls below it.
127 if (frame > i * 2 + 48 && flags[i] == 0) {
128 target = &work->particles[FROTH_FIRST_TARGET + i % work->effect->count];
129 point->velocityX += (target->x - point->x) >> 9;
130 point->velocityY += (target->y - point->y) >> 9;
131 point->velocityZ += (target->z - point->z) >> 9;
132 if (frame < i * 2 + 85) {
133 SET_VELOCITY(point, point->velocityX * 60 / 64,
134 point->velocityY * 60 / 64, point->velocityZ * 60 / 64);
135 }
136 // On the ground it strikes: its burst starts where it was last
137 // drawn, a little up or down at random, and the target flashes and
138 // recoils.
139 if (point->y < 0) {
140 flags[i] = 1;
141 point->variant = 0;
142 point->x = screenPosition.x;
143 point->y = screenPosition.y + (Random16() & 31) - 16;
145 work->effect->actors[i % work->effect->count], SPRITE_COLOR_WHITE,
146 POSE_DAMAGE, i % work->effect->count, 4);
148 work->effect->actors[i % work->effect->count], 0);
149 work->shakeFrames = 4;
151 }
152 }
153 // The burst where a mote struck: two mirrored halves cycling three
154 // images, for 16 frames.
155 if (point->variant >= 0 && point->variant < 16) {
156 draw[0](canvas, work->sheet + ((point->variant / 2) % 3 << 10),
157 point->x - 16, point->y - 56, 16, 64);
158 draw[1](canvas, work->sheet + ((point->variant / 2) % 3 << 10),
159 point->x, point->y - 56, 16, 64);
160 point->variant++;
161 }
162 }
163 Camera_ApplyShake(work->effect->variant * 2 + 2,
164 work->effect->variant * 2 + 2);
165 // Tell Camera_ApplyPhasedDelta a frame has ended.
166 if (work->cameraPhase == 0)
167 work->cameraPhase = 1;
168 EFFECT_END_FRAME(work);
169 }
170
173}
174
175/// Tornadoes sweep across the targets for 80 frames, sparkling with glints; the
176/// canvas flashes and the targets reel seven times, 8 frames apart, from frame
177/// 16, and the battle shows the damage on frame 32.
178///
179/// Abilities: Whirlwind, Tornado, Tempest, Gale, Typhoon, Hurricane (kind 20).
180///
181/// effect->variant picks the shape from gVortices_Shapes: how many tornadoes,
182/// how far they sway and how hard the screen shakes.
183///
184/// work->particles 0 to 15 are the glints, four for each tornado (so at most
185/// four tornadoes), offsets in pixels from its top left. Loads the tornado
186/// palette into the first 64 background colours, fades the canvas in and out
187/// through REG_BLDALPHA and keeps work->shakeFrames at 1 so the screen shakes
188/// every frame.
190 BlitterPair draw;
191 void **slots;
192 void **cursor;
193 struct BattleEffectWork *work;
194 void *canvas;
195 s32 wave;
196 u8 *palette;
197 struct EffectStep *point;
198 s32 frame;
199 s32 x;
200 s32 y;
201 s32 segment;
202 s32 cell;
203 s32 i;
204 s32 j;
205
207 cursor = slots;
208 EFFECT_GET_WORK_AND_CANVAS(cursor, work, canvas);
209 work->effect = effect;
211 REG_BLDALPHA = BLEND_ALPHA(16, 16);
213 Iwram_CopyWords((void *)BG_PLTT, palette, 128);
214 palette += 128;
215 Resource_DecodeType01(palette, work->sheet);
221
222 // The glints: each waits up to 15 frames, then plays at a random spot on
223 // its tornado.
224 for (j = 0; j != 16; j++) {
225 point = &work->particles[j];
226 point->x = Random16() & 31;
227 point->y = (Random16() & 63) + 16;
228 point->variant = -(Random16() & 15);
229 }
230 // Trails keep half a frame.
232 REG_BLDALPHA = BLEND_ALPHA(0, 16); // invisible to start with
233 WaitFrames(1);
235
236 for (frame = 0; frame != 80; frame++) {
237 wave = (Trig_Sin(frame << 10) * 16);
238 if (frame == 32)
240 // Seven flashes of the canvas, 8 frames apart: it is filled with level 8.
241 for (i = 0; i != 7; i++) {
242 if (frame == i * 8 + 16)
243 Iwram_FillWords(canvas, CANVAS_BYTES, 0x08080808);
244 }
245 // The sweep sways 16 pixels each way about a point 32 pixels right of
246 // the canvas's x 40 when the targets are the party, left otherwise.
247 if (work->effect->side == 1)
248 wave += 0x200000;
249 else
250 wave -= 0x200000;
251 // Fade in over 16 frames and out over the last 16.
252 if (frame <= 16)
253 REG_BLDALPHA = BLEND_ALPHA(frame, 16);
254 if (frame > 63)
255 REG_BLDALPHA = BLEND_ALPHA(0x4f - frame, 16);
256 // Each tornado: three sections stacked, swaying about the sweep, a
257 // quarter turn apart, with four glints.
258 for (i = 0;
260 i++) {
262 Trig_Sin((frame << 11) + i * 0x4000) +
263 wave) >>
264 16) +
265 40;
266 y = (Trig_Cos((frame << 11) + i * 0x4000) * 2) >> 16;
267 segment = (frame / 2) % 3;
268 draw[0](canvas,
269 work->sheet + segment * (2 * WHIRLWIND_SECTION_BYTES) +
271 x, y + 16, 40, 32);
272 draw[0](canvas,
273 work->sheet + segment * WHIRLWIND_SECTION_BYTES +
275 x, y + 48, 40, 32);
276 draw[0](canvas,
277 work->sheet + segment * (2 * WHIRLWIND_SECTION_BYTES) +
279 x, y + 80, 40, 32);
280 for (j = 0; j != 4; j++) {
281 point = &work->particles[i * 4 + j];
282 // A glint plays three cells, two frames each: glints 0 and 1 the
283 // first three, glints 2 and 3 the last three; 1 and 3 are mirrored.
284 if (point->variant >= 0) {
285 cell = point->variant / 2 + (j / 2) * 3;
286 draw[j & 1](canvas, work->sheet + gBattleFx_GlintCells[cell],
287 point->x + x, point->y + y,
290 }
291 point->variant++;
292 if (point->variant == 6) {
293 point->x = Random16() & 31;
294 point->y = (Random16() & 63) + 16;
295 point->variant = 0;
296 }
297 }
298 }
299 // Target j reels 3j frames after each flash.
301 for (i = 0; i != 7; i++) {
302 if (frame == i * 8 + j * 3 + 16) {
304 POSE_DAMAGE, j, 4);
306 }
307 }
308 }
309 work->shakeFrames = 1;
312 2);
313 EFFECT_END_FRAME(work);
314 }
315
319}
320
321#undef FROTH_MOTE_CELL
322#undef FROTH_FIRST_TARGET
323#undef FROTH_MOTES
324#undef WHIRLWIND_TORNADO_CELLS
325#undef WHIRLWIND_SECTION_BYTES
@ SPRITE_COLOR_WHITE
solid colour 15, white
Definition animspr.h:26
@ POSE_DAMAGE
taking damage
Definition battle.h:176
@ COMPOSITE_FLIP_X
@ COMPOSITE_FLIP
@ COMPOSITE_MAX
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...
Definition canvas.c:103
void BattleFx_BeginCanvasLayer(s32 bgControl)
Opens the canvas layer: starts the background palette fade, makes BG2 the canvas, alpha-blended over ...
Definition canvas.c:314
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 Camera_ApplyPhasedDelta(void)
Turns the battle camera by cameraDelta.
Definition djinn_heal.c:230
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
What every part of the battle effect object shares: its includes, macros and frame-loop helpers.
#define EFFECT_RELEASE_BLITTERS()
Frees the two blitters, the alternate first.
@ CANVAS_COPY_AND_FADE
copy, keeping 50% or 75% (transferValue) of each pixel in the canvas for the next frame
#define EFFECT_GET_WORK_AND_CANVAS(cursor, work, canvas)
The work block and canvas occupy adjacent slots, starting at HEAP_SLOT_BATTLE_EFFECT.
#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_SLOT(slots, slot)
A work slot read through a pointer to the effect's own slot, gWorkSlot[HEAP_SLOT_BATTLE_EFFECT].
#define EFFECT_FINISH_CANVAS()
The usual end of a canvas effect: stops the transfer callback before freeing what it reads,...
#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_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_END_FRAME(work)
The usual end of an effect frame: counts down the targets' flash timers (ObjectGroup_TickMemberTimers...
#define EFFECT_VIEW_FROM_CAMERA(camera)
Starts a frame's 3D projection from the battle camera: resets the transform, then looks from camera->...
u8 gBattleFx_GlintCellHeights[]
u8 gVortices_Shapes[][3]
Whirlwind, by variant: the WHIRLWIND_ columns.
u8 gVortices_Counts[][2]
Froth, by variant: motes and frames.
u16 gBattleFx_GlintCells[]
u8 gBattleFx_GlintCellWidths[]
@ FROTH_MOTE_COUNT
motes, at most FROTH_MOTES (vortices.c)
@ FROTH_FRAMES
the effect's frames; the damage shows 16 before
@ WHIRLWIND_SHAKE
Camera_ApplyShake's range.
@ WHIRLWIND_TORNADOES
tornadoes drawn
@ WHIRLWIND_SWAY
how far each sways across, in pixels
struct BattleObj * GetBattleObjectSlotFar(s32 objectId)
Far call to BattleObjGet.
s32 BattleUnit_GetEffectHeightFar(s32 id)
void BattleMotion_ApplyVariantMotionFar(s32 id, s32 variant)
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
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_BLITTER_ALTERNATE
Definition heap_state.h:47
@ HEAP_SLOT_CAMERA
Definition heap_state.h:38
@ HEAP_SLOT_BLITTER
Definition heap_state.h:46
@ HEAP_SLOT_BATTLE_CANVAS
Definition heap_state.h:43
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
#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 REG_BLDALPHA
Definition io_reg.h:142
#define BG_PLTT
Definition io_reg.h:157
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
static s32 Iwram_FillWords(void *destination, s32 size, u32 value)
Definition iwram_call.h:59
#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 CLAMP(v, low, high)
Keeps v within low to high, the low bound tested first.
Definition macros.h:23
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
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
#define Ram_MapCellBuffer
Definition ram_buffer.h:10
char ResourceId_TornadoSheet
char ResourceId_VortexSheet
s32 Resource_DecodeType01(const void *source, void *destination)
Decodes a type-01 resource and returns its unpacked byte count.
Definition decompress.c:31
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_133
Definition songs.h:126
#define SE_132
Definition songs.h:125
#define SE_164
Definition songs.h:159
#define SE_141
Definition songs.h:134
void * gWorkSlot[]
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
s16 actors[8]
the targets' unit ids, count of them
s32 variant
the ability's size, from 0 (Quake, then Earthquake)
s32 count
targets in actors, at least 1
The running battle effect's work: its canvas image, 64 particles, the display registers it stages and...
s32 cameraDelta
camera yaw turned per effect frame
s32 shakeFrames
shake frames left; Camera_ApplyShake counts down
s32 cameraPhase
The effect sets 1 after a frame; Camera_ApplyPhasedDelta then turns the whole cameraDelta and sets 0,...
struct BattleEffectArgument * effect
the command being run
struct EffectStep particles[64]
free while variant is -1
struct MotionObject * object
NULL once released.
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
s32 velocityY
16.16 fixed-point pixels per frame
Definition effect_step.h:29
s32 velocityZ
16.16 fixed-point pixels per frame
Definition effect_step.h:30
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
s32 z
16.16 fixed-point pixels
Definition motobj.h:25
s32 y
16.16 fixed-point pixels
Definition motobj.h:24
s32 x
16.16 fixed-point pixels
Definition motobj.h:23
void * Resource_GetTableEntry(s32 index)
Returns the ROM address of resource index from the resource directory.
Definition system.c:150
signed int s32
Definition types.h:14
signed char s8
Definition types.h:10
unsigned char u8
Definition types.h:11
#define EFFECT_CLIP_BOUNDS
Clips overflow on all four sides.
Definition effect.h:224
DrawRectangle BlitterPair[2]
A blitter pair: [0] built in HEAP_SLOT_BLITTER and [1] in HEAP_SLOT_BLITTER_ALTERNATE (BattleFx_Fetch...
Definition effect.h:244
void BattleFx_RunWhirlwind(struct BattleEffectArgument *effect)
Tornadoes sweep across the targets for 80 frames, sparkling with glints; the canvas flashes and the t...
Definition vortices.c:189
#define WHIRLWIND_TORNADO_CELLS
The tornado pictures follow the six glint cells (gBattleFx_GlintCells) in the sheet: 40x32 sections,...
Definition vortices.c:16
#define FROTH_MOTE_CELL
the mote picture in the sheet
Definition vortices.c:7
#define FROTH_FIRST_TARGET
the first target seat in work->particles
Definition vortices.c:8
void BattleFx_RunFroth(struct BattleEffectArgument *effect)
Motes fly out of the top of the user, hang, and from 48 frames after each appears home in on the targ...
Definition vortices.c:36
#define FROTH_MOTES
The motes set up in work->particles, before the target seats: no row of gVortices_Counts may ask for ...
Definition vortices.c:11
#define WHIRLWIND_SECTION_BYTES
Definition vortices.c:17