Alchemy
Loading...
Searching...
No Matches

ragnarok.c

Go to the documentation of this file.
1/// @file
2/// Ragnarok.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7/// Where the flash graphics start: after the 64x128 sword image.
8#define RAGNAROK_FLASH_CELLS (64 * 128)
9
10#define RAGNAROK_FRAMES 80
11#define RAGNAROK_COLUMNS 2 ///< columns that strike
12#define RAGNAROK_SEEDED 3 ///< columns given particles; the third is unused
13#define RAGNAROK_FLASHES 16 ///< flashes kept per column
14#define RAGNAROK_RING 12 ///< of which drawn as the ring
15#define RAGNAROK_SPARKS 340 ///< sparks kept per column
16#define RAGNAROK_DRAWN_SPARKS 256 ///< of which flown
17
18/// gRagnarok_StrikeColumns has three columns for each side.
19#define RAGNAROK_COLUMN_X(side, column) \
20 gRagnarok_StrikeColumns[(side)][(column)]
21
22/// A huge flaming blade swings down over the targets and two columns of light
23/// strike through them.
24///
25/// Abilities: Ragnarok (kind 58).
26///
27/// The sword is drawn for 40 frames: it swings down over 10 frames, pauses
28/// until frame 20, then creeps on. The columns flash at frames 16 and 24 and
29/// scatter sparks six frames later, as the targets recoil; the battle shows the
30/// damage on frame 40. Column x comes from gRagnarok_StrikeColumns: first two
31/// of three per side. work->particles holds 16 flashes a column and PARTICLES
32/// 340 sparks a column.
34 void **slots;
35 void **cursor;
36 struct BattleEffectWork *work;
37 void *canvas;
38 s32 col;
39 u8 *sheet;
40 struct MotionObject *user;
41 DrawRectangle blit[2];
42 s32 frame;
43 s32 i;
44
45 EFFECT_GET_SLOTS(slots, cursor, work, canvas);
46 sheet = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
47
48 user = GetBattleObjectSlotFar(effect->actor)->object;
49 // XXX: why the variant is forced to 1, as nothing in the effect or the
50 // battle reads it afterwards; the Lost Age's Ragnarok may show.
51 effect->variant = 1;
52 work->effect = effect;
54 REG_BLDALPHA = BLEND_ALPHA(16, 16);
56 // The user takes its action pose and animates fast until the end.
59
61 1);
63 work->sheet + RAGNAROK_FLASH_CELLS, 1, 0);
65
66 // Prepare 16 flashes and 340 sparks a column, for three columns although
67 // only two strike: the third's random draws are still taken.
68 col = 0;
69 do {
70 // Flashes: i * 2 pixels from the center, lifetime 25-32.
71 i = 0;
72 do {
73 struct EffectStep *flash = &work->particles[col * RAGNAROK_FLASHES + i];
74
75 s32 radius = i * 2;
76 s32 angle = Random16() & 0xffff;
77
78 flash->x = Trig_Sin(angle) * radius;
79 flash->y = -(Trig_Cos(angle) * radius);
80 flash->variant = i / 2 + 25;
81 i++;
82 } while (i != RAGNAROK_FLASHES);
83
84 // Sparks: random direction and speed from column y = 88, lifetime 32-39.
85 i = 0;
86 do {
87 struct EffectStep *spark = &PARTICLES[col * RAGNAROK_SPARKS + i];
88
89 s32 speed;
90 s32 angle;
91
92 speed = (Random16() & 0x1ff) + 32;
93 angle = Random16() & 0xffff;
94 spark->x = RAGNAROK_COLUMN_X(work->effect->side, col) << 16;
95 spark->y = 88 << 16;
96 spark->velocityX = (Trig_Sin(angle) * speed) >> 6;
97 spark->velocityY = -(Trig_Cos(angle) * speed * 2) >> 6;
98 spark->variant = (Random16() & 7) + 32;
99 i++;
100 } while (i != RAGNAROK_SPARKS);
101 col++;
102 } while (col != RAGNAROK_SEEDED);
103
104 // Each transfer keeps 3/4 of every canvas level, for an afterimage.
106
107 frame = 0;
108 do {
109 // Sounds and the first shake; the battle shows the damage on frame 40.
110 if (frame == 4) {
112 }
113 // An 8-frame shake from frame 8.
114 if (frame == 8) {
115 work->shakeFrames = frame;
116 }
117 if (frame == 18) {
119 }
120 if (frame == 40) {
122 }
123
124 // Frames 0 to 39, the blade: it swings down 16 pixels and 10 across a
125 // frame for 10 frames, pauses until frame 20, then creeps on, 2 pixels
126 // down and 1 across a frame. It is cut off at line 104.
127 if (frame <= 39) {
128 s32 height;
129 s32 x;
130 s32 top;
131
132 height = 128;
133 if (work->effect->side == 1) {
134 if (frame <= 9) {
135 x = frame * 10 - 8;
136 top = frame * 16 - 128;
137 } else if (frame > 20) {
138 x = frame + 62;
139 top = frame * 2 - 24;
140 } else {
141 x = 82;
142 top = 16;
143 }
144 } else {
145 if (frame <= 9) {
146 x = 128 - frame * 10;
147 top = frame * 16 - 128;
148 } else if (frame > 20) {
149 x = 58 - frame;
150 top = frame * 2 - 24;
151 } else {
152 x = 38;
153 top = 16;
154 }
155 }
156 if (top + 128 > 104) {
157 height = height - top - 24;
158 }
159 if (height > 0) {
160 blit[0](canvas, work->sheet, x - 32, top, 64, height);
161 }
162 }
163
164 // From frame 17 the palette fades towards the blast colours.
165 if (frame > 16) {
167 }
168
169 // The two columns, from frames 16 and 24: a 12-frame shake and the
170 // flashes at their start, the sparks from 6 frames later.
171 col = 0;
172 do {
173 s32 start = col * 8 + 16;
174
175 if (frame == start) {
176 work->shakeFrames = 12;
177 }
178 if (frame >= start) {
179 // Large flash for the first two frames, then 12 small flashes.
180 if (frame < start + 2) {
181 blit[0](canvas, work->sheet + RAGNAROK_FLASH_CELLS,
182 RAGNAROK_COLUMN_X(work->effect->side, col) - 16, 56, 32, 64);
183 }
184 i = 0;
185 do {
186 struct EffectStep *flash =
187 &work->particles[col * RAGNAROK_FLASHES + i];
188
189 s32 x;
190 s32 life;
191 s32 y;
192
193 y = Q_16_16_TO_INT(flash->y);
194 x = Q_16_16_TO_INT(flash->x) +
195 RAGNAROK_COLUMN_X(work->effect->side, col);
196 life = flash->variant;
197 if (life >= 0 && life <= 17) {
198 blit[0](canvas,
199 work->sheet + (gRagnarok_FlashCells[life / 3] << 11) +
201 x - 16, y + 56, 32, 64);
202 }
203 life = flash->variant;
204 flash->variant = life > 0 ? life - 1 : -1;
205 i++;
206 } while (i != RAGNAROK_RING);
207 }
208
209 // Sparks bounce below y = 108 at half speed; draw only within x = 0-126.
210 if (frame > start + 5) {
211 i = 0;
212 do {
213 struct EffectStep *spark = &PARTICLES[col * RAGNAROK_SPARKS + i];
214
215 if (spark->variant > 0) {
216 s32 x;
217 s32 y;
218 s32 size;
219
220 EffectStep_AdvanceWithGravity2D(spark, 64, 0x1000);
221 spark->variant--;
222 y = spark->y;
223 if (y > (108 << 16)) {
224 spark->velocityY = -spark->velocityY / 2;
225 } else {
226 x = spark->x;
227 if ((x >= 0 && x <= 0x7effff) && y >= 0) {
228 u8 *cell;
229 s32 lane;
230 s32 py = y >> 16;
231 s32 px = x >> 16;
232
233 // Size follows lifetime, 1 to 8 pixels; alternate sparks take
234 // the brighter pixel or add.
235 size = spark->variant / 5 + 1;
236 lane = i & 1;
237 cell = sheet + gBattleFx_MoteCells[size - 1];
238 px -= size / 2;
239 py -= size;
240 blit[lane](canvas, cell, px, py, size, size * 2);
241 }
242 }
243 }
244 i++;
245 } while (i != RAGNAROK_DRAWN_SPARKS);
246 }
247
248 // As the column's sparks start to fly, every target flashes and
249 // recoils.
251 if (frame == start + 6) {
253 POSE_DAMAGE, i, 10);
255 }
256 }
257 col++;
258 } while (col != RAGNAROK_COLUMNS);
259
260 Camera_ApplyShake(16, 16);
261 EFFECT_END_FRAME(work);
262 frame++;
263 } while (frame != RAGNAROK_FRAMES);
264
267}
268
269#undef RAGNAROK_FLASH_CELLS
270#undef RAGNAROK_FRAMES
271#undef RAGNAROK_COLUMNS
272#undef RAGNAROK_SEEDED
273#undef RAGNAROK_FLASHES
274#undef RAGNAROK_RING
275#undef RAGNAROK_SPARKS
276#undef RAGNAROK_DRAWN_SPARKS
277#undef RAGNAROK_COLUMN_X
@ SPRITE_COLOR_WHITE
solid colour 15, white
Definition animspr.h:26
@ 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_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.
@ 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...
u8 gRagnarok_FlashCells[]
The flash picture for each three frames at the end of a flash's life.
u16 gBattleFx_MoteCells[]
Mote cells: particle sheets hold ten, cell n (from 0) n + 1 pixels wide and twice that tall.
struct BattleObj * GetBattleObjectSlotFar(s32 objectId)
Far call to BattleObjGet.
void BattleMotion_ApplyVariantMotionFar(s32 id, s32 variant)
void ObjectDispatch_SelectAnimationFar(void *raw, s32 no)
void ObjectDispatch_SetAnimationSpeedFar(struct DispatchObject *obj, s32 val)
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
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.
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
#define RAGNAROK_DRAWN_SPARKS
of which flown
Definition ragnarok.c:16
#define RAGNAROK_COLUMN_X(side, column)
gRagnarok_StrikeColumns has three columns for each side.
Definition ragnarok.c:19
void BattleFx_RunRagnarok(struct BattleEffectArgument *effect)
A huge flaming blade swings down over the targets and two columns of light strike through them.
Definition ragnarok.c:33
#define RAGNAROK_RING
of which drawn as the ring
Definition ragnarok.c:14
#define RAGNAROK_SEEDED
columns given particles; the third is unused
Definition ragnarok.c:12
#define RAGNAROK_FLASHES
flashes kept per column
Definition ragnarok.c:13
#define RAGNAROK_SPARKS
sparks kept per column
Definition ragnarok.c:15
#define RAGNAROK_FRAMES
Definition ragnarok.c:10
#define RAGNAROK_COLUMNS
columns that strike
Definition ragnarok.c:11
#define RAGNAROK_FLASH_CELLS
Where the flash graphics start: after the 64x128 sword image.
Definition ragnarok.c:8
char ResourceId_FlameBladeSheet
char ResourceId_BlastSheet
char ResourceId_ParticleSpritesA
char ResourceId_FlashBurstSheet
#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.
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)
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
struct MotionObject * object
NULL once released.
A field object as the object dispatcher's far calls take it.
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
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
signed int s32
Definition types.h:14
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