Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
FlyingMagikoopaAI.inc.c
Go to the documentation of this file.
1#include "common.h"
2#include "npc.h"
3
5
7 Enemy* enemy = script->owner1.enemy;
8 Npc* npc = get_npc_unsafe(enemy->npcID);
9
10 npc->duration = 30;
11 script->AI_TEMP_STATE = 11;
12}
13
14void N(FlyingMagikoopaAI_11)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* volume) {
15 Enemy* enemy = script->owner1.enemy;
16 Npc* npc = get_npc_unsafe(enemy->npcID);
17 f32 basePosY = (f32)enemy->varTable[1] / 100.0;
18 EffectInstance* emoteTemp;
19
20 npc->pos.y = basePosY + sin_deg(enemy->varTable[0]) * 6.0;
21 enemy->varTable[0] = clamp_angle(enemy->varTable[0] + 10);
22
23 if (N(MagikoopaAI_CanShootSpell)(script, aiSettings->chaseRadius, aiSettings->chaseOffsetDist, volume) == 1) {
24 fx_emote(0, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 15, &emoteTemp);
26 npc->duration = 50;
27 script->AI_TEMP_STATE = 20;
28 } else {
29 npc->duration--;
30 if (npc->duration <= 0) {
31 npc->duration = 5;
32 script->AI_TEMP_STATE = 15;
33 }
34 }
35}
36
43
45 f32 dist;
46 f32 distToHit;
47 f32 randomDist;
48 f32 baseYaw;
49 s32 isCCW;
50 f32 moveDist;
51 s32 angleAdjust;
52
53 Enemy* enemy = arg0->owner1.enemy;
54 Npc* npc = get_npc_unsafe(enemy->npcID);
55 f32 posX, posY, posZ;
56 s32 result = RESULT_SEARCHING;
57 s32 iterations = 0;
58
59 npc->duration--;
60 if (npc->duration <= 0) {
61 randomDist = rand_int(30) + 180.0;
62 isCCW = FALSE;
64 npc->yaw = atan2(npc->pos.x, npc->pos.z, enemy->territory->wander.centerPos.x, enemy->territory->wander.centerPos.z) - iterations;
65 moveDist = dist2D(npc->pos.x, npc->pos.z, enemy->territory->wander.centerPos.x, enemy->territory->wander.centerPos.z);
66 if (randomDist > moveDist) {
67 randomDist = moveDist;
68 }
69 } else {
70 npc->yaw = atan2(npc->pos.x, npc->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
71 if (npc->yaw < 180.0) {
72 baseYaw = (rand_int(10) + 90.0) - 5.0;
73 } else {
74 baseYaw = (rand_int(10) + 270.0) - 5.0;
75 }
76 angleAdjust = iterations * 5;
77 while (TRUE) {
78 if (isCCW) {
79 npc->yaw = baseYaw + angleAdjust;
80 } else {
81 npc->yaw = baseYaw - angleAdjust;
82 }
83 posX = npc->pos.x;
84 posY = npc->pos.y;
85 posZ = npc->pos.z;
86 if (npc_test_move_taller_with_slipping(0, &posX, &posY, &posZ,
87 randomDist, npc->yaw, npc->collisionHeight, npc->collisionDiameter)) {
88 moveDist = dist2D(npc->pos.x, npc->pos.z, posX, posZ);
89 distToHit = moveDist;
90 if (distToHit > 160.0) {
91 if (distToHit < randomDist) {
92 randomDist = distToHit;
93 }
94 result = RESULT_OK_BLOCKED;
95 }
96 } else {
97 result = RESULT_OK_CLEAR;
98 }
99
100 if (result != RESULT_SEARCHING) {
101 break;
102 }
103
104 if (!isCCW) {
105 isCCW = TRUE;
106 } else {
107 angleAdjust += 5;
108 iterations += 1;
109 isCCW = FALSE;
110 }
111
112 if (iterations >= 7) {
113 result = RESULT_NONE_FOUND;
114 }
115 }
116 }
117 posX = npc->pos.x;
118 posZ = npc->pos.z;
119 add_vec2D_polar(&posX, &posZ, randomDist, npc->yaw);
120 npc->moveToPos.x = posX;
121 npc->moveToPos.y = npc->pos.y;
122 npc->moveToPos.z = posZ;
123 enemy->varTable[4] = npc->pos.x * 100.0;
124 enemy->varTable[6] = npc->pos.z * 100.0;
125 enemy->varTable[3] = rand_int(10) + 35;
126 npc->duration = 0;
127 npc->moveSpeed = 3.0f;
128 npc->jumpVel = 1.4f;
129 npc->jumpScale = 0.2f;
130 arg0->functionTemp[0] = 0x10;
131 }
132}
133
134void N(FlyingMagikoopaAI_16)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
135 Enemy* enemy = script->owner1.enemy;
136 Npc* npc = get_npc_unsafe(enemy->npcID);
137 f32 basePosY = (f32)enemy->varTable[1] / 100.0;
138
139 enemy->varTable[0] = clamp_angle(enemy->varTable[0] + 10);
140 npc->pos.y = basePosY + sin_deg(enemy->varTable[0]) * 6.0;
141
142 if (npc->turnAroundYawAdjustment == 0) {
143 enemy->varTable[5] = npc->pos.y * 100.0;
144 script->functionTemp[0] = 17;
145 }
146}
147
148void N(FlyingMagikoopaAI_17)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
149 Enemy* enemy = script->owner1.enemy;
150 Npc* npc = get_npc_unsafe(enemy->npcID);
151 f32 limitY = (f32)enemy->varTable[1] / 100.0;
152 f32 basePosY = (f32)enemy->varTable[5] / 100.0;
153 f32 startX = (f32)enemy->varTable[4] / 100.0;
154 f32 startZ = (f32)enemy->varTable[6] / 100.0;
155 f32 lerpX = update_lerp(EASING_SIN_OUT, startX, npc->moveToPos.x, npc->duration, enemy->varTable[3]);
156 f32 lerpZ = update_lerp(EASING_SIN_OUT, startZ, npc->moveToPos.z, npc->duration, enemy->varTable[3]);
157
158 npc->pos.x = lerpX;
159 npc->pos.z = lerpZ;
160 npc->pos.y = basePosY + sin_deg((s32)(npc->duration * (180.0 / (f32)enemy->varTable[3])) + 180) * 25.0;
161
162 npc->duration++;
163 if (npc->duration == (enemy->varTable[3] - 8)) {
164 npc->yaw = atan2(npc->pos.x, npc->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
165 }
166 if (limitY <= npc->pos.y) {
167 npc->pos.y = limitY;
168 enemy->varTable[0] = 0;
169 script->functionTemp[0] = 10;
170 } else if (npc->duration >= enemy->varTable[3]) {
171 if (enemy->varTable[0] >= 180.0) {
172 if (enemy->varTable[0] < 270.0) {
173 enemy->varTable[0] = clamp_angle(540 - enemy->varTable[0]);
174 }
175 }
176 script->functionTemp[0] = 10;
177 }
178}
179
180void N(FlyingMagikoopaAI_20)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
181 Enemy* enemy = script->owner1.enemy;
182 Npc* npc = get_npc_unsafe(enemy->npcID);
183
184 npc->duration = 40;
185 script->functionTemp[0] = 21;
186}
187
188void N(FlyingMagikoopaAI_21)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
189 Enemy* enemy = script->owner1.enemy;
190 Npc* npc = get_npc_unsafe(enemy->npcID);
191 f32 posX, posY, posZ;
192 EffectInstance* emoteTemp;
193
194 npc->duration--;
195 if (npc->duration == 0) {
196 npc->curAnim = enemy->animList[0];
197 fx_emote(2, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 12, &emoteTemp);
198 npc->curAnim = enemy->animList[0];
199 npc->duration = 15;
200 script->functionTemp[0] = 50;
201 } else if ((N(MagikoopaAI_CanShootSpell)(script, aiSettings->chaseRadius, aiSettings->chaseOffsetDist, territory) == 1) && (npc->turnAroundYawAdjustment == 0)) {
202 ai_enemy_play_sound(npc, 0x20D4, 0);
203 npc->curAnim = enemy->animList[8];
204 posX = npc->pos.x;
205 posY = npc->pos.y + 29.0f;
206 posZ = npc->pos.z + 1.0f;
207 add_vec2D_polar(&posX, &posZ, 30.0f, 270.0f - npc->renderYaw);
208 fx_gather_energy_pink(0, posX, posY, posZ, 0.1f, 13);
209 npc->duration = 15;
210 script->functionTemp[0] = 22;
211 }
212}
213
214void N(FlyingMagikoopaAI_22)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
215 Enemy* enemy = script->owner1.enemy;
216 Npc* npc = get_npc_unsafe(enemy->npcID);
217
218 npc->duration--;
219 if (npc->duration <= 0) {
220 npc->curAnim = enemy->animList[9];
221 npc->duration = 7;
222 script->functionTemp[0] = 0x17;
223 }
224}
225
226void N(FlyingMagikoopaAI_23)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
227 Enemy* enemy = script->owner1.enemy;
228 Npc* npc = get_npc_unsafe(enemy->npcID);
229 s32 temp_s1;
230 EffectInstance* emoteTemp;
231
232 npc->duration--;
233 if (npc->duration <= 0) {
234 temp_s1 = N(MagikoopaAI_CanShootSpell)(script, aiSettings->chaseRadius, aiSettings->chaseOffsetDist, territory);
235 if (temp_s1 != 1) {
236 fx_emote(2, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 12, &emoteTemp);
237 npc->curAnim = enemy->animList[0];
238 npc->duration = 15;
239 script->functionTemp[0] = 50;
240 } else {
242 get_enemy(enemy->npcID + 1)->varTable[0] = temp_s1;
243 npc->duration = 20;
244 script->functionTemp[0] = 24;
245 }
246 }
247}
248
249void N(FlyingMagikoopaAI_24)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
250 Enemy* enemy = script->owner1.enemy;
251 Npc* npc = get_npc_unsafe(enemy->npcID);
252 f32 basePosY = (f32)enemy->varTable[1] / 100.0;
253
254 npc->pos.y = basePosY + sin_deg(enemy->varTable[0]) * 6.0;
255 enemy->varTable[0] = clamp_angle(enemy->varTable[0] + 10);
256
257 npc->duration--;
258 if (npc->duration <= 0) {
259 npc->curAnim = enemy->animList[0];
260 npc->duration = 3;
261 script->AI_TEMP_STATE = 50;
262 }
263}
264
265void N(FlyingMagikoopaAI_50)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
266 Enemy* enemy = script->owner1.enemy;
267 Npc* npc = get_npc_unsafe(enemy->npcID);
268 f32 basePosY = (f32)enemy->varTable[1] / 100.0;
269
270 npc->pos.y = basePosY + sin_deg(enemy->varTable[0]) * 6.0;
271 enemy->varTable[0] = clamp_angle(enemy->varTable[0] + 10);
272
273 npc->duration--;
274 if (npc->duration <= 0) {
275 script->AI_TEMP_STATE = 10;
276 }
277}
278
279API_CALLABLE(N(FlyingMagikoopaAI_Main)) {
280 Bytecode* args = script->ptrReadPos;
281 Enemy* enemy = script->owner1.enemy;
282 Npc* npc = get_npc_unsafe(enemy->npcID);
283 EnemyDetectVolume territory;
284 EnemyDetectVolume* territoryPtr = &territory;
285 MobileAISettings* aiSettings = (MobileAISettings*)evt_get_variable(script, *args++);
286
287 territory.skipPlayerDetectChance = 0;
288 territory.shape = enemy->territory->wander.detectShape;
289 territory.pointX = enemy->territory->wander.detectPos.x;
290 territory.pointZ = enemy->territory->wander.detectPos.z;
291 territory.sizeX = enemy->territory->wander.detectSize.x;
292 territory.sizeZ = enemy->territory->wander.detectSize.z;
293 territory.halfHeight = 120.0f;
294 territory.detectFlags = 0;
295
296 if (isInitialCall) {
297 npc->flags &= ~NPC_FLAG_GRAVITY;
298 npc->flags |= NPC_FLAG_FLYING;
301 enemy->varTable[1] = npc->pos.y * 100.0;
302 enemy->varTable[0] = 0;
303 enemy->varTable[2] = 0;
304 npc->duration = 0;
305 script->AI_TEMP_STATE = 10;
306 }
307
308 npc->verticalRenderOffset = -5;
309
310 if (enemy->aiFlags & AI_FLAG_SUSPEND) {
311 if (enemy->aiSuspendTime != 0) {
312 return ApiStatus_BLOCK;
313 }
314 enemy->aiFlags &= ~AI_FLAG_SUSPEND;
315 }
316
317 switch (script->AI_TEMP_STATE) {
318 case 10:
319 N(FlyingMagikoopaAI_10)(script, aiSettings, territoryPtr);
320 // fallthrough
321 case 11:
322 N(FlyingMagikoopaAI_11)(script, aiSettings, territoryPtr);
323 break;
324 case 15:
325 N(FlyingMagikoopaAI_15)(script, aiSettings, territoryPtr);
326 if (script->AI_TEMP_STATE != 16) {
327 break;
328 }
329 case 16:
330 N(FlyingMagikoopaAI_16)(script, aiSettings, territoryPtr);
331 if (script->AI_TEMP_STATE != 17) {
332 break;
333 }
334 case 17:
335 N(FlyingMagikoopaAI_17)(script, aiSettings, territoryPtr);
336 break;
337 case 20:
338 N(FlyingMagikoopaAI_20)(script, aiSettings, territoryPtr);
339 break;
340 case 21:
341 N(FlyingMagikoopaAI_21)(script, aiSettings, territoryPtr);
342 break;
343 case 22:
344 N(FlyingMagikoopaAI_22)(script, aiSettings, territoryPtr);
345 break;
346 case 23:
347 N(FlyingMagikoopaAI_23)(script, aiSettings, territoryPtr);
348 if (script->AI_TEMP_STATE != 24) {
349 break;
350 }
351 case 24:
352 N(FlyingMagikoopaAI_24)(script, aiSettings, territoryPtr);
353 break;
354 case 50:
355 N(FlyingMagikoopaAI_50)(script, aiSettings, territoryPtr);
356 break;
357 }
358 return ApiStatus_BLOCK;
359}
360
361API_CALLABLE(N(FlyingMagikoopaAI_OnHitInit)) {
362 Enemy* enemy = script->owner1.enemy;
363
365 return ApiStatus_DONE2;
366}
367
368API_CALLABLE(N(FlyingMagikoopaAI_OnHit)) {
369 Enemy* enemy = script->owner1.enemy;
370 Npc* npc = get_npc_unsafe(enemy->npcID);
371
372 if (enemy->varTable[0] == 2) {
373 npc->jumpVel = 0.0f;
374 npc->moveSpeed = 0.0f;
375 }
376 return ApiStatus_DONE2;
377}
378
void N FlyingMagikoopaAI_22(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N FlyingMagikoopaAI_10(Evt *script, MobileAISettings *arg1, EnemyDetectVolume *arg2)
void N FlyingMagikoopaAI_24(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N FlyingMagikoopaAI_23(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N FlyingMagikoopaAI_16(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N FlyingMagikoopaAI_50(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
MagikoopaMoveResult
@ RESULT_OK_BLOCKED
@ RESULT_OK_CLEAR
@ RESULT_NONE_FOUND
@ RESULT_SEARCHING
void N FlyingMagikoopaAI_11(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *volume)
void N FlyingMagikoopaAI_20(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N FlyingMagikoopaAI_17(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N FlyingMagikoopaAI_15(Evt *arg0, MobileAISettings *arg1, EnemyDetectVolume *arg2)
void N FlyingMagikoopaAI_21(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
s32 N MagikoopaAI_CanShootSpell(Evt *script, f32 arg1, f32 arg2, EnemyDetectVolume *territory)
Vec3s pos
Definition demo_api.c:17
#define sin_deg
#define rand_int
#define clamp_angle
#define atan2
@ AI_FLAG_SUSPEND
Definition enums.h:4571
@ ENEMY_FLAG_ACTIVE_WHILE_OFFSCREEN
Definition enums.h:4542
@ EASING_SIN_OUT
Definition enums.h:521
@ SOUND_SPELL_CAST2
Definition enums.h:1499
@ SOUND_AI_ALERT_A
Definition enums.h:1078
@ SOUND_PARAM_MORE_QUIET
Definition enums.h:1746
@ NPC_FLAG_FLYING
Definition enums.h:3001
@ NPC_FLAG_FLIP_INSTANTLY
Definition enums.h:3019
#define ApiStatus_DONE2
Definition evt.h:118
s32 Bytecode
Definition evt.h:7
#define ApiStatus_BLOCK
Definition evt.h:116
s32 evt_get_variable(Evt *script, Bytecode var)
Definition evt.c:1690
f32 update_lerp(s32 easing, f32 start, f32 end, s32 elapsed, s32 duration)
Definition 43F0.c:735
b32 is_point_outside_territory(s32 shape, f32 centerX, f32 centerZ, f32 pointX, f32 pointZ, f32 sizeX, f32 sizeZ)
Definition 23680.c:412
void ai_enemy_play_sound(Npc *npc, s32 arg1, s32 arg2)
Definition 23680.c:543
s32 evt_set_variable(Evt *script, Bytecode var, s32 value)
Definition evt.c:1847
f32 dist2D(f32 ax, f32 ay, f32 bx, f32 by)
Definition 43F0.c:670
b32 npc_test_move_taller_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
void add_vec2D_polar(f32 *x, f32 *y, f32 r, f32 theta)
Definition 43F0.c:685
enum TerritoryShape shape
Definition npc.h:201
s32 flags
Definition npc.h:295
VecXZi detectSize
Definition npc.h:216
enum TerritoryShape detectShape
Definition npc.h:217
s16 npcID
Definition npc.h:300
Enemy * get_enemy(s32 npcID)
Looks for an enemy matching the specified npcID.
Definition npc.c:2540
s32 * animList
Definition npc.h:341
Enemy * curEnemy
Definition npc.h:394
VecXZi wanderSize
Definition npc.h:212
s8 aiSuspendTime
Definition npc.h:333
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:995
s16 detectFlags
Definition npc.h:207
EncounterStatus gCurrentEncounter
Definition encounter.c:176
enum TerritoryShape wanderShape
Definition npc.h:214
u32 aiFlags
Definition npc.h:332
s32 skipPlayerDetectChance
Definition npc.h:200
EnemyTerritoryWander wander
Definition npc.h:232
EnemyTerritory * territory
Definition npc.h:342
Definition npc.h:294
#define LVar0
Definition macros.h:148
s16 collisionDiameter
f32 jumpScale
f32 jumpVel
s32 flags
f32 renderYaw
AnimID curAnim
Vec3f moveToPos
s16 collisionHeight
s16 turnAroundYawAdjustment
s8 verticalRenderOffset
Vec3f pos
f32 moveSpeed
s16 duration
PlayerStatus * gPlayerStatusPtr