Alchemy
Loading...
Searching...
No Matches

dragon_cloud.c

Go to the documentation of this file.
1/// @file
2/// Dragon Cloud.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7#define DRAGON_CLOUD_FRAMES 150
8#define DRAGON_CLOUD_STRIKE_FRAME 83 ///< the flame strikes the first target
9#define DRAGON_CLOUD_TRAIL_CELL_BYTES (24 * 39) ///< bytes in each trail copy
10#define DRAGON_CLOUD_FIRST_EMBER 8 ///< the first ember in work->particles
11#define DRAGON_CLOUD_FIRST_FLASH 48 ///< the first flash in work->particles
12#define DRAGON_CLOUD_TRAIL_CELLS 0x1680 ///< the trail picture in the sheet
13#define DRAGON_CLOUD_PUFF_CELLS 0x3c00 ///< the puff pictures in the sheet
14#define DRAGON_CLOUD_PUFFS 8 ///< puffs, particles 0 to 7
15#define DRAGON_CLOUD_EMBERS 40 ///< embers, from FIRST_EMBER
16#define DRAGON_CLOUD_FLASHES 16 ///< flashes, from FIRST_FLASH
17
18/// Draws puff picture cell of sheet on canvas at (x, y) with blit, sized by
19/// the puff tables.
20#define DRAGON_CLOUD_DRAW_PUFF(blit, canvas, sheet, cell, x, y) \
21 blit(canvas, \
22 &(sheet)[DRAGON_CLOUD_PUFF_CELLS] + gBattleFx_PuffArcCells[cell], x, y, \
23 gBattleFx_PuffArcCellWidths[cell], gBattleFx_PuffArcCellHeights[cell])
24
25/// A flame leaves the user along a stored path with a fading trail of 19 copies
26/// behind it, then strikes the first target on DRAGON_CLOUD_STRIKE_FRAME and
27/// bursts into embers and flashes.
28///
29/// Abilities: Dragon Cloud (kind 49).
30///
31/// The trail's last nine copies are darker versions of the trail picture, each
32/// DRAGON_CLOUD_TRAIL_CELL_BYTES long. The camera turns over the first 64 of
33/// the DRAGON_CLOUD_FRAMES frames:
34///
35/// 0 to 17 a pair of puffs, one mirrored, bursts in front of the user
36/// 18 to 58 the flame follows its stored path
37/// 50 the first target flashes, the screen shakes and eight puffs
38/// rise in an arc
39/// 78 to 83 the flame dives in again
40/// 83 the target is struck; embers and flashes burst from it
42 struct Point2D trail[20];
43 struct EffectPosition position;
44 DrawRectangle draw[2];
45 void **slots;
46 void **cursor;
47 struct BattleEffectWork *work;
48 void *canvas;
49 s32 frame;
50 s32 drift;
51 s8 *path;
52 s32 x;
53 s32 y;
54 u8 *sheet;
55 struct BattleCamera *camera;
56 s32 i;
57 s32 j;
58
59 EFFECT_GET_SLOTS(slots, cursor, work, canvas);
60 drift = 0;
61 x = 0;
62 y = 0;
63 sheet = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
64 work->effect = effect;
66 REG_BLDALPHA = BLEND_ALPHA(16, 16);
68 1);
69 // Make nine darker copies after the trail picture, for trail copies 11 to
70 // 19, each four shades darker than the last.
71 for (i = 1; i != 20; i++) {
72 for (j = 0; j != DRAGON_CLOUD_TRAIL_CELL_BYTES; j++) {
73 s32 shade = work->sheet[DRAGON_CLOUD_TRAIL_CELLS + j];
74
75 if (i > 10) {
76 shade = shade - i * 4 + 40;
77 if (shade < 0)
78 shade = 0;
79 work->sheet[DRAGON_CLOUD_TRAIL_CELLS +
80 (i - 10) * DRAGON_CLOUD_TRAIL_CELL_BYTES + j] = shade;
81 }
82 }
83 }
86 &work->sheet[DRAGON_CLOUD_PUFF_CELLS], 1, 1);
88 Ram_MapCellBuffer, 1, 0);
91
92 // Seed the embers (particles 8 to 47) and flashes (48 to 63) thrown at the
93 // strike, and the eight puffs (0 to 7) on an arc, each starting two frames
94 // after the last.
95 for (j = 0; j != DRAGON_CLOUD_EMBERS; j++) {
96 struct EffectStep *ember = &work->particles[DRAGON_CLOUD_FIRST_EMBER + j];
97
98 if (work->effect->side == 0)
99 ember->x = -0x380000;
100 else
101 ember->x = 0x380000;
102 ember->y = 0;
103 ember->z = 0;
104 SET_VELOCITY(ember, ((Random16() & 63) - 32) << 14, (Random16() & 63) << 13,
105 ((Random16() & 63) - 32) << 14);
106 ember->variant = 1;
107 }
108 for (j = 0; j != DRAGON_CLOUD_FLASHES; j++) {
109 struct EffectStep *flash = &work->particles[DRAGON_CLOUD_FIRST_FLASH + j];
110
111 if (work->effect->side == 0)
112 flash->x = -0x380000;
113 else
114 flash->x = 0x380000;
115 flash->y = 0x140000;
116 flash->z = 0;
117 SET_VELOCITY(flash, ((Random16() & 63) - 32) << 14, (Random16() & 63) << 12,
118 ((Random16() & 63) - 32) << 14);
119 flash->variant = 0;
120 }
121 for (i = 0, j = -0x4000; i != DRAGON_CLOUD_PUFFS; i++, j += 0x1000) {
122 struct EffectStep *puff = &work->particles[i];
123
124 if (work->effect->side == 1)
125 puff->x = (Trig_Sin(j) * 24 >> 16) + 88;
126 else
127 puff->x = (-(Trig_Sin(j) * 24) >> 16) + 16;
128 puff->y = (Trig_Cos(j) * 16 >> 16) + 40;
129 puff->variant = -(i * 2);
130 }
132
133 for (frame = 0; frame != DRAGON_CLOUD_FRAMES; frame++) {
134 camera = gCameraWork;
135 if (frame == DRAGON_CLOUD_STRIKE_FRAME)
137 if (frame == 0)
139 if (frame == 50)
141 if (work->effect->side == 0) {
142 if (frame <= 63)
143 camera->yaw -= 0x100;
144 } else {
145 if (frame <= 63)
146 camera->yaw += 0x100;
147 }
149 if (frame <= 17) {
150 s32 cell = frame / 3;
151
152 DRAGON_CLOUD_DRAW_PUFF(draw[0], canvas, work->sheet, cell, 48,
153 gBattleFx_PuffArcCellBiasY[cell] + 60);
154 DRAGON_CLOUD_DRAW_PUFF(draw[1], canvas, work->sheet, cell, 56,
155 gBattleFx_PuffArcCellBiasY[cell] + 60);
156 }
157 // The path gives two 16-bit coordinates on frame 18, then a signed byte
158 // step for each axis every frame through frame 58. From frame 78 the
159 // flame starts again at (-56, 48) and dives 16 pixels a frame.
160 if (frame >= 18 && frame <= 58) {
161 if (frame == 18) {
162 x = (path[0] << 8) + (u8)path[1];
163 y = (path[2] << 8) + (u8)path[3] + 16;
164 path += 4;
165 } else {
166 x += path[0];
167 y += path[1];
168 path += 2;
169 }
170 }
171 if (frame >= 78 && frame <= 118) {
172 if (frame == 78) {
173 x = -56;
174 y = 48;
175 } else {
176 y -= 16;
177 }
178 }
179 // Shift the trail back by one and draw it: copy j follows the flame from
180 // frame j + 19 to frame j + 83, and copies past the tenth are darker.
181 for (j = 19; j != 0; j--) {
182 if (frame > j + 18 && frame <= j + 83) {
183 trail[j].x = trail[j - 1].x;
184 trail[j].y = trail[j - 1].y;
185 if (j > 10)
186 draw[0](canvas,
187 &work->sheet[DRAGON_CLOUD_TRAIL_CELLS +
189 trail[j].x, trail[j].y, 24, 39);
190 else
191 draw[0](canvas, &work->sheet[DRAGON_CLOUD_TRAIL_CELLS], trail[j].x,
192 trail[j].y, 24, 39);
193 }
194 }
196 // The flame leans with its smoothed vertical motion (drift, -8 to 8):
197 // one of five 24x48 cells, from rising to falling. Its position is the
198 // path's, halved across for the wide canvas and mirrored on side 1.
199 if (frame >= 18 && frame <= DRAGON_CLOUD_STRIKE_FRAME) {
200 s32 lift;
201
202 if (work->effect->side == 1)
203 position.x = 64 - x / 2;
204 else
205 position.x = x / 2 + 64;
206 position.y = 60 - y;
207 lift = (position.y - trail[0].y - 24) / 2;
208 if (lift > 2)
209 lift = 2;
210 if (lift < -2)
211 lift = -2;
212 drift += lift;
213 if (drift > 8)
214 drift = 8;
215 if (drift < -8)
216 drift = -8;
217 lift = drift / 4 + 2;
218 trail[0].x = position.x - 12;
219 trail[0].y = position.y - 20;
220 draw[0](canvas, &work->sheet[lift * (24 * 48)], trail[0].x - 6,
221 trail[0].y - 2, 24, 48);
222 }
223 if (frame == DRAGON_CLOUD_STRIKE_FRAME) {
224 work->shakeFrames = 8;
226 POSE_DAMAGE, 0, 8);
228 }
229 // After the strike the embers rise and fall back, 0x2000 a frame, until
230 // they drop below the ground.
231 if (frame > DRAGON_CLOUD_STRIKE_FRAME) {
232 // Embers are motes sized by depth. Only records 56 to 63 play the
233 // six flash pictures, two frames each; the first eight flashes, at 48
234 // to 55, are drawn as motes.
235 for (i = 0; i != 56; i++) {
236 struct EffectStep *ember =
238
239 if (ember->y >= 0) {
240 s32 size;
241
242 EffectPosition_ProjectPoint(&ember->x, &position);
243 position.x >>= 1;
244 if (position.depth <= 159)
245 position.depth = 160;
246 if (position.depth > 799)
247 position.depth = 799;
248 // Nearer is larger: 9 pixels at depth 160 or less.
249 // XXX: from depth 736 on the size is 0, and EFFECT_DRAW_MOTE would
250 // read gBattleFx_MoteCells[-1]; whether an ember ever gets that far
251 // needs a run of the effect to settle.
252 size = 9 - (position.depth - 160) / 64;
253 if (i > 47) {
254 if (ember->variant <= 11) {
255 draw[0](canvas,
256 Ram_MapCellBuffer + ember->variant / 2 * (32 * 64),
257 position.x - 16, position.y - 32, 32, 64);
258 ember->variant++;
259 }
260 } else {
261 EFFECT_DRAW_MOTE(draw[0], canvas, sheet, position.x, position.y,
262 size);
263 }
264 ember->x += ember->velocityX;
265 ember->y += ember->velocityY;
266 ember->z += ember->velocityZ;
267 ember->velocityY -= 0x2000;
268 }
269 }
270 }
271 if (frame == 50) {
272 work->shakeFrames = 12;
274 POSE_DAMAGE, 0, 8);
275 }
276 // The puffs, mirrored, two frames a cell; each starts when its variant
277 // counts up to zero.
278 if (frame > 49) {
279 for (i = 0; i != DRAGON_CLOUD_PUFFS; i++) {
280 struct EffectStep *puff = &work->particles[i];
281
282 if (puff->variant >= 0 && puff->variant <= 11) {
283 s32 cell = puff->variant / 2;
284
285 DRAGON_CLOUD_DRAW_PUFF(draw[1], canvas, work->sheet, cell,
286 puff->x -
288 puff->y + gBattleFx_PuffArcCellBiasY[cell]);
289 }
290 puff->variant++;
291 }
292 }
293 Camera_ApplyShake(8, 8);
294 EFFECT_END_FRAME(work);
295 }
296
298}
299
300#undef DRAGON_CLOUD_FRAMES
301#undef DRAGON_CLOUD_STRIKE_FRAME
302#undef DRAGON_CLOUD_TRAIL_CELL_BYTES
303#undef DRAGON_CLOUD_FIRST_EMBER
304#undef DRAGON_CLOUD_FIRST_FLASH
305#undef DRAGON_CLOUD_TRAIL_CELLS
306#undef DRAGON_CLOUD_PUFF_CELLS
307#undef DRAGON_CLOUD_PUFFS
308#undef DRAGON_CLOUD_EMBERS
309#undef DRAGON_CLOUD_FLASHES
310#undef DRAGON_CLOUD_DRAW_PUFF
@ SPRITE_COLOR_WHITE
solid colour 15, white
Definition animspr.h:26
@ POSE_DAMAGE
taking damage
Definition battle.h:176
struct BattleCamera * gCameraWork
BattleEffectDrawRectangle DrawRectangle
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 Resource_LoadAndDecompress(s32 id, void *dst, s32 skipPalette, s32 copyPalette)
Decompresses a resource whose first 128 bytes may be a palette.
#define DRAGON_CLOUD_FLASHES
flashes, from FIRST_FLASH
#define DRAGON_CLOUD_DRAW_PUFF(blit, canvas, sheet, cell, x, y)
Draws puff picture cell of sheet on canvas at (x, y) with blit, sized by the puff tables.
#define DRAGON_CLOUD_PUFFS
puffs, particles 0 to 7
#define DRAGON_CLOUD_STRIKE_FRAME
the flame strikes the first target
Definition dragon_cloud.c:8
void BattleFx_RunDragonCloud(struct BattleEffectArgument *effect)
A flame leaves the user along a stored path with a fading trail of 19 copies behind it,...
#define DRAGON_CLOUD_EMBERS
embers, from FIRST_EMBER
#define DRAGON_CLOUD_PUFF_CELLS
the puff pictures in the sheet
#define DRAGON_CLOUD_TRAIL_CELLS
the trail picture in the sheet
#define DRAGON_CLOUD_FIRST_EMBER
the first ember in work->particles
#define DRAGON_CLOUD_TRAIL_CELL_BYTES
bytes in each trail copy
Definition dragon_cloud.c:9
#define DRAGON_CLOUD_FIRST_FLASH
the first flash in work->particles
#define DRAGON_CLOUD_FRAMES
Definition dragon_cloud.c:7
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 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_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...
#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_PuffArcCellBiasY[]
u8 gBattleFx_PuffArcCellWidths[]
void BattlePres_SetupTransitionSceneFar(s32 x, s32 depth, s32 y, s32 zoom)
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_SHEET
Definition heap_state.h:44
#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 SET_VELOCITY(p, vx, vy, vz)
Definition macros.h:18
u32 Random16(void)
Advances the game's random number generator (the C library's classic linear congruential one),...
Definition math.c:10
void BattleFx_FetchRectangleBlitters(s32 flip, BlitterPair out)
Builds the two usual routines that draw onto the 128x128 canvas, both clipped on both axes.
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_DualStreamPath
char ResourceId_ParticleSpritesA
char ResourceId_FirePillarSheetB
char ResourceId_FlashBurstSheet
char ResourceId_EmberStreakSheet
#define SE_136
Definition songs.h:129
#define SE_HEAVY_IMPACT
Definition songs.h:127
The battle camera: its eye, the focus it turns about, and its pitch, yaw and distance.
u16 yaw
1/65536 turns
The command shared by an effect's caller, dispatcher and handlers.
s32 side
1 when the targets are the party, 0 for enemies
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 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 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
Two-dimensional {x, y} pair for position or velocity, a local of the summon scenes (Nereid,...
Definition effect.h:236
s32 y
16.16 pixels
Definition effect.h:238
s32 x
16.16 pixels in every scene that uses it
Definition effect.h:237
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