Alchemy
Loading...
Searching...
No Matches

djinn_heal.c

Go to the documentation of this file.
1/// @file
2/// Djinn healing.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7#define DJINN_HEAL_SWIRL_FRAMES 98 ///< frames of the swirl
8#define DJINN_HEAL_SWIRL_MOTES 32 ///< motes swirled in
9
10/// A small Mercury Djinni healing the party: the user glows while motes
11/// swirl round a point that rises from the user up to above the first
12/// target (frames 30 to 69); the Djinni appears there on frame 83. Then,
13/// for each target in turn, 8 frames apart, sparkles spiral in on it with
14/// the recovery sound and a glow, while the Djinni sways and finally flies
15/// off. No effect table entry points here, and nothing calls it.
16///
17/// PARTICLES 0 to 63 hold the swirl's motes (the first 32 drawn), then 0 to
18/// 511 the healing sparkles, 64 for each target; both are offsets from the
19/// point the transform is centred on, in 16.16. work->sheet holds the
20/// Djinni, the battle sheet slot first the motes and then the sparkle dots.
22 void **slots;
23 void **cursor;
24 struct BattleEffectWork *work;
25 void *canvas;
26 s32 member;
27 u8 *sheet;
28 DrawRectangle *draw;
29 struct MotionObject *actor;
30 struct MotionObject *goal;
31 s32 frame;
32 s32 i;
33 s32 position[3];
34 s32 target[3];
35 s32 delta[3];
36 s32 djinniPoint[3];
37 struct EffectPosition screen;
38 s32 point[3];
39 struct EffectPosition view;
40 BlitterPair callbacks;
41
42 EFFECT_GET_SLOTS(slots, cursor, work, canvas);
43 sheet = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
44 work->effect = effect;
47 work->sheet, 1, 1);
49 BattleFx_FetchRectangleBlitters(work->effect->side ^ 1, draw = callbacks);
51 goal = GetBattleObjectSlotFar(work->effect->actors[0])->object;
52 for (i = 0; i != 64; i++) {
53 struct EffectStep *spark = &PARTICLES[i];
54 s32 heading = Random16() & 0xffff;
55 s32 speed = (Random16() & 0xff) + 128;
56
57 SET_POSITION(spark, 0, ((Random16() & 31) + 20) << 16, 0);
58 SET_VELOCITY(spark, (Trig_Sin(heading) * speed) >> 5, 0,
59 (Trig_Cos(heading) * speed) >> 5);
60 spark->variant = 0;
61 }
62 // Trails keep 75% of each pixel a frame.
64
65 // The swirl: frame 8 plays its sound, frames 30 to 69 carry it from the
66 // user's feet to 90 pixels above the first target, frame 80 plays the
67 // Djinni's sound and frame 83 shows it. target keeps that point for the
68 // healing.
69 SET_VECTOR(position, actor->x, 0, actor->z);
70 SET_VECTOR(target, goal->x, 180 << 15, 0);
71 SET_VECTOR(delta, (target[0] - position[0]) / 40,
72 (target[1] - position[1]) / 40, (target[2] - position[2]) / 40);
73 for (frame = 0; frame != DJINN_HEAL_SWIRL_FRAMES; frame++) {
74 struct BattleCamera *camera = gCameraWork;
75 if (frame == 8)
77 if (frame == 80)
80 if (frame >= 30 && frame < 70) {
81 position[0] += delta[0];
82 position[1] += delta[1];
83 position[2] += delta[2];
84 }
86 // The user glows white for the first 24 frames.
87 if (frame == 0)
89 0);
90 if (frame == 24)
91 ObjectGroup_UpdateMembers(work->effect->actor, 0, -1, -1, 0);
92 // The swirl: 32 motes, mote i from frame i + 1, each turning about its
93 // own axis and, from 30 frames after it appears, pulled back into the
94 // centre. Their size runs 9 to 3 over depths 250 to 634.
95 for (i = 0; i != DJINN_HEAL_SWIRL_MOTES; i++) {
96 struct EffectStep *spark = &PARTICLES[i];
97 if (frame > i && spark->variant == 0) {
98 s32 size;
100 switch (i & 3) {
101 case 0:
102 SceneTransform_ApplyYaw(frame * (i * 32 + 256));
103 break;
104 case 1:
105 SceneTransform_ApplyPitch(-frame * (i * 32 + 256));
106 break;
107 case 2:
108 SceneTransform_ApplyRoll(-frame * (i * 32 + 256));
109 break;
110 case 3:
111 SceneTransform_ApplyPitch(-frame * (i * 32 + 256));
112 SceneTransform_ApplyRoll(-frame * (i * 32 + 256));
113 break;
114 }
115 EffectPosition_ProjectPoint(spark, &screen);
116 screen.x >>= 1;
118 CLAMP(screen.depth, 250, 634);
119 size = 9 - (screen.depth - 250) / 64;
120 EFFECT_DRAW_MOTE(callbacks[0], canvas, sheet, screen.x, screen.y, size);
122 if (frame > i + 30) {
123 s32 dx = -spark->x >> 8;
124 s32 dy = -spark->y >> 8;
125 s32 dz = -spark->z >> 8;
126
127 spark->velocityX += dx;
128 spark->velocityY += dy;
129 spark->velocityZ += dz;
130 }
131 }
132 }
133 // The Djinni appears at the swirl's centre, bobbing.
134 if (frame > 82) {
135 SET_VECTOR(djinniPoint, 0, (Trig_Sin(frame << 10) * 4), 0);
136 EffectPosition_ProjectPoint(djinniPoint, &screen);
137 screen.x >>= 1;
138 draw[1](canvas, work->sheet, screen.x - 10, screen.y - 17, 20, 34);
139 }
141 }
142 // The healing: sparkles scattered round each target, x and z within 64
143 // pixels and 32 to 95 up, as BattleFx_RunHealingMotes scatters them for
144 // Ply. Target n starts on frame n * 8; the last gets 72 frames.
145 for (i = 0; i != 512; i++) {
146 struct EffectStep *spark = &PARTICLES[i];
147 SET_POSITION(spark, ((Random16() & 0xff) - 127) << 15,
148 ((Random16() & 0x7f) + 64) << 15,
149 ((Random16() & 0xff) - 127) << 15);
150 spark->variant = 0;
151 }
153 for (frame = 0; frame != work->effect->count * 8 + 72; frame++) {
154 struct BattleCamera *camera = gCameraWork;
156 // The Djinni sways, and flies up and away for the last 32 frames.
157 if (frame >= work->effect->count * 8 + 40)
158 target[1] += 0x40000;
159 SET_VECTOR(point, target[0], target[1],
160 target[2] + Trig_Sin(frame << 11) * 40);
161 EffectPosition_ProjectPoint(point, &view);
162 view.x >>= 1;
163 callbacks[0](canvas, work->sheet, view.x - 10, view.y - 17, 20, 34);
164 EFFECT_FOR_EACH_TARGET(member, work->effect) {
165 struct MotionObject *object =
167 s32 start = member * 8;
169 SET_VECTOR(position, object->x, 160 << 14, object->z);
171 // 30 frames into its turn the target hears the recovery sound, and
172 // it glows from 40 to 64; its 64 sparkles spiral in, sparkle i from
173 // frame i / 2 + 1 of the turn, centred 40 pixels above it.
174 if (frame == start + 30)
176 if (frame == start + 40)
178 SPRITE_COLOR_WHITE, -1, -1, 0);
179 if (frame == start + 64)
180 ObjectGroup_UpdateMembers(work->effect->actors[member], 0, -1, -1, 0);
181 if (frame > start) {
182 SceneTransform_ApplyYaw((frame - start) << 9);
183 for (i = 0; i != 64; i++) {
184 struct EffectStep *spark = &PARTICLES[member * 64 + i];
185
186 if (frame > start + i / 2) {
187 s32 xx = (spark->x >> 8) * (spark->x >> 8);
188 s32 yy = (spark->y >> 8) * (spark->y >> 8);
189 s32 zz = (spark->z >> 8) * (spark->z >> 8);
190 s32 distance = Iwram_Sqrt(xx + yy + zz) >> 9;
191 if (distance != 0) {
192 s32 cellIndex;
193
194 EffectPosition_ProjectPoint(spark, &view);
195 view.x >>= 1;
196 CLAMP(view.depth, 314, 634);
197 /* FAKEMATCH: the size series A draws its sparks
198 * at, kept from that effect and never used here. Without the dead
199 * store: differ 479. */
200 cellIndex = 3 - (view.depth - 314) / 128;
201 cellIndex = (i * 4 + frame) % 9;
202 {
203 u8 *cell = sheet + gBattleFx_PuffCells[cellIndex];
204 u32 edge = gBattleFx_PuffSizes[cellIndex];
205 u32 half = edge >> 1;
206
207 draw[1](canvas, cell, view.x - half, view.y - half, edge, edge);
208 }
209 spark->x -= spark->x / distance;
210 spark->y -= spark->y / distance;
211 spark->z -= spark->z / distance;
212 }
213 }
214 }
215 }
216 }
218 }
220}
221
222/// Turns the battle camera by cameraDelta. The effect sets cameraPhase to 1
223/// after each of its frames; the callback then turns the whole delta once,
224/// and half of it on the frames in between, so the turn stays smooth whatever
225/// the effect's frame rate.
226///
227/// Runs each frame as a scheduler callback added by BattleFx_RunFire
228/// (fire.c) and BattleFx_RunFroth (vortices.c), which remove it before they
229/// return. Changes the camera slot's yaw and work->cameraPhase.
231 // Both come from the one slot table; a separate camera base compiles 4
232 // bytes longer.
233 void **slots = gWorkSlot + HEAP_SLOT_BATTLE_EFFECT;
234 struct BattleEffectWork *work = slots[0];
235 struct BattleCamera *camera = EFFECT_SLOT(slots, HEAP_SLOT_CAMERA);
236 s32 *phase = &work->cameraPhase;
237
238 if (*phase == 1) {
239 camera->yaw += work->cameraDelta;
240 *phase = 0;
241 } else {
242 camera->yaw += work->cameraDelta / 2;
243 if (*phase == 2)
244 *phase = 0;
245 else
246 *phase = 2;
247 }
248}
249
250#undef DJINN_HEAL_SWIRL_FRAMES
251#undef DJINN_HEAL_SWIRL_MOTES
@ SPRITE_COLOR_WHITE
solid colour 15, white
Definition animspr.h:26
struct BattleCamera * gCameraWork
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 Resource_LoadAndDecompress(s32 id, void *dst, s32 skipPalette, s32 copyPalette)
Decompresses a resource whose first 128 bytes may be a palette.
#define DJINN_HEAL_SWIRL_FRAMES
frames of the swirl
Definition djinn_heal.c:7
void Camera_ApplyPhasedDelta(void)
Turns the battle camera by cameraDelta.
Definition djinn_heal.c:230
UNUSED void BattleFx_RunDjinnHeal(struct BattleEffectArgument *effect)
A small Mercury Djinni healing the party: the user glows while motes swirl round a point that rises f...
Definition djinn_heal.c:21
#define DJINN_HEAL_SWIRL_MOTES
motes swirled in
Definition djinn_heal.c:8
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.
#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_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_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_VIEW_FROM_CAMERA(camera)
Starts a frame's 3D projection from the battle camera: resets the transform, then looks from camera->...
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.
struct BattleObj * GetBattleObjectSlotFar(s32 objectId)
Far call to BattleObjGet.
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
@ HEAP_SLOT_CAMERA
Definition heap_state.h:38
static s32 Iwram_Sqrt(s32 value)
Definition iwram_call.h:63
#define SET_VELOCITY(p, vx, vy, vz)
Definition macros.h:18
#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
#define CLAMP(v, low, high)
Keeps v within low to high, the low bound tested first.
Definition macros.h:23
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_AdvanceWithGravity3D(struct EffectStep *step, s32 damping, s32 gravity)
Moves a particle one frame in three dimensions: adds its velocity, then gravity to its vertical speed...
Definition positions.c:29
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_MercuryDjinnSmallSheet
char ResourceId_ParticleSpritesA
#define SE_RECOVERY
Definition songs.h:119
#define SE_142
Definition songs.h:135
#define SE_212
Definition songs.h:207
void * gWorkSlot[]
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 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
The running battle effect's work: its canvas image, 64 particles, the display registers it stages and...
s32 cameraDelta
camera yaw turned per effect frame
s32 cameraPhase
The effect sets 1 after a frame; Camera_ApplyPhasedDelta then turns the whole cameraDelta and sets 0,...
struct BattleEffectArgument * effect
the command being run
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 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
An effect object that moves and draws one sprite: its position, scale, velocity and target,...
Definition motobj.h:20
s32 z
16.16 fixed-point pixels
Definition motobj.h:25
s32 x
16.16 fixed-point pixels
Definition motobj.h:23
void SceneTransform_ApplyYaw(s32 angle)
Rotates gTransform about the Y axis by angle.
Definition transform.c:113
void SceneTransform_ApplyPitch(s32 angle)
Rotates gTransform about the X axis by angle.
Definition transform.c:97
void Transform_Pop(void)
Restores gTransform from the save area, if Transform_Push saved it.
Definition transform.c:49
void SceneTransform_ApplyPosition(const s32 *position)
Translates gTransform by position (x, y, z in 16.16).
Definition transform.c:145
void Transform_Push(void)
Saves gTransform into the save area (one level deep; a second save is ignored).
Definition transform.c:30
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
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11
#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