Alchemy
Loading...
Searching...
No Matches

bind.c

Go to the documentation of this file.
1/// @file
2/// Bind and Triangle Strike.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7// The triangle effects (Bind, Luff and BattleFx_RunTriangleStrike) spin a
8// shrinking triangle onto the first target for 64 frames and then stand a
9// rune there. The triangle is drawn as the ring and star effects draw their
10// outlines: its corners are projected onto the canvas and stored in the
11// velocity fields of EffectStep records, then each edge is sampled at evenly
12// spaced points and a flare is stamped at each. Both runners write the same
13// frame loop; only the prelude, the step towards the target and the vertex
14// table differ. The blue-ramp helper here, which nothing calls, converts a
15// full-screen tiled picture in place.
16
17/// Turns the screen into shades of blue, top down, with a ragged edge. Works
18/// on a copy of the screen in Ram_MapCellBuffer. Each column starts up to 63
19/// lines late, and the edge speeds up a little every frame; after at most 27
20/// frames the picture moves onto a second blue ramp at colours 96 to 127.
21/// Takes 256 random numbers, one a column.
22///
23/// Nothing calls it or takes its address. Writes background colours 32 to 63
24/// and then 96 to 127, the 0x7800 bytes of BG character block 2 (the
25/// backdrop's picture) and Ram_MapCellBuffer, keeps its delays in the sheet
26/// slot, and waits a frame for each step of the edge.
28 s32 i, x, y, row, end, speed;
29 s32 red, green, blue;
30 u16 color;
31 u8 *delays, *p, *pixel;
32 u16 *palette;
33 u32 delayMask;
34 // A 32-colour blue ramp at colours 32 to 63, red and green at half the blue.
35 palette = (u16 *)&BG_PLTT_COLOR(2, 0);
36 i = 0;
37 do {
38 s32 half;
39 half = i / 2;
40 *palette++ = RGB(half, half, i);
41 i++;
42 } while (i != 32);
43 delays = *(u8 **)&gWorkSlot[HEAP_SLOT_BATTLE_SHEET];
44 // The edge moves speed / 4 lines a frame, speed rising by one a frame
45 // from 16.
46 end = 0;
47 speed = 16;
49 delayMask = 63;
50 p = delays;
51 do {
52 *p++ = Random16() & delayMask;
53 } while (p != delays + 256);
54 row = 0;
55 i = 0;
56 do {
57 end += speed / 4;
58 speed++;
59 while (row != end) {
60 x = 0;
61 do {
62 y = row - delays[x];
63 if (y >= 0) {
64 if (y <= 119) {
65 pixel = BLUE_RAMP_PIXELS + ((x & 7) + ((x / 8) << 6) +
66 ((y & 7) << 3) + ((y / 8) << 11));
67 // Column x reaches line row - delays[x]; the pixel there becomes
68 // the brightest of its colour's channels, inverted, as an index
69 // into the ramp.
70 color = ((s16 *)BG_PLTT)[*pixel];
71 red = color & 31;
72 green = (color >> 5) & 31;
73 blue = (color >> 10) & 31;
74 if (red < green)
75 red = green;
76 if (red < blue)
77 red = blue;
78 *pixel = 63 - red;
79 }
80 }
81 x++;
82 } while (x != 256);
83 row++;
84 }
86 WaitFrames(1);
87 // Past line 248 every column (120 lines, lagging at most 63) is done.
88 if (end > 248)
89 break;
90 i++;
91 } while (i != 27);
92 // Then move every pixel up 64 colours, onto a second ramp at 96 to 127.
93 palette = (u16 *)&BG_PLTT_COLOR(6, 0);
94 i = 0;
95 do {
96 s32 half;
97 half = i / 2;
98 *palette++ = RGB(half, half, i);
99 i++;
100 } while (i != 32);
101 i = 0;
102 do {
103 BLUE_RAMP_PIXELS[i] += 64;
104 i++;
105 } while (i != 0x7800);
107 WaitFrames(1);
108}
109
110/// A triangle of light spins and shrinks onto the first target for 64 frames,
111/// then a rune stands on the target; the battle shows the result on frame 64.
112///
113/// Abilities: Bind (kind 38); Luff (kind 218).
114///
115/// When effect->prelude is 1 a Jupiter Djinni appears first, sways and rises
116/// away. The canvas darkens a little faster every 16 frames.
117///
118/// Runs BattleFx_RunDjinniEntrance first when effect->prelude is 1. Moves
119/// BG2X so the canvas's x 64 is on the first target, cycles the palette
120/// each frame through Graphics_UpdatePhasePalette, raises
121/// work->transferValue every 16 frames, keeps the triangle's corners in
122/// work->particles 0 to 2, and builds and frees its blitters every frame.
124 struct EffectPosition anchor;
125 // World input and projected vertices reuse one coordinate workspace.
126 union {
127 struct Vector3 world;
128 struct EffectPosition projected;
129 } position;
130 struct EffectPosition screen;
131 struct Vector3 scale;
132 s32 originX;
133 s32 originY;
134 BlitterPair draw;
135 void **slots;
136 void **cursor;
137 struct BattleEffectWork *work;
138 void *canvas;
139 s32 frame;
140 s32 member;
141 struct BattleCamera *camera;
142 s32 shift;
143 u8 *graphics;
144 u8 *palette;
145 struct MotionObject *object;
146 s32 tick;
147 struct EffectStep *point;
148 s32 size;
149 s32 j;
150 s32 k;
151
153 cursor = slots;
154 EFFECT_GET_WORK_AND_CANVAS(cursor, work, canvas);
155 graphics = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
156 camera = WORK_SLOT(HEAP_SLOT_CAMERA);
157 work->effect = effect;
159 if (work->effect->prelude == 1)
160 BattleFx_RunDjinniEntrance(effect, 3, work->effect->side, 0, &originX,
161 &originY);
162 REG_BG2PA = Q_8_8(1);
163
164 // Setup. The rune, the flares at 0x1000 and the Djinni at 0x2000, in the
165 // rune's colours; the Djinni sheet's palette is skipped.
167 Iwram_CopyWords((void *)BG_PLTT, palette, 128);
168 palette += 128;
169 Resource_DecodeType01(palette, work->sheet);
174 work->sheet + 0x1000);
176 palette += 128;
177 Resource_DecodeType01(palette, work->sheet + 0x2000);
178 // 4 off every pixel each frame.
181 shift = 64 - anchor.x;
182 REG_BG2X = shift << 8;
184
185 for (frame = 0; frame != work->effect->count * 20 + 72; frame++) {
186 // Frame loop: 20 frames a target and 72 more, though only the first
187 // target is drawn.
188 if (frame == 64)
190 // Red, green and blue sway a third of a turn apart.
191 Graphics_UpdatePhasePalette(frame, 0xaaab, 0x5555, 0);
192
193 // The Djinni sways 20 pixels either way and from frame 32 rises 2
194 // pixels a frame.
195 if (work->effect->prelude == 1) {
196 s32 x;
197 s32 y;
198
199 x = ((Trig_Sin(frame << 11) * 20) >> 16) + originX + shift - 20;
200 y = (((Trig_Cos(frame << 11) * 4)) >> 16) + originY - 24;
202 if (frame > 32)
203 y = y - frame * 2 + 64;
204 draw[0](canvas, work->sheet + 0x2000, x, y, 40, 40);
205 if (frame <= 3)
206 draw[1](canvas, work->sheet + 0x2000, x, y, 40, 40);
208 }
209 // The blitters, plain and mirrored, keeping the brighter pixel; from
210 // frame 32 the canvas darkens one level faster every 16 frames.
216 if (frame > 16 && (frame & 15) == 0)
217 work->transferValue += 0x01010101;
218
219 // Only the first target is drawn.
220 for (member = 0; member != 1; member++) {
221 tick = frame - member * 8;
222 object = GetBattleObjectSlotFar(work->effect->actors[member])->object;
223 if (tick >= 0 && tick < 96) {
225 position.world.x = object->x;
226 position.world.y = object->y;
227 position.world.z = object->z;
228 EffectPosition_ProjectPoint(&position.world, &screen);
229 // Always canvas x 64, where BG2X puts the target; only the
230 // projected y is kept.
231 screen.x = anchor.x + shift;
232 screen.y -= 24;
233 // The triangle: its three corners, turned a third of a circle apart and
234 // shrinking as they spin, are projected into the particles' velocity
235 // fields; each side is 24 flares. Over 64 frames the scale falls from
236 // 2.625 by 3/128 a frame while its roll and yaw turn steadily back
237 // to 0; frames 64 to 67 hold it still.
238 if (tick <= 67) {
239 for (j = 0; j != 3; j++) {
240 point = &work->particles[member * 32 + j];
242 if (tick <= 63) {
243 scale.x = 0x2a000 - (tick * 3 << 9);
244 scale.y = 0x2a000 - (tick * 3 << 9);
245 scale.z = 0x2a000 - (tick * 3 << 9);
247 SceneTransform_ApplyRoll((64 - tick) << 9);
248 SceneTransform_ApplyYaw((64 - tick) << 9);
249 }
250 SceneTransform_ApplyRoll(j * 0x5555);
251 EffectPosition_ProjectPoint(gBind_Vertex, &position.projected);
252 point->velocityX = position.projected.x + screen.x;
253 point->velocityY = position.projected.y + screen.y + 16;
254 }
255 for (j = 0; j != 3; j++) {
256 struct EffectStep *from = &work->particles[j + member * 32];
257 struct EffectStep *to = &work->particles[(j + 1) % 3 + member * 32];
258
259 // Flares shrink from size 5 to 1, a size every 16 frames.
260 size = 5 - tick / 16;
261 for (k = 0; k != 24; k++) {
262 s32 x =
263 from->velocityX + k * (to->velocityX - from->velocityX) / 24;
264 s32 y =
265 from->velocityY + k * (to->velocityY - from->velocityY) / 24;
266
267 draw[0](canvas,
268 work->sheet + gBattleFx_FlareCells[size - 1] + 0x1000,
269 x - size, y - size, size * 2, size * 2);
270 }
271 }
272 }
273 // Then the rune, in two mirrored halves.
274 if (tick > 63) {
275 draw[0](canvas, work->sheet, screen.x - 24, screen.y - 24, 24, 48);
276 draw[1](canvas, work->sheet, screen.x, screen.y - 24, 24, 48);
277 }
278 }
279 }
282 }
283
284 // Finish: the blitters were freed each frame.
287}
288
289/// The spinning triangle and rune of BattleFx_RunBind without the Djinni; on
290/// frame 46 the user steps up to the first target.
291///
292/// Abilities: none (kind 67).
293///
294/// Its own vertex, gBind_TriangleStrikeVertex, sets the triangle's size.
295/// Changes the same state as BattleFx_RunBind, on the narrow canvas, and
296/// starts the user's approach through BattleMotion_ApproachTargetFar.
298 struct EffectPosition anchor;
299 // World input and projected vertices reuse one coordinate workspace.
300 union {
301 struct Vector3 world;
302 struct EffectPosition projected;
303 } position;
304 struct EffectPosition screen;
305 struct Vector3 scale;
306 void **slots;
307 void **cursor;
308 struct BattleEffectWork *work;
309 void *canvas;
310 s32 frame;
311 BlitterPair draw;
312 s32 member;
313 struct BattleCamera *camera;
314 s32 shift;
315 u8 *graphics;
316 u8 *palette;
317 struct MotionObject *object;
318 s32 tick;
319 struct EffectStep *point;
320 s32 size;
321 s32 j;
322 s32 k;
323
325 cursor = slots;
326 EFFECT_GET_WORK_AND_CANVAS(cursor, work, canvas);
327 graphics = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
328 camera = WORK_SLOT(HEAP_SLOT_CAMERA);
329 work->effect = effect;
331
332 // Setup, as for Bind: the rune, and the flares at 0x1000.
334 Iwram_CopyWords((void *)BG_PLTT, palette, 128);
335 palette += 128;
336 Resource_DecodeType01(palette, work->sheet);
340 Resource_DecodeType01(palette, work->sheet + 0x1000);
341 // 4 off every pixel each frame.
344 shift = 64 - anchor.x;
345 REG_BG2X = shift << 8;
347
348 for (frame = 0; frame != work->effect->count * 20 + 72; frame++) {
349 // Frame loop, as in BattleFx_RunBind.
350 if (frame == 64)
352 if (frame == 46)
354 work->effect->actors[0], 16, 0);
355 Graphics_UpdatePhasePalette(frame, 0xaaab, 0x5555, 0);
361 if (frame > 16 && (frame & 15) == 0)
362 work->transferValue += 0x01010101;
363
364 // Only the first target is drawn.
365 for (member = 0; member != 1; member++) {
366 tick = frame - member * 8;
367 object = GetBattleObjectSlotFar(work->effect->actors[member])->object;
368 if (tick >= 0 && tick < 96) {
370 position.world.x = object->x;
371 position.world.y = object->y;
372 position.world.z = object->z;
373 EffectPosition_ProjectPoint(&position.world, &screen);
374 screen.x = anchor.x + shift;
375 screen.y -= 24;
376 if (tick <= 67) {
377 for (j = 0; j != 3; j++) {
378 point = &work->particles[member * 32 + j];
380 if (tick <= 63) {
381 scale.x = 0x2a000 - (tick * 3 << 9);
382 scale.y = 0x2a000 - (tick * 3 << 9);
383 scale.z = 0x2a000 - (tick * 3 << 9);
385 SceneTransform_ApplyRoll((64 - tick) << 9);
386 SceneTransform_ApplyYaw((64 - tick) << 9);
387 }
388 SceneTransform_ApplyRoll(j * 0x5555);
390 &position.projected);
391 point->velocityX = position.projected.x + screen.x;
392 point->velocityY = position.projected.y + screen.y + 16;
393 }
394 for (j = 0; j != 3; j++) {
395 struct EffectStep *from = &work->particles[j + member * 32];
396 struct EffectStep *to = &work->particles[(j + 1) % 3 + member * 32];
397
398 size = 5 - tick / 16;
399 for (k = 0; k != 24; k++) {
400 s32 x =
401 from->velocityX + k * (to->velocityX - from->velocityX) / 24;
402 s32 y =
403 from->velocityY + k * (to->velocityY - from->velocityY) / 24;
404
405 draw[0](canvas,
406 work->sheet + gBattleFx_FlareCells[size - 1] + 0x1000,
407 x - size, y - size, size * 2, size * 2);
408 }
409 }
410 }
411 // Then the rune, in two mirrored halves.
412 if (tick > 63) {
413 draw[0](canvas, work->sheet, screen.x - 24, screen.y - 24, 24, 48);
414 draw[1](canvas, work->sheet, screen.x, screen.y - 24, 24, 48);
415 }
416 }
417 }
420 }
421
424}
@ COMPOSITE_FLIP_X
@ COMPOSITE_MAX
BattleEffectDrawRectangle DrawRectangle
void BattleFx_RunBind(struct BattleEffectArgument *effect)
A triangle of light spins and shrinks onto the first target for 64 frames, then a rune stands on the ...
Definition bind.c:123
void BattleFx_RunTriangleStrike(struct BattleEffectArgument *effect)
The spinning triangle and rune of BattleFx_RunBind without the Djinni; on frame 46 the user steps up ...
Definition bind.c:297
UNUSED void Graphics_ConvertBackgroundToBlueRamp(void)
Turns the screen into shades of blue, top down, with a ragged edge.
Definition bind.c:27
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
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,...
#define BLUE_RAMP_PIXELS
The full-screen picture Graphics_ConvertBackgroundToBlueRamp (bind.c) works on, which Condemn draws t...
@ CANVAS_COPY_AND_DARKEN
copy, then darken the canvas by transferValue
#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_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_VIEW_FROM_CAMERA(camera)
Starts a frame's 3D projection from the battle camera: resets the transform, then looks from camera->...
#define EFFECT_BEGIN_NARROW_CANVAS(bgControl)
Opens the canvas layer at the canvas's own width, one texel per pixel, where BattleFx_BeginCanvasLaye...
struct Vector3 gBind_Vertex[]
The spinning triangle's first vertex, 24 up from its centre.
u16 gBattleFx_FlareCells[]
Flare cells: the first ten are squares 2x2 to 20x20, cell n (from 0) n + 1 pixels from its centre to ...
struct Vector3 gBind_TriangleStrikeVertex[]
The striking triangle's first vertex, the same.
struct BattleObj * GetBattleObjectSlotFar(s32 objectId)
Far call to BattleObjGet.
void BattleMotion_ApproachTargetFar(s32 actorId, s32 targetId, s32 travel_divisor, s32 initial_velocity_y)
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
@ 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_CAMERA
Definition heap_state.h:38
@ HEAP_SLOT_BLITTER
Definition heap_state.h:46
#define WORK_SLOT(n)
Reads slots through their own addresses; adjacent slots are reached by offsets.
Definition heap_state.h:14
#define Q_8_8(n)
The BG2/BG3 affine matrix entries are signed 8.8 fixed point: texels stepped per screen pixel.
Definition io_reg.h:59
#define RGB(r, g, b)
A 15-bit colour from its red, green and blue levels (0 to 31 each), as the palette stores it: blue in...
Definition io_reg.h:164
#define BG_CHAR_BLOCK(n)
Definition io_reg.h:166
#define REG_BG2X
Definition io_reg.h:65
#define BG_PLTT
Definition io_reg.h:157
#define REG_BG2PA
Definition io_reg.h:61
#define BG_PLTT_COLOR(palette, color)
Definition io_reg.h:158
static s32 Iwram_CopyWords(volatile void *destination, const volatile void *source, s32 size)
Definition iwram_call.h:85
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 EffectPosition_ProjectScaledBattler(s32 id, struct EffectPosition *position)
The screen position of a battler, scaled for the battle view, 16 pixels higher.
Definition positions.c:88
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
void Graphics_UpdatePhasePalette(s32 frame, s32 redPhase, s32 greenPhase, s32 bluePhase)
Rebuilds the background palette's first ramp as a grey ramp whose red, green and blue each sway with ...
Definition prism.c:183
void BattleFx_RunDjinniEntrance(struct BattleEffectArgument *effect, s32 mode, s32 side, s32 anchor, s32 *outX, s32 *outY)
Djinni entrance: sparks swirl around a point that travels from the user to the goal and gather into t...
Definition projectiles.c:29
char ResourceId_ParticleSpritesD
char ResourceId_ParticleSpritesA
char ResourceId_JupiterDjinnSheet
char ResourceId_RuneSheet
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_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define SE_142
Definition songs.h:135
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 count
targets in actors, at least 1
s32 prelude
1 plays a prelude: in some effects a Djinni appears
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 transferValue
The transfer mode's argument: the fill value, the share kept (50 or 75 percent) or the darken or brig...
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 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 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
Three coordinates, x, y and z: a position, a velocity or a direction.
Definition vector3.h:11
s32 z
Definition vector3.h:24
s32 x
Definition vector3.h:22
s32 y
Definition vector3.h:23
void * Resource_GetTableEntry(s32 index)
Returns the ROM address of resource index from the resource directory.
Definition system.c:150
void SceneTransform_ApplyYaw(s32 angle)
Rotates gTransform about the Y axis by angle.
Definition transform.c:113
void Render_ResetTransformState(void)
Allocates the one-level save area (heap slot HEAP_SLOT_TRANSFORM_STACK), clears gTransformStackDepth ...
Definition transform.c:19
void SceneTransform_ApplyScale(const s32 *scale)
Scales gTransform by scale (x, y, z factors in 16.16).
Definition transform.c:158
void SceneTransform_ApplyRoll(s32 angle)
Rotates gTransform about the Z axis by angle.
Definition transform.c:129
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
signed short s16
Definition types.h:12
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
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
static const s32 * Vector3_Coordinates(const struct Vector3 *vector)
Returns the vector's three coordinates as an array.
Definition vector3.h:31