Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
ProjectileHitbox.inc.c
Go to the documentation of this file.
1#ifndef _AI_PROJECTILE_HITBOX_INC_
2#define _AI_PROJECTILE_HITBOX_INC_ 0
3
4#include "common.h"
5#include "npc.h"
6#include "effects.h"
7
9 Enemy* enemy = script->owner1.enemy;
10 Bytecode* args = script->ptrReadPos;
11 Camera* camera = &gCameras[gCurrentCamID];
12 Npc* npc = get_npc_unsafe(enemy->npcID);
13 MobileAISettings* aiSettings = (MobileAISettings*)evt_get_variable(script, *args++);
14 f32 facingAngle;
15 f32 angleToPlayer;
16 f32 deltaAngle;
17 s32 i;
18
19 if (ai_check_player_dist(enemy, 0, aiSettings->chaseRadius, aiSettings->chaseOffsetDist)) {
20 if (clamp_angle(get_clamped_angle_diff(camera->curYaw, npc->yaw)) < 180.0) {
21 facingAngle = 90.0f;
22 } else {
23 facingAngle = 270.0f;
24 }
25
26 angleToPlayer = atan2(npc->pos.x, npc->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
27 deltaAngle = get_clamped_angle_diff(facingAngle, angleToPlayer);
28 if (fabsf(deltaAngle) > 75.0 || (2.0 * npc->collisionHeight <= fabsf(npc->pos.y - gPlayerStatusPtr->pos.y))) {
29 return -1;
30 }
32 return -1;
33 }
35 return -1;
36 }
37
38 // choose the first idle projectile hitbox
39 for (i = 0; i < enemy->AI_PROJECTILE_AMMO_COUNT; i++) {
40 s32 projectileNpcID = enemy->npcID + i + 1;
41 Enemy* projectileEnemy = get_enemy(projectileNpcID);
42
43 get_npc_unsafe(projectileNpcID);
44
45 if (projectileEnemy->VAR_PROJECTILE_HITBOX_STATE == 0) {
46 return projectileNpcID;
47 }
48 }
49 }
50 return -1;
51}
52
53void N(UnkNpcAIFunc48)(Evt* script, f32 arg1, f32 arg2, EnemyDetectVolume* territory) {
54 Enemy* enemy = script->owner1.enemy;
55 Npc* npc = get_npc_unsafe(enemy->npcID);
56
57 if (basic_ai_check_player_dist(territory, enemy, arg1, arg2, 1) == 0) {
58 EffectInstance* sp28;
59
60 fx_emote(EMOTE_QUESTION, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 15, &sp28);
62 npc->duration = 20;
63 script->functionTemp[0] = 33;
64 } else {
65 s32 npcID = N(ProjectileHitbox_GetUsableProjectileID)(script);
66
67 if (npcID != NPC_SELF && get_enemy(npcID)->varTable[0] == 0 && npc->turnAroundYawAdjustment == 0) {
69 npc->duration = enemy->varTable[1];
70 script->functionTemp[0] = 30;
71 }
72 }
73}
74
75void N(ProjectileHitbox_30)(Evt* script) {
76 Enemy* enemy = script->owner1.enemy;
77 Npc* npc = get_npc_unsafe(enemy->npcID);
78 s32 npcID;
79
80 npc->duration--;
81 if (npc->duration <= 0) {
83 if (npcID < 0) {
84 EffectInstance* emoteTemp;
85
86 fx_emote(EMOTE_QUESTION, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 15, &emoteTemp);
88 } else {
89 Enemy* hitboxEnemy;
90
92 hitboxEnemy = get_enemy(npcID);
93 hitboxEnemy->varTable[4] = enemy->npcID;
94 hitboxEnemy->varTable[0] = 1;
95 }
96 npc->duration = enemy->varTable[2];
97 script->functionTemp[0] = AI_STATE_PROJECTILE_HITBOX_33;
98 }
99}
100
101void N(ProjectileHitbox_31)(Evt* script) {
102 Enemy* enemy = script->owner1.enemy;
103
104 get_npc_unsafe(enemy->npcID)->duration = enemy->varTable[2];
105 script->functionTemp[0] = AI_STATE_PROJECTILE_HITBOX_33;
106}
107
108void N(ProjectileHitbox_32)(Evt* script) {
109 Enemy* enemy = script->owner1.enemy;
110 Npc* npc = get_npc_unsafe(enemy->npcID);
111 Enemy* enemy2 = get_enemy(enemy->npcID + 1);
112 Npc* npc2 = get_npc_unsafe(enemy2->npcID);
113
114 npc->yaw = atan2(npc->pos.x, npc->pos.z, npc2->pos.x, npc2->pos.z);
115 if (enemy2->varTable[0] == 0) {
117 npc->duration = enemy->varTable[2];
118 script->functionTemp[0] = AI_STATE_PROJECTILE_HITBOX_33;
119 }
120}
121
122// TODO same as ParatroopaAI_Reset, but removes the extra args since it affects codegen...?
123void N(ProjectileHitbox_33)(Evt* script) {
124 Npc* npc = get_npc_unsafe(script->owner1.enemy->npcID);
125
126 npc->duration--;
127 if (npc->duration <= 0) {
128 script->functionTemp[0] = AI_STATE_WANDER_INIT;
129 }
130}
131
132API_CALLABLE(N(ProjectileAI_Main)) {
133 Enemy* enemy = script->owner1.enemy;
134 Bytecode* args = script->ptrReadPos;
135 s32 phi_s6 = 0;
136 f32 x, y, z;
137 f32 hitDepth;
138 Npc* npc;
139 Npc* npc2;
140 MobileAISettings* aiSettings;
141 u32 vt0;
142
143 if (get_enemy_safe(enemy->npcID) != NULL) {
144 if (enemy->varTable[0] != 5) {
145 aiSettings = (MobileAISettings*)evt_get_variable(script, *args++);
146 npc = get_npc_unsafe(enemy->npcID);
147
148 if (enemy->varTable[1] & 2) {
150 }
151
152 if (isInitialCall || (enemy->aiFlags & AI_FLAG_SUSPEND)) {
153 script->functionTemp[0] = 0;
154 npc->duration = 0;
157 npc->flags &= ~NPC_FLAG_JUMPING;
158 enemy->varTable[0] = 0;
162 if (enemy->aiFlags & AI_FLAG_SUSPEND) {
163 enemy->aiFlags &= ~AI_FLAG_SUSPEND;
164 }
165 }
166
167 switch (script->functionTemp[0]) {
168 default:
169 return 0;
170 case 0:
173 enemy->varTable[0] = 0;
174 script->functionTemp[0] = 1;
175 // fallthrough
176 case 1:
177 vt0 = enemy->varTable[0];
178
179 if (enemy->varTable[0] == 1) {
180 enemy->varTable[0] = 2;
181 npc2 = get_npc_unsafe(enemy->varTable[4]);
182 npc->pos.x = npc2->pos.x;
183 npc->pos.z = npc2->pos.z;
184 add_vec2D_polar(&npc->pos.x, &npc->pos.z, enemy->varTable[3], 270.0f - npc2->renderYaw);
185 npc->pos.y = npc2->pos.y + enemy->varTable[2];
186 enemy->hitboxIsActive = vt0;
187 enemy->unk_10.x = npc->pos.x;
188 enemy->unk_10.y = npc->pos.y;
189 enemy->unk_10.z = npc->pos.z;
190 npc->rot.x = 0.0f;
191 npc->rot.y = 0.0f;
192 npc->rot.z = 0.0f;
193 npc->moveSpeed = aiSettings->moveSpeed;
194 npc->yaw = atan2(npc->pos.x, npc->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
195 npc->jumpVel = aiSettings->alertRadius;
196 npc->jumpScale = aiSettings->alertOffsetDist;
197 npc->moveToPos.y = npc2->pos.y;
198 npc->flags &= ~NPC_FLAG_INVISIBLE;
200 npc->flags |= NPC_FLAG_JUMPING;
203 npc->duration = 90;
204 script->functionTemp[0] = 2;
205 break;
206 }
207 return 0;
208 case 2:
209 break;
210 }
211
212 x = npc->pos.x;
213 y = npc->pos.y + (npc->collisionHeight * 0.5);
214 z = npc->pos.z;
216 0, &x, &y, &z, npc->moveSpeed, npc->yaw, npc->collisionDiameter, npc->collisionHeight) != 0)
217 {
218 phi_s6 = 1;
219 }
220
221 x = npc->pos.x;
222 y = npc->pos.y;
223 z = npc->pos.z;
224 hitDepth = 1000.0f;
225 if ((npc_raycast_down_sides(npc->collisionChannel, &x, &y, &z, &hitDepth) != 0) &&
226 (hitDepth < fabsf(npc->jumpVel)) &&
227 (fabsf(y - npc->moveToPos.y) < 20.0))
228 {
229 npc->pos.y = y;
230 npc_move_heading(npc, npc->moveSpeed, npc->yaw);
231 phi_s6 = 10;
232 }
233
234 if (hitDepth < 1.0) {
235 phi_s6 = 11;
236 }
237 npc->duration--;
238 if (npc->duration <= 0) {
239 phi_s6 = 20;
240 }
241
242 if (phi_s6 == 0) {
243 if (enemy->varTable[1] & 1) {
244 npc->rot.z += 40.0;
245 }
246 npc_move_heading(npc, npc->moveSpeed, npc->yaw);
247 npc->pos.y += npc->jumpVel;
248 npc->jumpVel -= npc->jumpScale;
249 } else {
250 fx_walking_dust(2, npc->pos.x, npc->pos.y, npc->pos.z, 0, 0);
251 enemy->varTable[0] = 0;
252 npc->pos.x = NPC_DISPOSE_POS_X;
253 npc->pos.y = NPC_DISPOSE_POS_Y;
254 npc->pos.z = NPC_DISPOSE_POS_Z;
255 npc->jumpVel = 0.0f;
258 npc->flags &= ~NPC_FLAG_JUMPING;
261 script->functionTemp[0] = 0;
262 }
263 }
264 }
265 return ApiStatus_BLOCK;
266}
267
268API_CALLABLE(N(ProjectileAI_Reflect)) {
269 Enemy* enemy = script->owner1.enemy;
270 Camera* camera = &gCameras[gCurrentCamID];
271 s32 phi_s4 = 0;
272 Npc* npc;
273 f32 x, y, z;
274 f32 hitDepth;
275 f32 temp_f20_2;
276 f32 temp_f20_3;
277 f32 temp_f22;
278 f32 yaw;
279 s32 cond;
280
281 if (isInitialCall) {
282 script->functionTemp[0] = 0;
283 }
284
285 if (get_enemy_safe(enemy->npcID) == NULL) {
286 evt_set_variable(script, LVar0, 0);
287 return ApiStatus_DONE2;
288 }
289 if (enemy->varTable[0] == 5) {
290 evt_set_variable(script, LVar0, 0);
291 return ApiStatus_DONE2;
292 }
293 if (get_enemy_safe(enemy->npcID) == NULL) {
294 evt_set_variable(script, LVar0, 0);
295 return ApiStatus_DONE2;
296 }
297
298 npc = get_npc_unsafe(enemy->npcID);
299 switch (script->functionTemp[0]) {
300 case 0:
301 fx_walking_dust(2, npc->pos.x, npc->pos.y, npc->pos.z, 0.0f, 0.0f);
302 yaw = clamp_angle(camera->curYaw);
303 temp_f20_2 = clamp_angle(yaw + 180.0);
304 temp_f22 = clamp_angle(yaw + 90.0);
305 temp_f20_3 = clamp_angle(temp_f20_2 + 90.0);
307 npc->yaw = temp_f22;
308 } else {
309 npc->yaw = temp_f20_3;
310 }
311 npc->duration = 30;
312 npc->jumpVel = 10.0f;
313 npc->jumpScale = 0.9f;
314 npc->moveSpeed *= 1.2;
315 script->functionTemp[0] = 1;
316 // fallthrough
317 case 1:
318 x = npc->pos.x;
319 y = npc->pos.y;
320 z = npc->pos.z;
321 if (npc_test_move_simple_with_slipping(0, &x, &y, &z, npc->moveSpeed, npc->yaw, npc->collisionDiameter,
322 npc->collisionHeight) == 0)
323 {
324 npc_move_heading(npc, npc->moveSpeed, npc->yaw);
325 } else {
326 phi_s4 = 1;
327 }
328
329 cond = FALSE;
330 if (npc->jumpVel < 0.0) {
331 x = npc->pos.x;
332 y = npc->pos.y + 13.0;
333 z = npc->pos.z;
334 hitDepth = fabsf(npc->jumpVel) + 16.0;
335 if ((npc_raycast_down_sides(npc->collisionChannel, &x, &y, &z, &hitDepth) != 0) &&
336 (hitDepth <= (fabsf(npc->jumpVel) + 13.0)))
337 {
338 cond = TRUE;
339 }
340 }
341
342 if (!cond) {
343 npc->pos.y += npc->jumpVel;
344 npc->jumpVel -= npc->jumpScale;
345 } else {
346 phi_s4 = 10;
347 }
348
349 npc->duration--;
350 if (npc->duration <= 0) {
351 phi_s4 = 11;
352 }
353
354 if (phi_s4 != 0) {
355 fx_walking_dust(2, npc->pos.x, npc->pos.y, npc->pos.z, 0, 0);
356 enemy->varTable[0] = 0;
357 npc->pos.x = NPC_DISPOSE_POS_X;
358 npc->pos.y = NPC_DISPOSE_POS_Y;
359 npc->pos.z = NPC_DISPOSE_POS_Z;
362 npc->flags &= ~NPC_FLAG_JUMPING;
365 script->functionTemp[0] = 0;
366 evt_set_variable(script, LVar0, 1);
367 return ApiStatus_DONE2;
368 }
369 if (enemy->varTable[1] & 1) {
370 npc->rot.z += 60.0;
371 }
372 break;
373 }
374 return ApiStatus_BLOCK;
375}
376
377#endif
void N ProjectileHitbox_31(Evt *script)
s32 N ProjectileHitbox_GetUsableProjectileID(Evt *script)
void N ProjectileHitbox_33(Evt *script)
void N ProjectileHitbox_30(Evt *script)
void N UnkNpcAIFunc48(Evt *script, f32 arg1, f32 arg2, EnemyDetectVolume *territory)
void N ProjectileHitbox_32(Evt *script)
#define npc_raycast_down_sides
#define clamp_angle
#define atan2
@ EMOTE_QUESTION
Definition enums.h:497
@ ENEMY_ANIM_INDEX_MELEE_PRE
Definition enums.h:3434
@ ENEMY_ANIM_INDEX_IDLE
Definition enums.h:3426
@ ENEMY_ANIM_INDEX_MELEE_HIT
Definition enums.h:3435
@ AI_FLAG_SUSPEND
Definition enums.h:4571
@ AI_STATE_WANDER_INIT
Definition enums.h:4581
@ AI_STATE_PROJECTILE_HITBOX_33
Definition enums.h:4608
@ ENEMY_FLAG_IGNORE_HAMMER
Definition enums.h:4547
@ ENEMY_FLAG_IGNORE_PARTNER
Definition enums.h:4549
@ ENEMY_FLAG_PROJECTILE
Definition enums.h:4527
@ ENEMY_FLAG_SKIP_BATTLE
Definition enums.h:4541
@ ENEMY_FLAG_IGNORE_TOUCH
Definition enums.h:4545
@ ENEMY_FLAG_CANT_INTERACT
Definition enums.h:4548
@ ENEMY_FLAG_IGNORE_JUMP
Definition enums.h:4546
@ ENEMY_FLAG_ACTIVE_WHILE_OFFSCREEN
Definition enums.h:4542
@ NPC_SELF
Definition enums.h:2526
@ PARTNER_BOW
Definition enums.h:2894
@ PARTNER_SUSHIE
Definition enums.h:2892
@ NPC_FLAG_JUMPING
Definition enums.h:3009
@ NPC_FLAG_IGNORE_PLAYER_COLLISION
Definition enums.h:3006
@ NPC_FLAG_INVISIBLE
Definition enums.h:2999
@ NPC_FLAG_IGNORE_CAMERA_FOR_YAW
Definition enums.h:3016
#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 fabsf(f32 f)
s32 evt_set_variable(Evt *script, Bytecode var, s32 value)
Definition evt.c:1847
b32 npc_test_move_simple_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
b32 npc_test_move_taller_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
s32 ai_check_player_dist(Enemy *enemy, s32 arg1, f32 arg2, f32 arg3)
Definition 23680.c:515
void add_vec2D_polar(f32 *x, f32 *y, f32 r, f32 theta)
Definition 43F0.c:685
f32 get_clamped_angle_diff(f32, f32)
Definition 43F0.c:606
s32 flags
Definition npc.h:295
s32 basic_ai_check_player_dist(EnemyDetectVolume *arg0, Enemy *arg1, f32 arg2, f32 arg3, b8 arg4)
Definition 23680.c:429
s16 npcID
Definition npc.h:300
Enemy * get_enemy_safe(s32 npcID)
Same as get_enemy(), with the exception of always returning a value if an enemy is not found.
Definition npc.c:2559
Enemy * get_enemy(s32 npcID)
Looks for an enemy matching the specified npcID.
Definition npc.c:2540
void enable_npc_shadow(Npc *npc)
Definition npc.c:1027
s32 * animList
Definition npc.h:341
f32 moveSpeed
Definition npc.h:93
void disable_npc_shadow(Npc *npc)
Definition npc.c:1037
Npc * get_npc_unsafe(s32 npcID)
Definition npc.c:995
Vec3s unk_10
Definition npc.h:302
s8 hitboxIsActive
Definition npc.h:299
f32 alertOffsetDist
Definition npc.h:97
f32 chaseRadius
Definition npc.h:102
f32 alertRadius
Definition npc.h:96
u32 aiFlags
Definition npc.h:332
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:986
f32 chaseOffsetDist
Definition npc.h:103
Definition npc.h:294
#define NPC_DISPOSE_POS_Z
Definition macros.h:161
#define NPC_DISPOSE_POS_X
Definition macros.h:159
#define NPC_DISPOSE_POS_Y
Definition macros.h:160
#define LVar0
Definition macros.h:148
s16 collisionDiameter
f32 jumpScale
f32 jumpVel
s32 flags
f32 renderYaw
AnimID curAnim
Vec3f moveToPos
s32 collisionChannel
s16 collisionHeight
s16 turnAroundYawAdjustment
Vec3f rot
s8 verticalRenderOffset
Vec3f pos
f32 moveSpeed
s16 duration
PlayerStatus * gPlayerStatusPtr
PartnerStatus gPartnerStatus
Definition partners.c:42
Camera gCameras[4]
Definition cam_main.c:17
s16 gCurrentCamID
Definition cam_main.c:13