Alchemy
Loading...
Searching...
No Matches

frost.c

Go to the documentation of this file.
1/// @file
2/// Frost.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7/// One row of gFrost_Timings, for each variant.
8enum {
9 FROST_MOTES, ///< the rising motes
10 FROST_COLUMNS, ///< the ice columns
11 FROST_FRAME ///< the frame the motes burst
12};
13
14/// Rising motes: motes spiral upwards while ice columns spring up one every 3
15/// frames from frame 36; at the burst frame the motes spread and fall, chips
16/// fly and smoke rises over the heights they span.
17///
18/// Abilities: Frost, Tundra, Glacier (kind 6).
19///
20/// The targets take a blue tint 4 frames apart from frame 40, the battle shows
21/// the damage 11 frames after the burst, and the effect ends 75 frames after
22/// it.
23///
24/// work->particles holds the 64 motes (angle, height and radius in x, y and
25/// z); after the burst the first 32 also hold the smoke puffs, in their
26/// velocity and variant fields, while motes 0 to 15 keep moving in theirs.
27/// PARTICLES holds the 32 chips. Writes REG_BG2PA and, on side 1, REG_BG2X;
28/// ends with the blitters freed, the transfer callback removed and the canvas
29/// layer closed.
30///
31/// effect: the targets; variant picks the number of motes and columns and
32/// the burst frame (gFrost_Timings).
34 void **slots;
35 void **cursor;
36 struct BattleEffectWork *work;
37 void *canvas;
38 s32 frame;
39 u8 *puffSheet;
40 DrawRectangle *draw;
41 s32 count;
42 s32 lowest;
43 s32 highest;
44 s32 xyz[3];
45 struct EffectPosition screen;
46 s32 point[3];
47 BlitterPair pair;
48 struct EffectStep *mote;
49 s32 i;
50
52 cursor = slots;
53 EFFECT_GET_WORK_AND_CANVAS(cursor, work, canvas);
54 puffSheet = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
55 work->effect = effect;
59 /* FAKEMATCH: the motes, columns, chips and puffs draw through a pointer
60 * to the pair, the columns' second picture through the pair itself; with
61 * pair[1] everywhere, 72 lines of tbs-en effect.s differ. */
62 BattleFx_FetchRectangleBlitters(0, draw = pair);
63
64 // Motes: x holds the angle, z the radius (56 to 119), y the height (-64
65 // to -33 pixels).
66 for (i = 0; i != 64; i++) {
67 struct EffectStep *seed = &work->particles[i];
68
69 seed->x = Random16() & 0xffff;
70 seed->z = (Random16() & 63) + 56;
71 seed->y = ((Random16() & 31) - 64) << 16;
72 }
73
75 // On side 1 the canvas moves 112 pixels right, over the party.
76 if (work->effect->side == 1)
77 REG_BG2X = -0x7000;
78
79 for (frame = 0;
80 frame != gFrost_Timings[work->effect->variant][FROST_FRAME] + 75;
81 frame++) {
82 // The range of heights the smoke will rise over, in 16.16 pixels,
83 // gathered from the motes and chips below.
84 lowest = 120 << 16;
85 highest = 0;
86 if (frame == gFrost_Timings[work->effect->variant][FROST_FRAME] + 11)
88 // The motes turn about a point 512 pixels in front of the eye, not about
89 // a target.
90 SET_VECTOR(point, 0, 0, 512 << 16);
93 // A chime every 4 frames while the columns spring up.
94 if (frame >= 36 && frame < 64 && (frame & 3) == 0)
96 // Frame 85 is Frost's burst; Tundra and Glacier play this sound 12 and 24
97 // frames before theirs.
98 if (frame == 85)
101 if (frame == i * 4 + 40)
104 }
105
106 // Motes: mote i appears at frame i and, from 16 frames later, turns,
107 // closing in and rising 5 pixels a frame up to 48 pixels. After the
108 // burst only the first 16 remain, spreading out and falling, and the
109 // range of their heights is kept; none is drawn from 35 frames after it.
110 // A mote is drawn only between -48 pixels and a ceiling that falls half a
111 // pixel with each index, so they stop at staggered heights. The screen
112 // position is halved for the narrow canvas and centred on (64, 60).
113 if (frame < gFrost_Timings[work->effect->variant][FROST_FRAME])
114 count = gFrost_Timings[work->effect->variant][FROST_MOTES];
115 else
116 count = 16;
117 if (frame < gFrost_Timings[work->effect->variant][FROST_FRAME] + 35) {
118 for (i = 0; i != count; i++) {
119 if (frame > i) {
120 s32 cell = i % 8;
121
122 mote = &work->particles[i];
123 if (mote->y < (48 - i / 2) << 16 && mote->y > -(48 << 16)) {
124 struct EffectPosition *position;
125 u32 width;
126 u32 height;
127
128 SET_VECTOR(xyz, mote->z * Trig_Sin(mote->x), mote->y,
129 mote->z * Trig_Cos(mote->x));
130 EffectPosition_ProjectPoint(xyz, position = &screen);
131 position->x = (position->x >> 17) + 64;
132 position->y = Q_16_16_TO_INT(position->y) + 60;
133 // UB: width is assigned in one argument and read in another.
134#ifdef UBFIX
135 width = gFrost_MoteWidths[cell];
136 height = gFrost_MoteHeights[cell];
137 draw[1](canvas, work->sheet + gFrost_MoteCells[cell],
138 position->x - (width >> 1), position->y - (height >> 1),
139 width, height);
140#else
141 draw[1](canvas, work->sheet + gFrost_MoteCells[cell],
142 position->x - ((width = gFrost_MoteWidths[cell]) >> 1),
143 position->y - ((height = gFrost_MoteHeights[cell]) >> 1),
144 width, height);
145#endif
146 }
147 if (frame < gFrost_Timings[work->effect->variant][FROST_FRAME]) {
148 if (frame > i + 16) {
149 if (mote->z > 4)
150 mote->z -= 2;
151 if (mote->y < 48 << 16)
152 mote->y += 5 << 16;
153 mote->x += 0x200;
154 }
155 } else {
156 mote->z += 8;
157 mote->y -= (i % 5 + 2) << 16;
158 if (lowest > mote->y)
159 lowest = mote->y;
160 if (highest < mote->y)
161 highest = mote->y;
162 }
163 }
164 }
165 }
166 // Mote heights are relative to their centre: 64 rows down the canvas
167 // puts them beside the chips' canvas rows.
168 lowest += 64 << 16;
169 highest += 64 << 16;
170
171 // Columns (32 wide), standing at gFrost_ColumnSpots: one more every 3
172 // frames from frame 36; over the last 7 frames before the burst they use
173 // the second blitter, a flash before they break.
174 if (frame < gFrost_Timings[work->effect->variant][FROST_FRAME]) {
175 for (i = 0; i != gFrost_Timings[work->effect->variant][FROST_COLUMNS];
176 i++) {
177 if (i < (frame - 36) / 3) {
178 s32 cell = i % 3;
179 u32 height;
180
181 if (frame >= gFrost_Timings[work->effect->variant][FROST_FRAME] - 7) {
182#ifdef UBFIX
183 height = gFrost_ColumnHeights[cell];
184 draw[1](canvas, work->sheet + gFrost_ColumnCells[cell],
187 32, height);
188#else
189 draw[1](canvas, work->sheet + gFrost_ColumnCells[cell],
192 (height = gFrost_ColumnHeights[cell]),
193 32, height);
194#endif
195 } else {
196#ifdef UBFIX
197 height = gFrost_ColumnHeights[cell];
198 pair[0](canvas, work->sheet + gFrost_ColumnCells[cell],
201 32, height);
202#else
203 pair[0](canvas, work->sheet + gFrost_ColumnCells[cell],
206 (height = gFrost_ColumnHeights[cell]),
207 32, height);
208#endif
209 }
210 }
211 }
212 }
213
214 // Chips: at the burst, 32 fly up from canvas rows 80 to 95 for 16 to 31
215 // frames each (24 of them are drawn).
216 if (frame == gFrost_Timings[work->effect->variant][FROST_FRAME]) {
217 for (i = 0; i != 32; i++) {
218 struct EffectStep *chip = &PARTICLES[i];
219
220 SET_POSITION(chip, (Random16() & 127) << 16,
221 ((Random16() & 15) + 80) << 16,
222 ((Random16() & 63) - 32) << 12);
223 chip->velocityY = ((-Random16() & 15) - 16) << 13;
224 chip->variant = (Random16() & 15) + 16;
225 }
226 }
227 if (frame >= gFrost_Timings[work->effect->variant][FROST_FRAME]) {
228 // The first 24 chips, drawn while they last; every one, live or not,
229 // widens the range of heights the smoke rises over.
230 for (i = 0; i != 24; i++) {
231 struct EffectStep *chip = &PARTICLES[i];
232
233 if (chip->variant >= 0) {
234 s32 cell = i % 8;
235
236 draw[1](canvas, work->sheet + gFrost_ChipCells[cell],
237 Q_16_16_TO_INT(chip->x), Q_16_16_TO_INT(chip->y),
239 chip->x += chip->velocityX;
240 chip->y += chip->velocityY;
241 chip->variant--;
242 }
243 if (lowest > chip->y)
244 lowest = chip->y;
245 if (highest < chip->y)
246 highest = chip->y;
247 }
248 }
249 lowest >>= 16;
250 highest >>= 16;
251 if (highest <= lowest)
252 highest = lowest + 1;
253
254 // Smoke: puffs appear over the heights of the motes and chips and rise
255 // half a pixel a frame. A puff keeps its x and y in velocityX and
256 // velocityY, since x, y and z still hold the first 16 motes, and waits
257 // 3 to 18 frames before its first picture (variant 20 to 35).
258 if (frame == gFrost_Timings[work->effect->variant][FROST_FRAME]) {
259 for (i = 0; i != 32; i++) {
260 struct EffectStep *puff = &work->particles[i];
261
262 puff->velocityX = (Random16() & 127) << 16;
263 if (highest == lowest)
264 puff->velocityY = lowest << 16;
265 else
266 puff->velocityY = (Random16() % (highest - lowest) + lowest) << 16;
267 puff->variant = (Random16() & 15) + 20;
268 }
269 }
270 if (frame >= gFrost_Timings[work->effect->variant][FROST_FRAME]) {
271 // Each puff plays nine pictures, 2 frames each, and until 35 frames
272 // after the burst starts again at a random spot when it goes out.
273 s32 rise =
274 (frame - gFrost_Timings[work->effect->variant][FROST_FRAME]) / 2;
275
276 for (i = 0; i != 32; i++) {
277 struct EffectStep *puff = &work->particles[i];
278
279 if (puff->variant >= 0 && puff->variant <= 17) {
280 s32 cell = (17 - puff->variant) / 2;
281 u32 size;
282
283#ifdef UBFIX
284 size = gBattleFx_PuffSizes[cell];
285 draw[1](canvas, puffSheet + gBattleFx_PuffCells[cell],
286 Q_16_16_TO_INT(puff->velocityX) - (size >> 1),
287 Q_16_16_TO_INT(puff->velocityY) - (size >> 1) - rise, size,
288 size);
289#else
290 draw[1](canvas, puffSheet + gBattleFx_PuffCells[cell],
292 ((size = gBattleFx_PuffSizes[cell]) >> 1),
293 Q_16_16_TO_INT(puff->velocityY) - (size >> 1) - rise, size,
294 size);
295#endif
296 }
297 puff->variant--;
298 if ((puff->variant == -1 || puff->variant == 17) &&
299 frame < gFrost_Timings[work->effect->variant][FROST_FRAME] + 35) {
300 puff->variant = 17;
301 puff->velocityX = (Random16() & 127) << 16;
302 puff->velocityY = (Random16() % (highest - lowest) + lowest) << 16;
303 }
304 }
305 }
307 }
308
312}
@ SPRITE_COLOR_BLUE_TINT
blue raised to full
Definition animspr.h:27
@ POSE_DAMAGE
taking damage
Definition battle.h:176
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_EndCanvasLayer(void)
Closes the canvas layer: plays the closing sound, restores BG1's scroll and the projection centre,...
Definition canvas.c:490
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
void BattleFx_RunFrost(struct BattleEffectArgument *effect)
Rising motes: motes spiral upwards while ice columns spring up one every 3 frames from frame 36; at t...
Definition frost.c:33
@ FROST_COLUMNS
the ice columns
Definition frost.c:10
@ FROST_FRAME
the frame the motes burst
Definition frost.c:11
@ FROST_MOTES
the rising motes
Definition frost.c:9
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.
#define EFFECT_PRESENT_FRAME(work)
Ends a frame of a canvas effect: marks the canvas ready for the transfer callback,...
@ 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 EFFECT_SLOT(slots, slot)
A work slot read through a pointer to the effect's own slot, gWorkSlot[HEAP_SLOT_BATTLE_EFFECT].
#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_BEGIN_NARROW_CANVAS(bgControl)
Opens the canvas layer at the canvas's own width, one texel per pixel, where BattleFx_BeginCanvasLaye...
u8 gFrost_ColumnHeights[]
u8 gFrost_MoteWidths[]
u8 gFrost_Timings[][3]
Motes, ice columns and the burst frame, for each variant.
u16 gFrost_ChipCells[]
u8 gBattleFx_PuffSizes[]
Each puff cell's side.
u16 gBattleFx_PuffCells[]
Nine square puff cells, read by the falling, frost, healing, Djinni heal and Boreas parts.
u8 gFrost_ChipWidths[]
u8 gFrost_ColumnSpots[][2]
Where each ice column stands: x, then the y of its foot.
u8 gFrost_MoteHeights[]
u8 gFrost_ChipHeights[]
u16 gFrost_ColumnCells[]
u16 gFrost_MoteCells[]
@ RISING_MOTES_COLUMN_X
canvas x of the column's left edge
@ RISING_MOTES_COLUMN_FOOT
canvas y of its foot
void AudioCommand_PlayFar(s32 id)
s32 Trig_Cos(s32 angle)
s32 Trig_Sin(s32 angle)
@ HEAP_SLOT_BATTLE_EFFECT
Definition heap_state.h:42
@ HEAP_SLOT_BATTLE_SHEET
Definition heap_state.h:44
#define REG_BG2X
Definition io_reg.h:65
#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
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
char ResourceId_SparkleDots
char ResourceId_IceChipSheet
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define SE_136
Definition songs.h:129
#define SE_115
Definition songs.h:108
#define SE_132
Definition songs.h:125
void * gWorkSlot[]
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
s32 variant
the ability's size, from 0 (Quake, then Earthquake)
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
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 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
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
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned char u8
Definition types.h:11
#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
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