Alchemy
Loading...
Searching...
No Matches

fire.c

Go to the documentation of this file.
1/// @file
2/// Fire.
3/// Part of effect.c, the battle effect object, compiled only through it.
4
6
7/// The embers set up in PARTICLES: no row of gFire_Counts may ask for more.
8#define FIRE_EMBERS 64
9
10/// Homing embers: embers burst from the top of the user two a frame, turn
11/// towards the targets 48 frames after they appear, and each one that hits the
12/// ground shows an impact flare for 12 frames as its target flinches.
13///
14/// Abilities: Fire, Fireball, Inferno (kind 12).
15///
16/// The camera swings round over frames 17 to 79, and the battle shows the
17/// damage 24 frames before the end.
18///
19/// Schedules Camera_ApplyPhasedDelta for the swing and drives it through
20/// work->cameraDelta and work->cameraPhase; sets work->shakeFrames on each hit
21/// and writes REG_BLDALPHA. Ends with both callbacks removed, the blitters
22/// freed and the canvas layer closed.
23///
24/// effect: the targets; variant picks the number of embers
25/// (gFire_Counts).
27 void **slots;
28 void **cursor;
29 struct BattleEffectWork *work;
30 void *canvas;
31 s32 frame;
32 struct BattleCamera *camera;
33 u8 *sheet;
34 s32 bodyTop;
35 struct EffectPosition screen;
36 BlitterPair draw;
37 struct MotionObject *user;
38 s32 i;
39
41 cursor = slots;
42 EFFECT_GET_WORK_AND_CANVAS(cursor, work, canvas);
43 camera = ((struct BattleCamera *)WORK_SLOT(HEAP_SLOT_CAMERA));
44 // The motes are in the battle sheet's slot; work->sheet holds the flares.
45 sheet = EFFECT_SLOT(slots, HEAP_SLOT_BATTLE_SHEET);
46 work->effect = effect;
47 if (effect->side == 1)
49 else
52 1);
60 REG_BLDALPHA = BLEND_ALPHA(16, 16);
61
62 // The embers leave the top of the user's body in a random direction and
63 // speed, rising at -16 to 111 sixty-fourths of a pixel a frame.
65 bodyTop = user->y + BattleUnit_GetEffectHeightFar(work->effect->actor);
66 for (i = 0; i != FIRE_EMBERS; i++) {
67 struct EffectStep *ember = &PARTICLES[i];
68 s32 angle;
69 s32 speed;
70
71 angle = Random16();
72 speed = (Random16() & 127) + 127;
73 SET_VELOCITY(ember, (Trig_Sin(angle) * speed) >> 6,
74 (s32)(((Random16() & 127) - 16) << 16) >> 6,
75 (Trig_Cos(angle) * speed) >> 6);
76 SET_POSITION(ember, user->x, bodyTop, user->z);
77 // -1 in flight, then the frames of the impact flare.
78 ember->variant = -1;
79 }
80
81 work->cameraDelta = 0;
82 work->cameraPhase = 0;
84 // Each transfer keeps three quarters of every level, for long trails.
86
87 // The last ember launches on frame count / 2; the effect runs 132 frames
88 // past that.
89 for (frame = 0; frame != (gFire_Counts[work->effect->variant] >> 1) + 132;
90 frame++) {
91 // The camera turns 0x100 of yaw a frame over frames 17 to 79.
92 if (frame > 16 && frame < 80)
93 work->cameraDelta = 0x100;
94 else
95 work->cameraDelta = 0;
96 if (frame == (gFire_Counts[work->effect->variant] >> 1) + 108)
98 // Re-centre the camera's focus at full zoom, then project from it.
101
102 // The embers in flight: two launch each frame, ember i after frame i / 2.
103 for (i = 0; i != gFire_Counts[work->effect->variant]; i++) {
104 struct EffectStep *ember = &PARTICLES[i];
105 s32 launchFrame;
106
107 launchFrame = i / 2;
108 if (frame > launchFrame && ember->variant == -1) {
109 s32 size;
110
111 // Size 10 to 1 over depths 160 to 799; maximum blend for the first 48
112 // frames, additive after.
113 EffectPosition_ProjectPoint(ember, &screen);
114 screen.x >>= 1;
115 CLAMP(screen.depth, 160, 799);
116 size = 10 - (screen.depth - 160) / 64;
117 EFFECT_DRAW_MOTE(draw[frame < launchFrame + 48 ? 1 : 0], canvas, sheet,
118 screen.x, screen.y, size);
119 ember->x += ember->velocityX;
120 ember->y += ember->velocityY;
121 ember->z += ember->velocityZ;
122 }
123
124 // Accelerate towards the target by 1/512 of the distance, damping the
125 // speed to 60/64 until 85 frames after the ember appeared. Embers are
126 // dealt to the targets in turn (i % count).
127 if (frame > launchFrame + 48 && ember->variant == -1) {
128 struct MotionObject *target;
129 s32 vx;
130 s32 vy;
131 s32 vz;
132
133 target = GetBattleObjectSlotFar(
134 work->effect->actors[i % work->effect->count])
135 ->object;
136 vx = ember->velocityX += (target->x - ember->x) >> 9;
137 vy = ember->velocityY += (target->y - ember->y) >> 9;
138 vz = ember->velocityZ += (target->z - ember->z) >> 9;
139 if (frame < launchFrame + 85) {
140 SET_VELOCITY(ember, vx * 60 / 64, vy * 60 / 64, vz * 60 / 64);
141 }
142
143 // Below the ground it hits: keep its screen position (from this
144 // frame's drawing above) for the impact flare, tint the target red in
145 // its damage pose for 4 frames, and shake the screen for 2 frames.
146 if (ember->y < 0) {
147 ember->variant = 0;
148 ember->x = screen.x;
149 ember->y = screen.y;
152 work->effect->actors[i % work->effect->count],
154 work->shakeFrames = 2;
155 }
156 }
157 }
158
159 // The impact flares: six pictures, 2 frames each, drawn 56 pixels
160 // higher than where the ember hit.
161 for (i = 0; i != gFire_Counts[work->effect->variant]; i++) {
162 struct EffectStep *ember = &PARTICLES[i];
163
164 if (ember->variant >= 0 && ember->variant < 12) {
165 s32 cell;
166 u32 width;
167
168 cell = ember->variant / 2;
169 // UB: width is assigned in one argument and read in another.
170#ifdef UBFIX
171 width = gFire_FlareWidths[cell];
172 draw[1](canvas, work->sheet + gFire_FlareCells[cell],
173 ember->x - (width >> 1), ember->y + gFire_FlareBiasY[cell] - 56,
174 width, gFire_FlareHeights[cell]);
175#else
176 draw[1](canvas, work->sheet + gFire_FlareCells[cell],
177 ember->x - ((width = gFire_FlareWidths[cell]) >> 1),
178 ember->y + gFire_FlareBiasY[cell] - 56, width,
179 gFire_FlareHeights[cell]);
180#endif
181 ember->variant++;
182 }
183 }
184
185 // Tell Camera_ApplyPhasedDelta a frame has passed.
186 if (work->cameraPhase == 0)
187 work->cameraPhase = 1;
188 Camera_ApplyShake(8, 8);
189 EFFECT_END_FRAME(work);
190 }
191
196}
197
198#undef FIRE_EMBERS
@ SPRITE_COLOR_RED_TINT
red raised to full
Definition animspr.h:28
@ POSE_DAMAGE
taking damage
Definition battle.h:176
@ COMPOSITE_ADDITIVE
@ COMPOSITE_MAX
BattleEffectDrawRectangle DrawRectangle
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
void Resource_LoadAndDecompress(s32 id, void *dst, s32 skipPalette, s32 copyPalette)
Decompresses a resource whose first 128 bytes may be a palette.
void Camera_ApplyPhasedDelta(void)
Turns the battle camera by cameraDelta.
Definition djinn_heal.c:230
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_RELEASE_BLITTERS()
Frees the two blitters, the alternate first.
#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_GET_WORK_AND_CANVAS(cursor, work, canvas)
The work block and canvas occupy adjacent slots, starting at HEAP_SLOT_BATTLE_EFFECT.
#define EFFECT_CALLBACK_ORDER
The scheduler order of every per-frame effect callback (Scheduler_AddOrUpdateCallback sorts the 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_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_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 gFire_FlareHeights[]
u8 gFire_Counts[]
Embers by variant, at most FIRE_EMBERS (fire.c).
u8 gFire_FlareBiasY[]
u16 gFire_FlareCells[]
u8 gFire_FlareWidths[]
struct BattleObj * GetBattleObjectSlotFar(s32 objectId)
Far call to BattleObjGet.
void BattlePres_SetupTransitionSceneFar(s32 x, s32 depth, s32 y, s32 zoom)
s32 BattleUnit_GetEffectHeightFar(s32 id)
void AudioCommand_PlayFar(s32 id)
void BattleFx_RunFire(struct BattleEffectArgument *effect)
Homing embers: embers burst from the top of the user two a frame, turn towards the targets 48 frames ...
Definition fire.c:26
#define FIRE_EMBERS
The embers set up in PARTICLES: no row of gFire_Counts may ask for more.
Definition fire.c:8
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_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 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
#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 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
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_ParticleSpritesA
char ResourceId_EmberStreakSheet
s32 Scheduler_AddOrUpdateCallback(SchedulerCallback callback, s32 order)
Schedules callback with order, or gives a task already running it the new order, and re-sorts the tab...
Definition scheduler.c:102
s32 Scheduler_RemoveCallback(SchedulerCallback callback)
Unschedules the task running callback: clears its routine and gives it order 0x7fff,...
Definition scheduler.c:146
#define SE_133
Definition songs.h:126
#define SE_136
Definition songs.h:129
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 variant
the ability's size, from 0 (Quake, then Earthquake)
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 frame
frame counter some effects keep, from 0
s32 cameraDelta
camera yaw turned per effect frame
s32 shakeFrames
shake frames left; Camera_ApplyShake counts down
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 y
16.16 fixed-point pixels
Definition motobj.h:24
s32 x
16.16 fixed-point pixels
Definition motobj.h:23
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned char u8
Definition types.h:11
#define EFFECT_CLIP_BOUNDS
Clips overflow on all four sides.
Definition effect.h:224
#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