Alchemy
Loading...
Searching...
No Matches

titan_blade.c

Go to the documentation of this file.
1/// @file
2/// Titan Blade.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7/// The sparks, in PARTICLES after the dust.
8#define TITAN_BLADE_SWORD_SPARKS \
9 ((struct EffectStep *)(Ram_MapCellBuffer + \
10 TITAN_BLADE_DUST * sizeof(struct EffectStep)))
11
12#define TITAN_BLADE_FRAMES 102
13#define TITAN_BLADE_SWORD_IMAGE 20000 ///< the sword picture in the sheet
14#define TITAN_BLADE_FLASHES 32 ///< flashes scattered
15#define TITAN_BLADE_RING 16 ///< of which drawn as the ring
16#define TITAN_BLADE_DUST 684 ///< dust slots in PARTICLES, before the sparks
17#define TITAN_BLADE_FIRST_DUST 256 ///< dust lit at once on frame 28
18#define TITAN_BLADE_DRAWN_DUST 342 ///< dust moved and drawn
19#define TITAN_BLADE_SPARKS 340 ///< sparks after the dust
20/// The flash pictures in the sheet, after the 34x104 fire pillar.
21#define TITAN_BLADE_FLASH_CELLS (34 * 104)
22
23/// A huge sword drops onto the first target amid charging flashes, dust and
24/// sparks.
25///
26/// Abilities: Titan Blade (kind 61).
27///
28/// Dust rises at the target's feet from frame 28 while a pillar of fire scrolls
29/// over it; the sword drops in, holds, sinks and plunges after frame 60. A ring
30/// of flashes bursts from frame 56, sparks fly from frame 60 as the battle
31/// shows the damage, and every target flashes and recoils on frame 68. The
32/// canvas is wiped at frames 9 and 60.
34 void **slots;
35 void **slotCursor;
36 struct BattleEffectWork *work;
37 void *canvas;
38 DrawRectangle blitters[2];
39 u8 *sheet;
40 struct EffectPosition screenPosition;
41 s32 frame;
42 s32 canvasCenterX;
43 s32 step;
44 s32 sparkOriginX;
45 s32 i;
46
47 EFFECT_GET_SLOTS(slots, slotCursor, work, canvas);
49
50 work->effect = effect;
52 REG_BLDALPHA = BLEND_ALPHA(16, 16);
53 EffectPosition_ProjectBattler(work->effect->actors[0], &screenPosition);
54 canvasCenterX = screenPosition.x / 2;
55
57 blitters[0] = slots[HEAP_SLOT_BLITTER - HEAP_SLOT_BATTLE_EFFECT];
61
63 work->sheet + TITAN_BLADE_SWORD_IMAGE, 1, 1);
65 0);
67 work->sheet + TITAN_BLADE_FLASH_CELLS, 1, 0);
69
71
72 // The flashes: flash i sits i * 2 pixels from the ring's centre at a
73 // random angle and lives 25 to 40 frames; only the first 16 are drawn.
74 i = 0;
75 do {
76 struct EffectStep *flash = &work->particles[i];
77
78 s32 scale = i * 2;
79 s32 ang = Random16() & 0xFFFF;
80
81 flash->x = Trig_Sin(ang) * scale;
82 flash->y = -(Trig_Cos(ang) * scale);
83 flash->variant = i / 2 + 25;
84 i++;
85 } while (i != TITAN_BLADE_FLASHES);
86
87 // All the dust starts free (variant -1).
88 i = 0;
89 do {
90 PARTICLES[i].variant = -1;
91 i++;
92 } while (i != TITAN_BLADE_DUST);
93
94 i = 0;
95 // The sparks start at canvas y 88 below the target, thrown twice as fast
96 // across as Ragnarok's, and live 32 to 39 frames.
97 sparkOriginX = canvasCenterX << 16;
98 do {
99 struct EffectStep *spark = &TITAN_BLADE_SWORD_SPARKS[i];
100
101 s32 mag;
102 s32 ang;
103
104 /* FAKEMATCH: the mask is loaded into the magnitude before the random word
105 * (ldr r6, =0x1ff; ands r6, r0); as Random16() & 0x1FF, 41 of 779
106 * instructions differ in tbs-en. */
107 mag = 0x1FF;
108 mag &= Random16();
109 ang = Random16() & 0xFFFF;
110 spark->x = sparkOriginX;
111 spark->y = 176 << 15;
112 spark->velocityX = (Trig_Sin(ang) * (mag + 32)) >> 5;
113 spark->velocityY = -(Trig_Cos(ang) * (mag + 32)) >> 6;
114 spark->variant = (Random16() & 7) + 32;
115 i++;
116 } while (i != TITAN_BLADE_SPARKS);
117
118 frame = 0;
119 do {
120 // The palette fades towards the blast colours over frames 25 to 47,
121 // then towards the lightning colours from frame 57.
122 if (frame >= 25 && frame <= 47) {
124 }
125 if (frame > 56) {
127 }
128
129 // Shakes of 8 frames from frames 8 and 48, and of 16 from the strike.
130 if (frame == 8) {
131 work->shakeFrames = frame;
132 }
133 if (frame == 48) {
134 work->shakeFrames = 8;
135 }
136 if (frame == 60) {
137 work->shakeFrames = 16;
138 }
139
140 if (frame == 4) {
142 }
143 if (frame == 32) {
145 }
146 if (frame == 60) {
149 }
150
151 // From frame 56: a ring of 16 flashes around the target, each shown for
152 // the last 18 frames of its life.
153 if (frame > 55) {
154 i = 0;
155 do {
156 struct EffectStep *flash = &work->particles[i];
157
158 s32 x;
159 s32 life;
160 s32 y;
161
162 y = Q_16_16_TO_INT(flash->y);
163 x = Q_16_16_TO_INT(flash->x) + canvasCenterX;
164 life = flash->variant;
165 if (life >= 0 && life <= 17) {
166 blitters[0](canvas,
167 work->sheet + (gTitanBlade_FlashCells[life / 3] << 11) +
169 x - 16, y + 48, 32, 64);
170 }
171 life = flash->variant;
172 flash->variant = life > 0 ? life - 1 : -1;
173 i++;
174 } while (i != TITAN_BLADE_RING);
175 }
176
177 // Dust at the target's feet: every free one of the first 256 on frame
178 // 28, scattered up to 8 pixels across and 16 up and down around canvas
179 // y 96, thrown up.
180 if (frame == 28) {
181 i = 0;
182 do {
183 struct EffectStep *dust = &PARTICLES[i];
184
185 if (dust->variant == -1) {
186 s32 mag;
187 s32 ang;
188
189 mag = Random16() & 63;
190 ang = Random16() & 0xFFFF;
191 dust->x = ((Trig_Sin(ang) * mag) >> 3) + sparkOriginX;
192 dust->y = ((Trig_Cos(ang) * mag) >> 2) + (192 << 15);
193 dust->velocityX = ((Random16() & 63) - 32) << 14;
194 dust->velocityY = (-(Random16() & 63) - 8) << 13;
195 dust->variant = 0;
196 }
197 i++;
198 } while (i != TITAN_BLADE_FIRST_DUST);
199 }
200
201 // Frames 32 to 63: up to 16 more dust a frame, and the 34-pixel pillar
202 // of fire scrolls up through the target in two pieces that wrap at 104
203 // rows.
204 step = frame - 32;
205 if (step >= 0 && step <= 31) {
206 s32 cnt;
207
208 cnt = 0;
209 i = 0;
210 do {
211 struct EffectStep *dust = &PARTICLES[i];
212
213 if (dust->variant == -1) {
214 s32 mag;
215 s32 ang;
216
217 mag = Random16() & 63;
218 ang = Random16() & 0xFFFF;
219 dust->x = ((Trig_Sin(ang) * mag) >> 3) + sparkOriginX;
220 dust->y = ((Trig_Cos(ang) * mag) >> 2) + (192 << 15);
221 dust->velocityX = ((Random16() & 63) - 32) << 14;
222 dust->velocityY = (-(Random16() & 63) - 8) << 13;
223 dust->variant = 0;
224 cnt++;
225 if (cnt == 16) {
226 break;
227 }
228 }
229 i++;
230 } while (i != TITAN_BLADE_DUST);
231 }
232
233 if (step >= 0 && step <= 31) {
234 s32 phase = frame * 16;
235 s32 x = canvasCenterX - 17;
236 s32 width = 34;
237 DrawRectangle blit = blitters[0];
238 s32 high = 104;
239 s32 size = (phase - 256) % high;
240
241 blit(canvas, work->sheet, x, 4 - size, width, high);
242 blit(canvas, work->sheet, x, 108 - size, width, size);
243 }
244
245 // Until frame 71, move and draw the first 342 dust motes; they swell
246 // from frame 69, and one goes out once it falls below y 108. The tests
247 // on frames past 71 never hold here.
248 if (frame <= 71) {
249 i = 0;
250 do {
251 struct EffectStep *dust = &PARTICLES[i];
252
253 if (dust->variant >= 0) {
254 s32 size;
255
256 size = i % 3 + 2;
257 if (dust->velocityY > 0) {
258 size += 2;
259 }
260 if (frame > 68 && size <= 5) {
261 size = 6;
262 }
263 if (frame > 70 && size <= 6) {
264 size = 7;
265 }
266 if (frame > 72 && size <= 7) {
267 size = 8;
268 }
269 if (frame > 74 && size <= 8) {
270 size = 9;
271 }
272 if (frame > 76) {
273 size = 10;
274 }
275 EFFECT_DRAW_MOTE(blitters[0], canvas, sheet, Q_16_16_TO_INT(dust->x),
276 Q_16_16_TO_INT(dust->y), size);
277
278 dust->x += dust->velocityX;
279 dust->y += dust->velocityY;
280 if (frame > 80) {
281 dust->velocityY += -32768;
282 } else {
283 dust->velocityY += gTitanBlade_DustGravity[i & 3];
284 }
285 dust->velocityX = dust->velocityX * 62 / 64;
286 dust->velocityY = dust->velocityY * 62 / 64;
287 dust->variant++;
288 if (dust->velocityY > 0 && Q_16_16_TO_INT(dust->y) > 108) {
289 dust->variant = -1;
290 }
291 }
292 i++;
293 } while (i != TITAN_BLADE_DRAWN_DUST);
294 }
295
296 // The 36x120 sword, until frame 95: it drops in over 10 frames, holds,
297 // sinks slowly from frame 33 and plunges after frame 60. Rows below
298 // y 108 are not drawn.
299 if (frame <= 95) {
300 s32 x;
301 s32 high;
302 s32 top;
303
304 x = canvasCenterX - 18;
305 high = 120;
306 if (frame > 60) {
307 top = frame * 8 - 450;
308 } else if (frame > 32) {
309 top = step / 2 + 16;
310 } else if (frame <= 9) {
311 top = frame * 16 - 128;
312 } else {
313 top = 16;
314 }
315 if (top + 120 > 108) {
316 high = high - top - 12;
317 }
318 if (high > 0) {
319 blitters[1](canvas, work->sheet + TITAN_BLADE_SWORD_IMAGE, x, top, 36,
320 high);
321 }
322 }
323
324 // From frame 60 the sparks fly, bouncing at half speed below y 108.
325 if (frame > 59) {
326 i = 0;
327 do {
328 struct EffectStep *spark = &TITAN_BLADE_SWORD_SPARKS[i];
329
330 if (spark->variant > 0) {
331 s32 x;
332 s32 y;
333 s32 size;
334
335 EffectStep_AdvanceWithGravity2D(spark, 64, 128 << 6);
336 y = spark->y;
337 spark->variant--;
338 if (y > (216 << 15)) {
339 spark->velocityY = -spark->velocityY / 2;
340 } else {
341 x = spark->x;
342 if ((x >= 0 && x <= 0x7effff) && y >= 0) {
343 u8 *cell;
344
345 size = spark->variant / 5 + 1;
346 cell = sheet + gBattleFx_MoteCells[size - 1];
347 x >>= 16;
348 y >>= 16;
349 x -= size / 2;
350 y -= size;
351 blitters[0](canvas, cell, x, y, size, size * 2);
352 }
353 }
354 }
355 i++;
356 } while (i != TITAN_BLADE_SPARKS);
357 }
358
359 // Frame 68: every target flashes and recoils.
360 if (frame == 68) {
363 POSE_DAMAGE, i, 16);
365 }
366 }
367
368 // The canvas flashes, filled with level 63, as the sword lands and as it
369 // strikes.
370 if (frame == 9) {
371 Iwram_FillWords(canvas, CANVAS_BYTES, 0x3F3F3F3F);
372 }
373 if (frame == 60) {
374 Iwram_FillWords(canvas, CANVAS_BYTES, 0x3F3F3F3F);
375 }
376
377 Camera_ApplyShake(16, 16);
378 EFFECT_END_FRAME(work);
379 frame++;
380 } while (frame != TITAN_BLADE_FRAMES);
381
383}
384
385#undef TITAN_BLADE_SWORD_SPARKS
386#undef TITAN_BLADE_FRAMES
387#undef TITAN_BLADE_SWORD_IMAGE
388#undef TITAN_BLADE_FLASHES
389#undef TITAN_BLADE_RING
390#undef TITAN_BLADE_DUST
391#undef TITAN_BLADE_FIRST_DUST
392#undef TITAN_BLADE_DRAWN_DUST
393#undef TITAN_BLADE_SPARKS
394#undef TITAN_BLADE_FLASH_CELLS
@ SPRITE_COLOR_WHITE
solid colour 15, white
Definition animspr.h:26
@ POSE_DAMAGE
taking damage
Definition battle.h:176
@ COMPOSITE_TRANSPARENT
@ 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_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_StepPaletteToResource(s32 resourceId)
Moves each RGB555 channel of background colours 0 to 63 one level towards the resource palette.
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.
Definition dispatch.c:254
What every part of the battle effect object shares: its includes, macros and frame-loop helpers.
#define EFFECT_DRAW_MOTE(draw, canvas, sheet, x, y, size)
Particle sheets hold ten mote cells, 1x2 to 10x20 pixels.
@ 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_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_GET_SLOTS(slots, cursor, work, canvas)
Starts at the effect's entry in the whole work-slot array.
#define EFFECT_END_FRAME(work)
The usual end of an effect frame: counts down the targets' flash timers (ObjectGroup_TickMemberTimers...
s32 gTitanBlade_DustGravity[]
Dust gravity, by particle index & 3.
u16 gBattleFx_MoteCells[]
Mote cells: particle sheets hold ten, cell n (from 0) n + 1 pixels wide and twice that tall.
u8 gTitanBlade_FlashCells[]
The flash picture for each three frames at the end of a flash's life.
void BattleMotion_ApplyVariantMotionFar(s32 id, s32 variant)
void AudioCommand_PlayFar(s32 id)
s32 Trig_Cos(s32 angle)
s32 Trig_Sin(s32 angle)
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_BATTLE_SHEET
Definition heap_state.h:44
@ HEAP_SLOT_BLITTER
Definition heap_state.h:46
#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
static s32 Iwram_FillWords(void *destination, s32 size, u32 value)
Definition iwram_call.h:59
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
void EffectPosition_ProjectBattler(s32 id, struct EffectPosition *position)
The screen position of a battler, 16 pixels higher.
Definition positions.c:100
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,...
Definition positions.c:46
char ResourceId_FirePillarSheetA
char ResourceId_BlastSheet
char ResourceId_LightningBoltSheet
char ResourceId_ParticleSpritesA
char ResourceId_SwordSheet
char ResourceId_FlashBurstSheet
#define SE_164
Definition songs.h:159
#define SE_212
Definition songs.h:207
#define SE_HEAVY_IMPACT
Definition songs.h:127
#define SE_145
Definition songs.h:138
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 shakeFrames
shake frames left; Camera_ApplyShake counts down
struct BattleEffectArgument * effect
the command being run
struct EffectStep particles[64]
free while variant is -1
A point projected onto the screen, with its depth.
Definition effect_step.h:46
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 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
#define TITAN_BLADE_DRAWN_DUST
dust moved and drawn
Definition titan_blade.c:18
#define TITAN_BLADE_FLASH_CELLS
The flash pictures in the sheet, after the 34x104 fire pillar.
Definition titan_blade.c:21
#define TITAN_BLADE_FLASHES
flashes scattered
Definition titan_blade.c:14
#define TITAN_BLADE_RING
of which drawn as the ring
Definition titan_blade.c:15
#define TITAN_BLADE_SPARKS
sparks after the dust
Definition titan_blade.c:19
#define TITAN_BLADE_SWORD_SPARKS
The sparks, in PARTICLES after the dust.
Definition titan_blade.c:8
#define TITAN_BLADE_FRAMES
Definition titan_blade.c:12
#define TITAN_BLADE_DUST
dust slots in PARTICLES, before the sparks
Definition titan_blade.c:16
void BattleFx_RunTitanBlade(struct BattleEffectArgument *effect)
A huge sword drops onto the first target amid charging flashes, dust and sparks.
Definition titan_blade.c:33
#define TITAN_BLADE_SWORD_IMAGE
the sword picture in the sheet
Definition titan_blade.c:13
#define TITAN_BLADE_FIRST_DUST
dust lit at once on frame 28
Definition titan_blade.c:17
signed int s32
Definition types.h:14
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