Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
tubba_heart_attack.c
Go to the documentation of this file.
1#include "common.h"
2#include "effects_internal.h"
3
15
16extern Gfx D_09000400_3D2980[];
17extern Gfx D_09000518_3D2A98[];
18
19u8 AnimScalePct[] = { 94, 92, 100, 105, 107, 105, 100 };
20
21u8 AppearScalePct[] = { 20, 40, 58, 73, 85, 92, 97, 100 };
22
24 0, 2, 5, 9, 14, 20, 27, 35, 44, 54,
25 64, 74, 84, 94, 100
26};
27
29 0, 10, 20, 30, 40, 50, 60, 70, 80, 90,
30 100, 109, 117, 124, 130, 135, 139, 142, 144, 145
31};
32
34 100, 100, 100, 100, 100, 100, 100, 100, 101, 102,
35 102, 103, 103, 104, 104, 104, 107, 107, 110, 110,
36 118, 118, 126, 126, 134, 142, 145, 145, 145, 142,
37 134, 126, 126, 118, 118, 110, 110, 105, 105, 105,
38 102, 103, 103, 104, 104, 104, 107, 107, 110, 110,
39 118, 118, 126, 126, 134, 142, 145, 145, 145, 142,
40 134, 126, 126, 118, 118, 110, 110, 105, 105, 105
41};
42
44 -5, -5, -5, -4, -4,
45 -4, -3, -3, -2, -2,
46 -1, -1, 0, 0, 1,
47 2, 2, 3, 3, 4,
48 4, 4, 5, 5, 5,
49};
50
54void tubba_heart_attack_appendGfx(void* effect);
55
57 s32 type,
58 f32 arg1,
59 f32 arg2,
60 f32 arg3,
61 f32 arg4,
62 s32 duration
63) {
65 EffectInstance* effect;
67 s32 numParts = 1;
68 s32 i;
69
73 bp.unk_00 = 0;
74 bp.renderUI = NULL;
75 bp.effectID = EFFECT_TUBBA_HEART_ATTACK;
76
77 effect = create_effect_instance(&bp);
78 effect->numParts = numParts;
79 data = effect->data.tubbaHeartAttack = general_heap_malloc(numParts * sizeof(*data));
80 ASSERT(effect->data.tubbaHeartAttack != NULL);
81
82 data->type = type;
83 data->lifetime = 0;
84 if (duration <= 0) {
85 data->timeLeft = 1000;
86 } else {
87 data->timeLeft = duration;
88 }
89 data->primA = 255;
90 data->centerX = arg1;
91 data->centerY = arg2;
92 data->centerZ = arg3;
93 data->overallScale = arg4;
94 data->primR = 70;
95 data->primG = 180;
96 data->primB = 120;
97
98 for (i = 0; i < TUBBA_MINI_HEART_COUNT; i++) {
99 f32 sin = sin_deg(i * 1080 / TUBBA_MINI_HEART_COUNT);
100 f32 cos = cos_deg(i * 1080 / TUBBA_MINI_HEART_COUNT);
101
102 data->rotZ[i] = rand_int(359) - 180;
103 data->finalX[i] = sin * 15.0f;
104 data->finalY[i] = HeartOffsetY[i] + 10;
105 data->finalZ[i] = cos * 15.0f;
106 data->initialX[i] = sin * 120.0f;
107 data->initialY[i] = HeartOffsetY[i] * 8 + 40;
108 data->initialZ[i] = cos * 120.0f;
109 data->appearDelay[i] = i * 2 + 1;
110 data->shrinkVelY[i] = 0;
111 data->state[i] = HEART_STATE_INIT;
112 data->stateTime[i] = 0;
113 data->rotXY[i] = 0;
114 }
115
116 return effect;
117}
118
121
123
126 EffectInstance* puffEffect;
127 s32 type = data->type;
128 s32 time;
129 f32 factor;
130 f32 angle;
131 f32 sin;
132 f32 cos;
133 Matrix4f mtx;
134 Matrix4f tempMtx;
135 s32 i;
136 s32 j;
137
138 if (effect->flags & FX_INSTANCE_FLAG_DISMISS) {
139 effect->flags &= ~FX_INSTANCE_FLAG_DISMISS;
140 data->timeLeft = 64;
141 }
142
143 if (data->timeLeft < 1000) {
144 data->timeLeft--;
145 }
146
147 data->lifetime++;
148
149 if (data->timeLeft < 0) {
150 remove_effect(effect);
151 return;
152 }
153
154 time = data->lifetime;
155
156 for (i = 0; i < TUBBA_MINI_HEART_COUNT; i++) {
157 f32 x = data->initialX[i];
158 f32 y = data->initialY[i];
159 f32 z = data->initialZ[i];
160
161 data->scaleY[i] = AnimScalePct[time % ARRAY_COUNT(AnimScalePct)] * 0.01f;
162 data->scaleX[i] = 2.0f - data->scaleY[i];
163
164 switch (data->state[i]) {
165 case HEART_STATE_INIT:
166 data->posX[i] = x;
167 data->posY[i] = y;
168 data->posZ[i] = z;
169 data->rotXY[i] += 0.0f;
170
171 if (data->appearDelay[i] != 0) {
172 data->appearDelay[i]--;
173 break;
174 }
175
176 data->state[i] = HEART_STATE_APPEAR;
177 data->scaleX[i] = data->scaleY[i] = AppearScalePct[data->stateTime[i]] * 0.01;
178 data->stateTime[i]++;
179 break;
181 data->scaleX[i] = data->scaleY[i] = AppearScalePct[data->stateTime[i]] * 0.01;
182 data->rotXY[i] += 0.0f;
183
184 data->stateTime[i]++;
185 if (data->stateTime[i] >= ARRAY_COUNT(AppearScalePct)) {
186 if (type == FX_HEART_SWARM_HIT) {
187 data->state[i] = HEART_STATE_SWARM;
188 } else {
189 data->state[i] = HEART_STATE_MISS;
190 }
191 data->stateTime[i] = 0;
192 }
193 break;
194 case HEART_STATE_MISS:
195 data->rotXY[i] += 0.0f;
196
197 factor = MissInterpPct[data->stateTime[i]] * 0.01;
198
199 data->scaleX[i] = data->scaleY[i] = 1.0f;
200 data->posX[i] = x + (data->finalX[i] - x) * factor;
201 data->posY[i] = y + (data->finalY[i] - y) * factor;
202 data->posZ[i] = z + (data->finalZ[i] - z) * factor;
203
204 data->stateTime[i]++;
205 if (data->stateTime[i] >= ARRAY_COUNT(MissInterpPct)) {
206 data->state[i] = HEART_STATE_DISPERSE;
207 data->stateTime[i] = 0;
208 data->shrinkVelX[i] = data->finalX[i] * 0.5;
209 data->shrinkVelY[i] = data->finalY[i] * 0.5;
210 data->shrinkVelZ[i] = data->finalZ[i] * 0.5;
211 }
212 break;
214 data->rotXY[i] += 0.0f;
215
216 factor = SwarmInterpPct[data->stateTime[i]] * 0.01;
217
218 data->scaleY[i] = 1.0f;
219 data->scaleX[i] = 1.0f;
220 data->posX[i] = x + (data->finalX[i] - x) * factor;
221 data->posY[i] = y + (data->finalY[i] - y) * factor;
222 data->posZ[i] = z + (data->finalZ[i] - z) * factor;
223
224 data->stateTime[i]++;
225 if (data->stateTime[i] >= ARRAY_COUNT(SwarmInterpPct)) {
226 data->state[i] = HEART_STATE_WAIT;
227 data->stateTime[i] = 0;
228 }
229 break;
230 case HEART_STATE_WAIT:
231 if (i == 24) {
232 for (j = 0; j < ARRAY_COUNT(data->state); j++) {
233 data->state[j] = HEART_STATE_SQUEEZE;
234 }
235 }
236 break;
238 factor = SqueezeInterpPct[data->stateTime[i]] * 0.01;
239 angle = i * 1080 / TUBBA_MINI_HEART_COUNT + (1.0f - factor) * 1080.0f * 0.5 * cos_deg(i * 180 / TUBBA_MINI_HEART_COUNT);
240 sin = sin_deg(angle);
241 cos = cos_deg(angle);
242
243 data->posX[i] = ((15.0f / factor) / factor) * sin;
244 data->posY[i] = HeartOffsetY[i] + 10;
245 data->posZ[i] = ((15.0f / factor) / factor) * cos;
246
247 data->stateTime[i]++;
248 if (data->stateTime[i] >= ARRAY_COUNT(SqueezeInterpPct)) {
249 data->state[i] = HEART_STATE_DISPERSE;
250 data->stateTime[i] = 0;
251 data->shrinkVelX[i] = data->finalX[i] * 0.5;
252 data->shrinkVelY[i] = data->finalY[i] * 0.5;
253 data->shrinkVelZ[i] = data->finalZ[i] * 0.5;
254 }
255 break;
257 data->posX[i] += data->shrinkVelX[i];
258 data->posY[i] += data->shrinkVelY[i];
259 data->posZ[i] += data->shrinkVelZ[i];
260 data->shrinkVelX[i] *= 0.99;
261 data->shrinkVelY[i] *= 0.99;
262 data->shrinkVelZ[i] *= 0.99;
263 data->shrinkVelY[i] += -0.1;
264
265 data->stateTime[i]++;
266 if (data->stateTime[i] >= 17) {
267 data->stateTime[i] = 0;
268 data->state[i] = HEART_STATE_VANISH;
269 }
270
271 data->rotZ[i] *= 0.9;
272 break;
274 load_effect(EFFECT_FLOATING_CLOUD_PUFF);
275 guRotateF(mtx, data->rotXY[i], 0.0f, 1.0f, 0.0f);
276 guTranslateF(tempMtx, data->posX[i], data->posY[i], data->posZ[i]);
277 guMtxCatF(tempMtx, mtx, mtx);
278
279 puffEffect = floating_cloud_puff_main(0, data->centerX + mtx[3][0], data->centerY + mtx[3][1], data->centerZ + mtx[3][2], 1.0f, 16);
280 puffEffect->data.floatingCloudPuff->unk_28 = 100;
281 puffEffect->data.floatingCloudPuff->unk_2C = 0;
282 puffEffect->data.floatingCloudPuff->unk_30 = 0;
283
284 data->state[i] = HEART_STATE_DONE;
285 break;
286 }
287 }
288}
289
291 RenderTask renderTask;
292 RenderTask* retTask;
293
295 renderTask.appendGfxArg = effect;
296 renderTask.dist = 10;
298
299 retTask = queue_render_task(&renderTask);
301}
302
303void func_E00CC9C8(void) {
304}
305
307 TubbaHeartAttackFXData* data = ((EffectInstance*)effect)->data.tubbaHeartAttack;
308 Camera* camera = &gCameras[gCurrentCameraID];
309 s32 alpha = data->primA;
310 Matrix4f sp18;
311 Matrix4f sp58;
312 s32 i;
313
314 gDPPipeSync(gMainGfxPos++);
315 gSPSegment(gMainGfxPos++, 0x09, VIRTUAL_TO_PHYSICAL(((EffectInstance*)effect)->graphics->data));
316
317 guTranslateF(sp18, data->centerX, data->centerY, data->centerZ);
318 guScaleF(sp58, data->overallScale, data->overallScale, data->overallScale);
319 guMtxCatF(sp58, sp18, sp18);
321
322 gSPMatrix(gMainGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
323 gDPSetPrimColor(gMainGfxPos++, 0, 0, data->primR, data->primG, data->primB, alpha);
324 gDPSetEnvColor(gMainGfxPos++, 0, 0, 0, 0);
325 gSPDisplayList(gMainGfxPos++, D_09000400_3D2980);
326
327 for (i = 0; i < TUBBA_MINI_HEART_COUNT; i++) {
328 if (data->state[i] != HEART_STATE_INIT && data->state[i] != HEART_STATE_DONE) {
329 guRotateF(sp18, data->rotXY[i], 0.0f, 1.0f, 0.0f);
330 guTranslateF(sp58, data->posX[i], data->posY[i], data->posZ[i]);
331 guMtxCatF(sp58, sp18, sp18);
332 guRotateF(sp58, -data->rotXY[i], 0.0f, 1.0f, 0.0f);
333 guMtxCatF(sp58, sp18, sp18);
334 guRotateF(sp58, data->rotZ[i], 0.0f, 0.0f, 1.0f);
335 guMtxCatF(sp58, sp18, sp18);
336 guScaleF(sp58, data->scaleX[i], data->scaleY[i], 1.0f);
337 guMtxCatF(sp58, sp18, sp18);
339
340 gSPMatrix(gMainGfxPos++, &gDisplayContext->matrixStack[gMatrixListPos++], G_MTX_PUSH | G_MTX_MUL | G_MTX_MODELVIEW);
341 gSPMatrix(gMainGfxPos++, camera->mtxBillboard, G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
342 gSPDisplayList(gMainGfxPos++, D_09000518_3D2A98);
343 gSPPopMatrix(gMainGfxPos++, G_MTX_MODELVIEW);
344 }
345 }
346
347 gSPPopMatrix(gMainGfxPos++, G_MTX_MODELVIEW);
348}
Mtx matrixStack[0x200]
f32 Matrix4f[4][4]
#define general_heap_malloc
#define guRotateF
#define queue_render_task
#define guMtxF2L
#define sin_deg
#define guTranslateF
#define guMtxCatF
#define remove_effect
#define rand_int
#define load_effect
#define cos_deg
#define create_effect_instance
#define guScaleF
#define TUBBA_MINI_HEART_COUNT
Definition effects.h:1797
struct TubbaHeartAttackFXData * tubbaHeartAttack
Definition effects.h:2566
@ FX_HEART_SWARM_HIT
Definition effects.h:1800
struct FloatingCloudPuffFXData * floatingCloudPuff
Definition effects.h:2569
EffectData data
Definition effects.h:2605
#define ASSERT(condition)
@ FX_INSTANCE_FLAG_DISMISS
Definition enums.h:3517
@ RENDER_TASK_FLAG_REFLECT_FLOOR
Definition enums.h:3318
@ RENDER_MODE_CLOUD_NO_ZCMP
Definition enums.h:3311
EffectInstance * floating_cloud_puff_main(s32 arg0, f32 arg1, f32 arg2, f32 arg3, f32 arg4, s32 arg5)
#define ARRAY_COUNT(arr)
Definition macros.h:40
#define VIRTUAL_TO_PHYSICAL(addr)
Definition macros.h:47
Mtx * mtxBillboard
void(* renderUI)(EffectInstance *effectInst)
Definition effects.h:2655
void(* init)(EffectInstance *effectInst)
Definition effects.h:2652
void(* update)(EffectInstance *effectInst)
Definition effects.h:2653
void(* renderWorld)(EffectInstance *effectInst)
Definition effects.h:2654
void * appendGfxArg
void(* appendGfx)(void *)
u8 SwarmInterpPct[]
u8 SqueezeInterpPct[]
void tubba_heart_attack_update(EffectInstance *effect)
void tubba_heart_attack_appendGfx(void *effect)
u8 AppearScalePct[]
EffectInstance * tubba_heart_attack_main(s32 type, f32 arg1, f32 arg2, f32 arg3, f32 arg4, s32 duration)
u8 AnimScalePct[]
MiniHeartState
@ HEART_STATE_MISS
@ HEART_STATE_DONE
@ HEART_STATE_SWARM
@ HEART_STATE_SQUEEZE
@ HEART_STATE_VANISH
@ HEART_STATE_INIT
@ HEART_STATE_WAIT
@ HEART_STATE_APPEAR
@ HEART_STATE_DISPERSE
Gfx D_09000518_3D2A98[]
u8 MissInterpPct[]
s8 HeartOffsetY[TUBBA_MINI_HEART_COUNT]
void tubba_heart_attack_init(EffectInstance *effect)
void func_E00CC9C8(void)
void tubba_heart_attack_render(EffectInstance *effect)
Gfx D_09000400_3D2980[]
EFFECT_DEF_FLOATING_CLOUD_PUFF(floating_cloud_puff_main)
Camera gCameras[4]
Definition cam_main.c:17
Gfx * gMainGfxPos
Definition cam_main.c:15
u16 gMatrixListPos
Definition main_loop.c:45
s32 gCurrentCameraID
Definition cam_math.c:4
DisplayContext * gDisplayContext
Definition cam_main.c:16