Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
HoppingAI.inc.c
Go to the documentation of this file.
1#include "common.h"
2#include "npc.h"
3#include "effects.h"
4
5void N(HoppingAI_HopInit)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
6 Enemy* enemy = script->owner1.enemy;
7 Npc* npc = get_npc_unsafe(enemy->npcID);
8 f32 x, y, z;
9 s32 i;
10
11 basic_ai_wander_init(script, aiSettings, territory);
12 npc->flags |= NPC_FLAG_JUMPING;
13 npc->jumpVel = (rand_int(45) / 10.0) + 8.0;
14 npc->jumpScale = 1.5f;
16
20 npc->pos.x, npc->pos.z,
22 {
23 npc->yaw = atan2(npc->pos.x, npc->pos.z, enemy->territory->wander.centerPos.x, enemy->territory->wander.centerPos.z);
24 x = npc->pos.x;
25 y = npc->pos.y;
26 z = npc->pos.z;
27
28 for (i = 0; i < 6; i++) {
29 if (npc_test_move_simple_with_slipping(npc->collisionChannel, &x, &y, &z, 25.0f,
30 npc->yaw, npc->collisionHeight, npc->collisionDiameter))
31 {
32 npc->yaw += 30.0;
33 } else {
34 break;
35 }
36 }
37 } else {
38 npc->yaw = clamp_angle(npc->yaw + rand_int(60) - 30.0f);
39 }
40}
41
42void N(HoppingAI_Hop)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
43 Enemy* enemy = script->owner1.enemy;
44 Npc* npc = get_npc_unsafe(enemy->npcID);
45 f32 posX, posY, posZ, hitDepth;
46
47 if (aiSettings->playerSearchInterval >= 0) {
48 if (script->functionTemp[1] <= 0) {
49 script->functionTemp[1] = aiSettings->playerSearchInterval;
50 if (basic_ai_check_player_dist(territory, enemy, aiSettings->alertRadius, aiSettings->alertOffsetDist, 0) != 0) {
51 EffectInstance* emoteTemp;
52 fx_emote(EMOTE_EXCLAMATION, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 15, &emoteTemp);
54 npc->yaw = atan2(npc->pos.x, npc->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
55 script->AI_TEMP_STATE = AI_STATE_CHASE_INIT;
56 return;
57 }
58 }
59 script->functionTemp[1]--;
60 }
61
62 if (npc->moveSpeed > 0.0) {
63 f32 collRadius;
64 f32 collHeight;
65 f32 moveSpeed;
66
67 posX = npc->pos.x;
68 posY = npc->pos.y;
69 posZ = npc->pos.z;
70 moveSpeed = npc->moveSpeed;
71 collHeight = npc->collisionHeight;
72 collRadius = npc->collisionDiameter;
73
75 &posX, &posY, &posZ,
76 moveSpeed, npc->yaw, collHeight, collRadius * 1.2))
77 {
78 npc_move_heading(npc, npc->moveSpeed, npc->yaw);
79 } else {
80 npc->moveSpeed = 0.0f;
81 }
82 }
83
84 if (npc->jumpVel < 0.0) {
85 posX = npc->pos.x;
86 posY = npc->pos.y + 13.0;
87 posZ = npc->pos.z;
88 hitDepth = fabsf(npc->jumpVel) + 16.0;
89
90 if (npc_raycast_down_sides(npc->collisionChannel, &posX, &posY, &posZ, &hitDepth) &&
91 hitDepth <= fabsf(npc->jumpVel) + 13.0)
92 {
93 npc->jumpVel = 0.0f;
94 npc->pos.y = posY;
95 npc->flags &= ~NPC_FLAG_JUMPING;
96 script->AI_TEMP_STATE = AI_STATE_LOITER_INIT;
97 script->functionTemp[1] = (rand_int(1000) % 3) + 2;
98
99 if (aiSettings->unk_AI_2C <= 0) {
100 script->AI_TEMP_STATE = AI_STATE_HOP_INIT;
101 } else if (aiSettings->moveTime <= 0) {
102 script->AI_TEMP_STATE = AI_STATE_HOP_INIT;
103 } else if (script->functionTemp[1] == 0) {
104 script->AI_TEMP_STATE = AI_STATE_HOP_INIT;
105 }
106 return;
107 }
108 }
109 npc->pos.y += npc->jumpVel;
110 npc->jumpVel -= npc->jumpScale;
111}
112
113void N(HoppingAI_LoiterInit)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
114 Enemy* enemy = script->owner1.enemy;
115 Npc* npc = get_npc_unsafe(enemy->npcID);
116
117 npc->duration = (aiSettings->waitTime / 2) + rand_int((aiSettings->waitTime / 2) + 1);
118 npc->yaw = clamp_angle(npc->yaw + rand_int(180) - 90.0f);
120 script->AI_TEMP_STATE = AI_STATE_LOITER;
121}
122
123void N(HoppingAI_Loiter)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
124 Enemy* enemy = script->owner1.enemy;
125 Npc* npc = get_npc_unsafe(enemy->npcID);
126
127 if (aiSettings->playerSearchInterval >= 0 && basic_ai_check_player_dist(territory, enemy, aiSettings->chaseRadius, aiSettings->chaseOffsetDist, 0) != 0) {
128 EffectInstance* emoteTemp;
129 fx_emote(EMOTE_EXCLAMATION, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 15, &emoteTemp);
131 npc->yaw = atan2(npc->pos.x, npc->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
132 script->AI_TEMP_STATE = AI_STATE_CHASE_INIT;
133 } else if (npc->turnAroundYawAdjustment == 0) {
134 npc->duration--;
135 if (npc->duration <= 0) {
136 script->functionTemp[1]--;
137 if (script->functionTemp[1] > 0) {
138 npc->yaw = clamp_angle(npc->yaw + 180.0f);
139 npc->duration = (rand_int(1000) % 11) + 5;
140 } else {
141 script->AI_TEMP_STATE = AI_STATE_HOP_INIT;
142 }
143 }
144 }
145}
146
147void N(HoppingAI_ChaseInit)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
148 Npc* enemy = get_npc_unsafe(script->owner1.enemy->npcID);
149
150 basic_ai_chase_init(script, aiSettings, territory);
151 enemy->flags |= ENEMY_FLAG_FLYING;
152 enemy->jumpVel = rand_int(5) + 10.0;
153 enemy->jumpScale = 1.5f;
154 enemy->yaw = atan2(enemy->pos.x, enemy->pos.z, gPlayerStatusPtr->pos.x, gPlayerStatusPtr->pos.z);
155 enemy->moveSpeed = aiSettings->chaseSpeed;
156 script->AI_TEMP_STATE = AI_STATE_CHASE;
158}
159
160void N(HoppingAI_Chase)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
161 Enemy* enemy = script->owner1.enemy;
162 Npc* npc = get_npc_unsafe(enemy->npcID);
163 f32 posX, posY, posZ;
164 f32 groundY, hitDepth;
165 EffectInstance* emoteTemp;
166
167 if (npc->moveSpeed > 0.0) {
168 posX = npc->pos.x;
169 posY = npc->pos.y;
170 posZ = npc->pos.z;
171 if (npc_test_move_simple_with_slipping(npc->collisionChannel, &posX, &posY, &posZ, npc->moveSpeed, npc->yaw,
173 {
174 npc->moveSpeed = 0.0f;
175 } else {
176 npc_move_heading(npc, npc->moveSpeed, npc->yaw);
177 }
178 }
179
180 if (npc->jumpVel < 0.0) {
181 posX = npc->pos.x;
182 groundY = 100.0f;
183 posZ = npc->pos.z;
184 hitDepth = 1000.0f;
185 npc_raycast_down_sides(npc->collisionChannel, &posX, &groundY, &posZ, &hitDepth);
186
187 posX = npc->pos.x;
188 posY = npc->pos.y + 13.0;
189 posZ = npc->pos.z;
190 hitDepth = fabsf(npc->jumpVel) + 16.0;
191 if (npc_raycast_down_sides(npc->collisionChannel, &posX, &posY, &posZ, &hitDepth) && hitDepth <= fabsf(npc->jumpVel) + 13.0) {
192 npc->jumpVel = 0.0f;
193 npc->pos.y = posY;
194 npc->flags &= ~NPC_FLAG_JUMPING;
195 fx_walking_dust(2, npc->pos.x, npc->pos.y, npc->pos.z, 0.0f, 0.0f);
196 script->AI_TEMP_STATE = AI_STATE_CHASE_INIT;
197
198 if (basic_ai_check_player_dist(territory, enemy, aiSettings->chaseRadius, aiSettings->chaseOffsetDist, 1) == 0) {
199 fx_emote(EMOTE_QUESTION, npc, 0.0f, npc->collisionHeight, 1.0f, 2.0f, -20.0f, 15, &emoteTemp);
200 npc->duration = 25;
201 script->AI_TEMP_STATE = AI_STATE_LOSE_PLAYER;
202 }
203 return;
204 }
205 }
206 npc->pos.y += npc->jumpVel;
207 npc->jumpVel -= npc->jumpScale;
208}
209
210void N(HoppingAI_LosePlayer)(Evt* script, MobileAISettings* aiSettings, EnemyDetectVolume* territory) {
211 Npc* npc = get_npc_unsafe(script->owner1.enemy->npcID);
212
213 npc->duration--;
214 if (npc->duration <= 0) {
215 script->AI_TEMP_STATE = AI_STATE_HOP_INIT;
216 }
217}
218
219API_CALLABLE(N(HoppingAI_Main)) {
220 Enemy* enemy = script->owner1.enemy;
221 Bytecode* args = script->ptrReadPos;
222 Npc* npc = get_npc_unsafe(enemy->npcID);
223 MobileAISettings* aiSettings = (MobileAISettings*)evt_get_variable(script, *args++);
224 EnemyDetectVolume territory;
225 EnemyDetectVolume* territoryPtr;
226
227 enemy->varTable[10] = evt_get_variable(script, *args++);
228 territory.skipPlayerDetectChance = 0;
229 territory.shape = enemy->territory->wander.detectShape;
230 territory.pointX = enemy->territory->wander.detectPos.x;
231 territory.pointZ = enemy->territory->wander.detectPos.z;
232 territory.sizeX = enemy->territory->wander.detectSize.x;
233 territory.sizeZ = enemy->territory->wander.detectSize.z;
234 territory.halfHeight = 100.0f;
235 territory.detectFlags = 0;
236 territoryPtr = &territory;
237
238 if (isInitialCall) {
239 script->AI_TEMP_STATE = AI_STATE_HOP_INIT;
240 npc->duration = 0;
241 script->functionTemp[1] = 0;
242 npc->flags &= ~NPC_FLAG_JUMPING;
243 npc->flags &= ~NPC_FLAG_GRAVITY;
244 npc->flags |= NPC_FLAG_FLYING;
245
248 script->AI_TEMP_STATE = AI_STATE_CHASE_INIT;
249 enemy->flags &= ~ENEMY_FLAG_BEGIN_WITH_CHASING;
250 }
251 }
252
253 if (enemy->aiFlags & AI_FLAG_SUSPEND) {
254 if (enemy->aiSuspendTime != 0) {
255 return ApiStatus_BLOCK;
256 }
257 enemy->aiFlags &= ~AI_FLAG_SUSPEND;
258 }
259
260 switch (script->AI_TEMP_STATE) {
262 N(HoppingAI_HopInit)(script, aiSettings, territoryPtr);
263 // fallthrough
264 case AI_STATE_HOP:
265 N(HoppingAI_Hop)(script, aiSettings, territoryPtr);
266 break;
268 N(HoppingAI_LoiterInit)(script, aiSettings, territoryPtr);
269 if (script->AI_TEMP_STATE != AI_STATE_LOITER) {
270 break;
271 }
272 // fallthrough
273 case AI_STATE_LOITER:
274 N(HoppingAI_Loiter)(script, aiSettings, territoryPtr);
275 break;
277 N(HoppingAI_ChaseInit)(script, aiSettings, territoryPtr);
278 // fallthrough
279 case AI_STATE_CHASE:
280 N(HoppingAI_Chase)(script, aiSettings, territoryPtr);
281 break;
283 N(HoppingAI_LosePlayer)(script, aiSettings, territoryPtr);
284 break;
285 }
286 return ApiStatus_BLOCK;
287}
void N HoppingAI_LosePlayer(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N HoppingAI_LoiterInit(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N HoppingAI_Chase(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N HoppingAI_Hop(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N HoppingAI_ChaseInit(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N HoppingAI_Loiter(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
void N HoppingAI_HopInit(Evt *script, MobileAISettings *aiSettings, EnemyDetectVolume *territory)
#define npc_raycast_down_sides
#define rand_int
#define clamp_angle
#define atan2
@ EMOTE_EXCLAMATION
Definition enums.h:495
@ EMOTE_QUESTION
Definition enums.h:497
@ ENEMY_ANIM_INDEX_IDLE
Definition enums.h:3426
@ AI_FLAG_SUSPEND
Definition enums.h:4571
@ AI_FLAG_SKIP_EMOTE_AFTER_FLEE
Definition enums.h:4572
@ AI_FLAG_SKIP_IDLE_ANIM_AFTER_FLEE
Definition enums.h:4573
@ AI_STATE_LOITER
Definition enums.h:4588
@ AI_STATE_HOP_INIT
Definition enums.h:4585
@ AI_STATE_LOITER_INIT
Definition enums.h:4587
@ AI_STATE_CHASE_INIT
Definition enums.h:4592
@ AI_STATE_HOP
Definition enums.h:4586
@ AI_STATE_CHASE
Definition enums.h:4593
@ AI_STATE_LOSE_PLAYER
Definition enums.h:4594
@ ENEMY_FLAG_FLYING
Definition enums.h:4532
@ ENEMY_FLAG_BEGIN_WITH_CHASING
Definition enums.h:4551
@ SOUND_SEQ_FUZZY_HOP
Definition enums.h:1722
@ 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_JUMPING
Definition enums.h:3009
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)
b32 is_point_outside_territory(s32 shape, f32 centerX, f32 centerZ, f32 pointX, f32 pointZ, f32 sizeX, f32 sizeZ)
Definition 23680.c:412
void basic_ai_chase_init(Evt *script, MobileAISettings *npcAISettings, EnemyDetectVolume *territory)
Definition 23680.c:769
void ai_enemy_play_sound(Npc *npc, s32 arg1, s32 arg2)
Definition 23680.c:543
b32 npc_test_move_simple_with_slipping(s32, f32 *, f32 *, f32 *, f32, f32, f32, f32)
void basic_ai_wander_init(Evt *script, MobileAISettings *npcAISettings, EnemyDetectVolume *territory)
Definition 23680.c:567
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
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
s32 * animList
Definition npc.h:341
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
enum TerritoryShape wanderShape
Definition npc.h:214
u32 aiFlags
Definition npc.h:332
void npc_move_heading(Npc *npc, f32 speed, f32 yaw)
Definition npc.c:986
s32 skipPlayerDetectChance
Definition npc.h:200
EnemyTerritoryWander wander
Definition npc.h:232
EnemyTerritory * territory
Definition npc.h:342
Definition npc.h:294
s16 collisionDiameter
f32 jumpScale
f32 jumpVel
s32 flags
AnimID curAnim
s32 collisionChannel
s16 collisionHeight
s16 turnAroundYawAdjustment
Vec3f pos
f32 moveSpeed
s16 duration
PlayerStatus * gPlayerStatusPtr