1 /*------------------------Patrick 2/7/97-----------------------------
2 Source file for Marine and Seal AI behaviour functions....
3 --------------------------------------------------------------------*/
4 #include "3dc.h"
5
6 #include "inline.h"
7 #include "module.h"
8
9 #include "stratdef.h"
10 #include "gamedef.h"
11 #include "bh_types.h"
12 #include "comp_shp.h"
13 #include "dynblock.h"
14 #include "dynamics.h"
15 #include "lighting.h"
16
17 #include "pfarlocs.h"
18 #include "pvisible.h"
19 #include "pheromon.h"
20 #include "bh_gener.h"
21 #include "bh_far.h"
22 #include "bh_pred.h"
23 #include "bh_marin.h"
24 #include "bh_weap.h"
25 #include "bh_debri.h"
26 #include "bh_alien.h"
27 #include "psnd.h"
28 #include "weapons.h"
29 #include "load_shp.h"
30 #include "particle.h"
31 #include "sfx.h"
32 #include "huddefs.h"
33 #include "pldghost.h"
34 #include "pldnet.h"
35 #include "psndplat.h"
36 #include "ai_sight.h"
37 #include "los.h"
38 #include "bh_corpse.h"
39 #include "bh_dummy.h"
40 #include "scream.h"
41 #include "targeting.h"
42
43 #include "dxlog.h"
44
45 #define UseLocalAssert Yes
46 #include "ourasert.h"
47
48 #include "sequnces.h"
49 #include "showcmds.h"
50 #include "extents.h"
51 #include "avp_userprofile.h"
52 #include "hud.h"
53
54 #define ALL_PULSERIFLES 0
55 #define MOTIONTRACKERS 0
56 #define ANARCHY 0
57 #define PISTOL_CLIP_SIZE 8
58 #define SENTRY_SENSITIVITY 1500
59 #define MARINE_AUTODETECT_RANGE 2500
60
61 #define SUSPECT_SENSITIVITY 2100
62 /* Ten centimetres. It can make a lot of difference. */
63
64 #define ALL_NEW_AVOIDANCE (1)
65 #define TWO_PISTOL_GUY (1)
66
67 /* external global variables used in this file */
68 extern int ModuleArraySize;
69 extern char *ModuleCurrVisArray;
70 extern int NormalFrameTime;
71 extern unsigned char Null_Name[8];
72 extern ACTIVESOUNDSAMPLE ActiveSounds[];
73 extern int CurrentLightAtPlayer;
74
75 extern int AIModuleArraySize;
76 extern AIMODULE *AIModuleArray;
77 extern DAMAGE_PROFILE FallingDamage;
78
79 extern enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr);
80 extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeSetFromLibrary(const char* rif_name,const char* shape_set_name);
81 extern HIERARCHY_VARIANT_DATA* GetHierarchyAlternateShapeSetCollectionFromLibrary(const char* rif_name,int collection_index);
82 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
83 extern STRATEGYBLOCK* CreateRocketKernel(VECTORCH *position, MATRIXCH *orient,int fromplayer);
84 extern STRATEGYBLOCK* CreateFrisbeeKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer);
85 extern int AlienPCIsCurrentlyVisible(int checktime,STRATEGYBLOCK *sbPtr);
86 extern int SBIsEnvironment(STRATEGYBLOCK *sbPtr);
87 void Marine_SwitchExpression(STRATEGYBLOCK *sbPtr,int state);
88
89 extern void PrintSpottedNumber(void);
90
91 /* prototypes for this file */
92 static STATE_RETURN_CONDITION Execute_MFS_Wait(STRATEGYBLOCK *sbPtr);
93 #if 0
94 static STATE_RETURN_CONDITION Execute_MFS_Hunt(STRATEGYBLOCK *sbPtr);
95 static STATE_RETURN_CONDITION Execute_MNS_DischargeGL(STRATEGYBLOCK *sbPtr);
96 static STATE_RETURN_CONDITION Execute_MNS_Hunt(STRATEGYBLOCK *sbPtr);
97 #endif
98 static STATE_RETURN_CONDITION Execute_MFS_Wander(STRATEGYBLOCK *sbPtr);
99 static STATE_RETURN_CONDITION Execute_MFS_Approach(STRATEGYBLOCK *sbPtr);
100 static STATE_RETURN_CONDITION Execute_MFS_Firing(STRATEGYBLOCK *sbPtr);
101 static STATE_RETURN_CONDITION Execute_MFS_Return(STRATEGYBLOCK *sbPtr);
102 static STATE_RETURN_CONDITION Execute_MFS_Pathfinder(STRATEGYBLOCK *sbPtr);
103 static STATE_RETURN_CONDITION Execute_MFS_Avoidance(STRATEGYBLOCK *sbPtr);
104 static STATE_RETURN_CONDITION Execute_MFS_SentryMode(STRATEGYBLOCK *sbPtr);
105
106 static STATE_RETURN_CONDITION Execute_MNS_Approach(STRATEGYBLOCK *sbPtr);
107 static STATE_RETURN_CONDITION Execute_MNS_Avoidance(STRATEGYBLOCK *sbPtr);
108 static STATE_RETURN_CONDITION Execute_MNS_Wander(STRATEGYBLOCK *sbPtr);
109 static STATE_RETURN_CONDITION Execute_MNS_Wait(STRATEGYBLOCK *sbPtr);
110 static STATE_RETURN_CONDITION Execute_MNS_DischargeLOSWeapon(STRATEGYBLOCK *sbPtr);
111 static STATE_RETURN_CONDITION Execute_MNS_DischargeShotgun(STRATEGYBLOCK *sbPtr);
112 static STATE_RETURN_CONDITION Execute_MNS_DischargePistol(STRATEGYBLOCK *sbPtr);
113 static STATE_RETURN_CONDITION Execute_MNS_DischargeSADAR(STRATEGYBLOCK *sbPtr);
114 static STATE_RETURN_CONDITION Execute_MNS_DischargeFlamethrower(STRATEGYBLOCK *sbPtr);
115 static STATE_RETURN_CONDITION Execute_MNS_ThrowMolotov(STRATEGYBLOCK *sbPtr);
116 static STATE_RETURN_CONDITION Execute_MNS_DischargeMinigun(STRATEGYBLOCK *sbPtr);
117 static STATE_RETURN_CONDITION Execute_MNS_SentryMode(STRATEGYBLOCK *sbPtr);
118 static STATE_RETURN_CONDITION Execute_MNS_Respond(STRATEGYBLOCK *sbPtr);
119 static STATE_RETURN_CONDITION Execute_MNS_Retreat(STRATEGYBLOCK *sbPtr);
120 static STATE_RETURN_CONDITION Execute_MNS_Return(STRATEGYBLOCK *sbPtr);
121 static STATE_RETURN_CONDITION Execute_MNS_Pathfinder(STRATEGYBLOCK *sbPtr);
122 static STATE_RETURN_CONDITION Execute_MNS_Taunting(STRATEGYBLOCK *sbPtr);
123 static STATE_RETURN_CONDITION Execute_MNS_Reloading(STRATEGYBLOCK *sbPtr);
124 static STATE_RETURN_CONDITION Execute_MNS_GetWeapon(STRATEGYBLOCK *sbPtr);
125 static STATE_RETURN_CONDITION Execute_MNS_NewDischargeGL(STRATEGYBLOCK *sbPtr);
126 static STATE_RETURN_CONDITION Execute_MNS_DischargeSmartgun(STRATEGYBLOCK *sbPtr);
127 static STATE_RETURN_CONDITION Execute_MNS_PanicReloading(STRATEGYBLOCK *sbPtr);
128 static STATE_RETURN_CONDITION Execute_MNS_DischargeTwoPistols(STRATEGYBLOCK *sbPtr);
129 static STATE_RETURN_CONDITION Execute_MNS_DischargeSkeeter(STRATEGYBLOCK *sbPtr);
130 static STATE_RETURN_CONDITION Execute_MNS_AcidAvoidance(STRATEGYBLOCK *sbPtr);
131
132 static void MarineMisfireFlameThrower(SECTION_DATA *muzzle, int *timer);
133 static STATE_RETURN_CONDITION Execute_MNS_NullPanicFire(STRATEGYBLOCK *sbPtr);
134 static STATE_RETURN_CONDITION Execute_MNS_PanicFireLOSWeapon(STRATEGYBLOCK *sbPtr);
135 static STATE_RETURN_CONDITION Execute_MNS_PanicFireFlamethrower(STRATEGYBLOCK *sbPtr);
136 static STATE_RETURN_CONDITION Execute_MNS_PanicFireGL(STRATEGYBLOCK *sbPtr);
137 static STATE_RETURN_CONDITION Execute_MNS_PanicFireMinigun(STRATEGYBLOCK *sbPtr);
138 static STATE_RETURN_CONDITION Execute_MNS_PanicFirePistol(STRATEGYBLOCK *sbPtr);
139 static STATE_RETURN_CONDITION Execute_MNS_PanicFireShotgun(STRATEGYBLOCK *sbPtr);
140 static STATE_RETURN_CONDITION Execute_MNS_PanicFireUnarmed(STRATEGYBLOCK *sbPtr);
141
142 void NPC_Maintain_Minigun(STRATEGYBLOCK *sbPtr, DELTA_CONTROLLER *mgd);
143 void Marine_AssumePanicExpression(STRATEGYBLOCK *sbPtr);
144 static STATE_RETURN_CONDITION Execute_MFS_Respond(STRATEGYBLOCK *sbPtr);
145 static STATE_RETURN_CONDITION Execute_MNS_PumpAction(STRATEGYBLOCK *sbPtr);
146 static STATE_RETURN_CONDITION Execute_MFS_Retreat(STRATEGYBLOCK *sbPtr);
147
148 static void Execute_Dying(STRATEGYBLOCK *sbPtr); /* used for near and far */
149
150 static void ProcessFarMarineTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule);
151 static void LobAGrenade(STRATEGYBLOCK *sbPtr);
152 static void CreateMarineGunFlash(STRATEGYBLOCK *sbPtr);
153
154 static void MarineFireFlameThrower(STRATEGYBLOCK *sbPtr);
155
156 static void Marine_ConsiderFallingDamage(STRATEGYBLOCK *sbPtr);
157 static void Marine_MirrorSuspectPoint(STRATEGYBLOCK *sbPtr);
158 static int MarineCanSeeTarget(STRATEGYBLOCK *sbPtr);
159 static int MarineCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target);
160 static int MarineIsAwareOfTarget(STRATEGYBLOCK *sbPtr);
161 static int MarineShouldBeCrawling(STRATEGYBLOCK *sbPtr);
162 static int MarineRetreatsInTheFaceOfDanger(STRATEGYBLOCK *sbPtr);
163 static void SetMarineAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening);
164 static void SetMarineAnimationSequence_Null(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening);
165 void Marine_Enter_Respond_State(STRATEGYBLOCK *sbPtr);
166
167 int SpeedRangeMods(VECTORCH *range,VECTORCH *speed);
168 STRATEGYBLOCK *Marine_GetNewTarget(VECTORCH *marinepos, STRATEGYBLOCK *me);
169 void FakeTrackerWheepGenerator(VECTORCH *marinepos, STRATEGYBLOCK *me);
170
171 void InitMission(STRATEGYBLOCK *sbPtr,MARINE_MISSION mission);
172
173 void WanderMission_Control(STRATEGYBLOCK *sbPtr);
174 void PathfinderMission_Control(STRATEGYBLOCK *sbPtr);
175 void GuardMission_Control(STRATEGYBLOCK *sbPtr);
176 void LocalGuardMission_Control(STRATEGYBLOCK *sbPtr);
177 void LoiterMission_Control(STRATEGYBLOCK *sbPtr);
178 void RunAroundOnFireMission_Control(STRATEGYBLOCK *sbPtr);
179
180 void WanderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result);
181 void PathfinderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result);
182 void GuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result);
183 void LocalGuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result);
184 void LoiterMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result);
185
186 void Marine_Enter_SentryMode_State(STRATEGYBLOCK *sbPtr);
187 void Marine_Enter_Wait_State(STRATEGYBLOCK *sbPtr);
188 void Marine_Enter_Firing_State(STRATEGYBLOCK *sbPtr);
189 void Marine_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr);
190 void Marine_Enter_Wander_State(STRATEGYBLOCK *sbPtr);
191 void Marine_Enter_Approach_State(STRATEGYBLOCK *sbPtr);
192 void Marine_Enter_Hunt_State(STRATEGYBLOCK *sbPtr);
193 void Marine_Enter_Retreat_State(STRATEGYBLOCK *sbPtr);
194 void Marine_Enter_Return_State(STRATEGYBLOCK *sbPtr);
195 void Marine_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr);
196 void Marine_Enter_Taunt_State(STRATEGYBLOCK *sbPtr);
197 void Marine_Enter_PanicFire_State(STRATEGYBLOCK *sbPtr);
198 void Marine_Enter_Reload_State(STRATEGYBLOCK *sbPtr);
199 void Marine_Enter_PumpAction_State(STRATEGYBLOCK *sbPtr);
200 void Marine_Enter_PullPistol_State(STRATEGYBLOCK *sbPtr);
201 void Marine_Enter_OneArmShotgun_State(STRATEGYBLOCK *sbPtr);
202 void Marine_Enter_OneArmPistol_State(STRATEGYBLOCK *sbPtr);
203 void Marine_Enter_PanicReload_State(STRATEGYBLOCK *sbPtr);
204
205 void Marine_Activate_AcidAvoidance_State(STRATEGYBLOCK *sbPtr, VECTORCH *incidence);
206
207 void Marine_QueueNeutralExpression(STRATEGYBLOCK *sbPtr);
208 void Marine_QueueGrimaceExpression(STRATEGYBLOCK *sbPtr);
209 void Marine_QueuePanicExpression(STRATEGYBLOCK *sbPtr);
210 void Marine_QueueWink1Expression(STRATEGYBLOCK *sbPtr);
211 void Marine_QueueWink2Expression(STRATEGYBLOCK *sbPtr);
212 int Marine_HasHisMouthOpen(STRATEGYBLOCK *sbPtr);
213 void Marine_UpdateFace(STRATEGYBLOCK *sbPtr);
214
215 void Marine_MuteVoice(STRATEGYBLOCK *sbPtr);
216 void Marine_WoundedScream(STRATEGYBLOCK *sbPtr);
217 void Marine_AcidScream(STRATEGYBLOCK *sbPtr);
218 void Marine_BurningScream(STRATEGYBLOCK *sbPtr);
219 void Marine_DeathScream(STRATEGYBLOCK *sbPtr);
220 void Marine_ElectrocutionScream(STRATEGYBLOCK *sbPtr);
221 void Marine_BurningDeathScream(STRATEGYBLOCK *sbPtr);
222 void Marine_AngryScream(STRATEGYBLOCK *sbPtr);
223 void Marine_PanicScream(STRATEGYBLOCK *sbPtr);
224 void Marine_OoophSound(STRATEGYBLOCK *sbPtr);
225 void Marine_SurpriseSound(STRATEGYBLOCK *sbPtr);
226 void Marine_Sobbing(STRATEGYBLOCK *sbPtr);
227 void Marine_TauntShout(STRATEGYBLOCK *sbPtr);
228
229 void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output);
230 void CreateMarineBot(VECTORCH *Position,int weapon);
231 void Convert_To_RunningOnFire(STRATEGYBLOCK *sbPtr);
232 void GetPointToFaceMarineTowards(STRATEGYBLOCK *sbPtr,VECTORCH *output);
233 void DoMarineHearing(STRATEGYBLOCK *sbPtr);
234
235 static void HandleWaitingAnimations(STRATEGYBLOCK *sbPtr);
236 static void HandleMovingAnimations(STRATEGYBLOCK *sbPtr);
237 int MakeModifiedTargetNum(int targetnum,int dist);
238
239
240 /* Console Variables */
241
242 int Marine_Skill=20000;
243 int Marine_Terminal_Velocity=20000;
244
245 /* Console Variables */
246
247 MARINE_WEAPON_DATA NPC_Marine_Weapons[] = {
248 {
249 MNPCW_PulseRifle, /* ID */
250 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
251
252 Execute_MNS_DischargeLOSWeapon, /* Func. */
253 NULL, /* Misfire func. */
254 Execute_MNS_PanicFireLOSWeapon, /* WeaponPanicFireFunction */
255 "hnpcmarine", /* Riffname */
256 "marine with pulse rifle", /* HierarchyName */
257 "dum flash", /* GunflashName */
258 "pulse rifle", /* ElevationSection */
259 "marine with pulse rifle", /* HitLocationTableName */
260 "Template", /* TemplateName */
261 "pulse mag", /* ClipName */
262 0, /* MinRange (Don't fire when closer) */
263 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
264 -1, /* MaxRange (Don't fire if further) */
265 0, /* Accuracy */
266 1000*65536/60, /* Firing Rate */
267 MARINE_NEAR_FIRE_TIME, /* Firing Time */
268 10, /* MinimumBurstSize */
269 AMMO_10MM_CULW_NPC, /* Ammo profile */
270 99, /* clip_size */
271 MSSS_Reload, /* Reload_Sequence */
272 300, /* TargetCallibrationShift */
273 SID_NOSOUND, /* StartSound */
274 SID_PULSE_LOOP, /* LoopSound */
275 SID_NOSOUND, /* EndSound */
276 1, /* Enable Grenades */
277 1, /* UseElevation */
278 1, /* EnableTracker */
279 1, /* ARealMarine */
280 0, /* Android */
281 },
282 {
283 MNPCW_Flamethrower, /* ID */
284 SFX_NONE, /* enum SFX_ID SfxID; */
285 Execute_MNS_DischargeFlamethrower, /* Func. */
286 MarineMisfireFlameThrower, /* Misfire func. */
287 Execute_MNS_PanicFireFlamethrower, /* WeaponPanicFireFunction */
288 "hnpcmarine", /* Riffname */
289 "marine with flame thrower", /* HierarchyName */
290 "dum flash", /* GunflashName */
291 "flamer", /* ElevationSection */
292 "marine with flame thrower", /* HitLocationTableName */
293 "Template", /* TemplateName */
294 "flamer mag", /* ClipName */
295 0, /* MinRange (Don't fire when closer) */
296 5000, /* ForceFireRange (Fire if closer) */
297 10000, /* MaxRange (Don't fire if further) */
298 ONE_FIXED, /* Accuracy */
299 200, /* Firing Rate */
300 MARINE_NEAR_FIRE_TIME<<2, /* Firing Time */
301 0, /* MinimumBurstSize */
302 AMMO_FLAMETHROWER, /* Ammo profile */
303 (ONE_FIXED*3), /* clip_size */
304 MSSS_Reload, /* Reload_Sequence */
305 0, /* TargetCallibrationShift */
306 SID_INCIN_START, /* StartSound */
307 SID_INCIN_LOOP, /* LoopSound */
308 SID_INCIN_END, /* EndSound */
309 0, /* Enable Grenades */
310 1, /* UseElevation */
311 1, /* EnableTracker */
312 1, /* ARealMarine */
313 0, /* Android */
314 },
315 {
316 MNPCW_Smartgun, /* ID */
317 SFX_MUZZLE_FLASH_SMARTGUN, /* enum SFX_ID SfxID; */
318 Execute_MNS_DischargeSmartgun, /* Func. Changed from DischargeLOSWeapon! */
319 NULL, /* Misfire func. */
320 Execute_MNS_PanicFireLOSWeapon, /* WeaponPanicFireFunction */
321 "hnpcmarine", /* Riffname */
322 "marine with smart gun", /* HierarchyName */
323 "dum flash", /* GunflashName */
324 "smart gun", /* ElevationSection */
325 "marine with smart gun", /* HitLocationTableName */
326 "Template", /* TemplateName */
327 "smart mag", /* ClipName */
328 0, /* MinRange (Don't fire when closer) */
329 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
330 36000, /* MaxRange (Don't fire if further) */
331 ONE_FIXED, /* Accuracy */
332 50*65536, /* Firing Rate */
333 MARINE_NEAR_FIRE_TIME, /* Firing Time */
334 50, /* MinimumBurstSize */
335 AMMO_SMARTGUN_NPC, /* Ammo profile */
336 300, /* clip_size */
337 MSSS_Reload, /* Reload_Sequence */
338 0, /* TargetCallibrationShift */
339 SID_NOSOUND, /* StartSound */
340 SID_SMART1, /* LoopSound */
341 SID_NOSOUND, /* EndSound */
342 0, /* Enable Grenades */
343 1, /* UseElevation */
344 1, /* EnableTracker */
345 1, /* ARealMarine */
346 0, /* Android */
347 },
348 {
349 MNPCW_SADAR, /* ID */
350 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
351
352 Execute_MNS_DischargeSADAR, /* Func. */
353 NULL, /* Misfire func. */
354 Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */
355 "hnpcmarine", /* Riffname */
356 "marine with SADAR", /* HierarchyName */
357 "dum flame", /* GunflashName */
358 "SADAR Tube", /* ElevationSection */
359 "marine with pulse rifle", /* HitLocationTableName */
360 "Template", /* TemplateName */
361 "SADAR", /* ClipName */
362 5000, /* MinRange (Don't fire when closer) */
363 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
364 -1, /* MaxRange (Don't fire if further) */
365 0, /* Accuracy */
366 1000*65536/60, /* Firing Rate */
367 MARINE_NEAR_FIRE_TIME, /* Firing Time */
368 0, /* MinimumBurstSize */
369 AMMO_10MM_CULW, /* Ammo profile */
370 1, /* clip_size */
371 MSSS_Reload, /* Reload_Sequence */
372 300, /* TargetCallibrationShift */
373 SID_ROCKFIRE, /* StartSound */
374 SID_NOSOUND, /* LoopSound */
375 SID_NOSOUND, /* EndSound */
376 1, /* Enable Grenades */
377 1, /* UseElevation */
378 1, /* EnableTracker */
379 1, /* ARealMarine */
380 0, /* Android */
381 },
382 {
383 MNPCW_GrenadeLauncher, /* ID */
384 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
385
386 Execute_MNS_NewDischargeGL, /* Func. */
387 NULL, /* Misfire func. */
388 Execute_MNS_PanicFireGL, /* WeaponPanicFireFunction */
389 "hnpcmarine", /* Riffname */
390 "marine + grenade launcher", /* HierarchyName */
391 "dum flash", /* GunflashName */
392 "gren stock", /* ElevationSection */
393 "marine with pulse rifle", /* HitLocationTableName */
394 "Template", /* TemplateName */
395 "gren mag", /* ClipName */
396 9000, /* MinRange (Don't fire when closer) */
397 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
398 -1, /* MaxRange (Don't fire if further) */
399 0, /* Accuracy */
400 1000*65536/60, /* Firing Rate */
401 MARINE_NEAR_FIRE_TIME, /* Firing Time */
402 0, /* MinimumBurstSize */
403 AMMO_10MM_CULW, /* Ammo profile */
404 6, /* clip_size */
405 MSSS_Reload, /* Reload_Sequence */
406 0, /* TargetCallibrationShift */
407 SID_ROCKFIRE, /* StartSound */
408 SID_NOSOUND, /* LoopSound */
409 SID_NOSOUND, /* EndSound */
410 1, /* Enable Grenades */
411 1, /* UseElevation */
412 1, /* EnableTracker */
413 1, /* ARealMarine */
414 0, /* Android */
415 },
416 {
417 MNPCW_Minigun, /* ID */
418 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
419
420 Execute_MNS_DischargeMinigun, /* Func. */
421 NULL, /* Misfire func. */
422 Execute_MNS_PanicFireMinigun, /* WeaponPanicFireFunction */
423 "hnpcmarine", /* Riffname */
424 "Marine with Mini Gun", /* HierarchyName */
425 "dum flash", /* GunflashName */
426 "mini gun", /* ElevationSection */
427 "marine with pulse rifle", /* HitLocationTableName */
428 "Template", /* TemplateName */
429 "mini mag", /* ClipName */
430 0, /* MinRange (Don't fire when closer) */
431 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
432 -1, /* MaxRange (Don't fire if further) */
433 0, /* Accuracy */
434 100*65536, /* Firing Rate */
435 MARINE_NEAR_FIRE_TIME, /* Firing Time */
436 MINIGUN_MINIMUM_BURST, /* MinimumBurstSize */
437 AMMO_MINIGUN_NPC, /* Ammo profile */
438 500, /* clip_size */
439 MSSS_Reload, /* Reload_Sequence */
440 0, /* TargetCallibrationShift */
441 SID_NOSOUND, /* StartSound */
442 SID_MINIGUN_LOOP, /* LoopSound */
443 SID_MINIGUN_END, /* EndSound */
444 0, /* Enable Grenades */
445 1, /* UseElevation */
446 1, /* EnableTracker */
447 1, /* ARealMarine */
448 0, /* Android */
449 },
450 {
451 MNPCW_PistolMarine, /* ID */
452 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
453
454 Execute_MNS_DischargePistol, /* Func. */
455 NULL, /* Misfire func. */
456 Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */
457 "hnpcmarine", /* Riffname */
458 "PISTOL", /* HierarchyName */
459 "dum flash", /* GunflashName */
460 "Rbicep", /* ElevationSection */
461 "marine with pulse rifle", /* HitLocationTableName */
462 "Template", /* TemplateName */
463 NULL, /* ClipName */
464 0, /* MinRange (Don't fire when closer) */
465 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
466 -1, /* MaxRange (Don't fire if further) */
467 30000, /* Accuracy */
468 1, /* Firing Rate */
469 MARINE_NEAR_FIRE_TIME, /* Firing Time */
470 0, /* MinimumBurstSize */
471 AMMO_MARINE_PISTOL, /* Ammo profile */
472 12, /* clip_size */
473 MSSS_Reload, /* Reload_Sequence */
474 250, /* TargetCallibrationShift */
475 SID_SHOTGUN, /* StartSound */
476 SID_NOSOUND, /* LoopSound */
477 SID_NOSOUND, /* EndSound */
478 0, /* Enable Grenades */
479 1, /* UseElevation */
480 0, /* EnableTracker */
481 1, /* ARealMarine */
482 0, /* Android */
483 },
484 {
485 MNPCW_MShotgun, /* ID */
486 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
487
488 Execute_MNS_DischargeShotgun, /* Func. */
489 NULL, /* Misfire func. */
490 Execute_MNS_PanicFireShotgun, /* WeaponPanicFireFunction */
491 "hnpc_civvie", /* Riffname */
492 "male_shotgun", /* HierarchyName */
493 "flash dummy", /* GunflashName */
494 "shot gun", /* ElevationSection */
495 "male civvie", /* HitLocationTableName */
496 "TEMPLATE", /* TemplateName */
497 NULL, /* ClipName */
498 0, /* MinRange (Don't fire when closer) */
499 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
500 -1, /* MaxRange (Don't fire if further) */
501 0, /* Accuracy */
502 1, /* Firing Rate */
503 -1, /* Firing Time */
504 0, /* MinimumBurstSize */
505 AMMO_SHOTGUN, /* Ammo profile */
506 8, /* clip_size */
507 MSSS_Reload, /* Reload_Sequence */
508 0, /* TargetCallibrationShift */
509 SID_SHOTGUN, /* StartSound */
510 SID_NOSOUND, /* LoopSound */
511 SID_NOSOUND, /* EndSound */
512 0, /* Enable Grenades */
513 1, /* UseElevation */
514 0, /* EnableTracker */
515 0, /* ARealMarine */
516 0, /* Android */
517 },
518 {
519 MNPCW_MPistol, /* ID */
520 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
521
522 Execute_MNS_DischargePistol, /* Func. */
523 NULL, /* Misfire func. */
524 Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */
525 "hnpc_civvie", /* Riffname */
526 "male_pistol", /* HierarchyName */
527 "flash dummy", /* GunflashName */
528 "male right bicep", /* ElevationSection */
529 "male civvie", /* HitLocationTableName */
530 "TEMPLATE", /* TemplateName */
531 NULL, /* ClipName */
532 0, /* MinRange (Don't fire when closer) */
533 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
534 -1, /* MaxRange (Don't fire if further) */
535 10000, /* Accuracy */
536 1, /* Firing Rate */
537 MARINE_NEAR_FIRE_TIME, /* Firing Time */
538 0, /* MinimumBurstSize */
539 AMMO_10MM_CULW_NPC, /* Ammo profile */
540 PISTOL_CLIP_SIZE, /* clip_size */
541 MSSS_Reload, /* Reload_Sequence */
542 0, /* TargetCallibrationShift */
543 SID_SHOTGUN, /* StartSound */
544 SID_NOSOUND, /* LoopSound */
545 SID_NOSOUND, /* EndSound */
546 0, /* Enable Grenades */
547 1, /* UseElevation */
548 0, /* EnableTracker */
549 0, /* ARealMarine */
550 0, /* Android */
551 },
552 {
553 MNPCW_MFlamer, /* ID */
554 SFX_NONE, /* enum SFX_ID SfxID; */
555 Execute_MNS_DischargeFlamethrower, /* Func. */
556 MarineMisfireFlameThrower, /* Misfire func. */
557 Execute_MNS_PanicFireFlamethrower, /* WeaponPanicFireFunction */
558 "hnpc_civvie", /* Riffname */
559 "male_flamer", /* HierarchyName */
560 "flash dummy", /* GunflashName */
561 "male right bicep", /* ElevationSection */
562 "male civvie", /* HitLocationTableName */
563 "TEMPLATE", /* TemplateName */
564 "flame canaster", /* ClipName */
565 0, /* MinRange (Don't fire when closer) */
566 5000, /* ForceFireRange (Fire if closer) */
567 10000, /* MaxRange (Don't fire if further) */
568 ONE_FIXED, /* Accuracy */
569 200, /* Firing Rate */
570 MARINE_NEAR_FIRE_TIME<<2, /* Firing Time */
571 0, /* MinimumBurstSize */
572 AMMO_FLAMETHROWER, /* Ammo profile */
573 (ONE_FIXED*2), /* clip_size */
574 MSSS_Reload, /* Reload_Sequence */
575 0, /* TargetCallibrationShift */
576 SID_INCIN_START, /* StartSound */
577 SID_INCIN_LOOP, /* LoopSound */
578 SID_INCIN_END, /* EndSound */
579 0, /* Enable Grenades */
580 1, /* UseElevation */
581 0, /* EnableTracker */
582 0, /* ARealMarine */
583 0, /* Android */
584 },
585 {
586 MNPCW_MUnarmed, /* ID */
587 SFX_NONE, /* enum SFX_ID SfxID; */
588
589 NULL, /* Func. */
590 NULL, /* Misfire func. */
591 Execute_MNS_PanicFireUnarmed, /* WeaponPanicFireFunction */
592 "hnpc_civvie", /* Riffname */
593 "male_unarmed", /* HierarchyName */
594 NULL, /* GunflashName */
595 NULL, /* ElevationSection */
596 "male civvie", /* HitLocationTableName */
597 "TEMPLATE", /* TemplateName */
598 NULL, /* ClipName */
599 0, /* MinRange (Don't fire when closer) */
600 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
601 -1, /* MaxRange (Don't fire if further) */
602 0, /* Accuracy */
603 1, /* Firing Rate */
604 MARINE_NEAR_FIRE_TIME, /* Firing Time */
605 0, /* MinimumBurstSize */
606 AMMO_NONE, /* Ammo profile */
607 -1, /* clip_size */
608 MSSS_Standard, /* Reload_Sequence */
609 0, /* TargetCallibrationShift */
610 SID_NOSOUND, /* StartSound */
611 SID_NOSOUND, /* LoopSound */
612 SID_NOSOUND, /* EndSound */
613 0, /* Enable Grenades */
614 0, /* UseElevation */
615 0, /* EnableTracker */
616 0, /* ARealMarine */
617 0, /* Android */
618 },
619 {
620 MNPCW_MMolotov, /* ID */
621 SFX_NONE, /* enum SFX_ID SfxID; */
622
623 Execute_MNS_ThrowMolotov, /* Func. */
624 NULL, /* Misfire func. */
625 Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */
626 "hnpc_civvie", /* Riffname */
627 "male_bottle", /* HierarchyName */
628 "bottle", /* GunflashName */
629 NULL, /* ElevationSection */
630 "male civvie", /* HitLocationTableName */
631 "TEMPLATE", /* TemplateName */
632 NULL, /* ClipName */
633 0, /* MinRange (Don't fire when closer) */
634 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
635 10000, /* MaxRange (Don't fire if further) */
636 -10000, /* Accuracy */
637 1, /* Firing Rate */
638 MARINE_NEAR_FIRE_TIME, /* Firing Time */
639 0, /* MinimumBurstSize */
640 AMMO_10MM_CULW, /* Ammo profile */
641 -1, /* clip_size */
642 MSSS_Standard, /* Reload_Sequence */
643 0, /* TargetCallibrationShift */
644 SID_NOSOUND, /* StartSound */
645 SID_NOSOUND, /* LoopSound */
646 SID_NOSOUND, /* EndSound */
647 0, /* Enable Grenades */
648 0, /* UseElevation */
649 0, /* EnableTracker */
650 0, /* ARealMarine */
651 0, /* Android */
652 },
653 {
654 MNPCW_Android, /* ID */
655 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
656
657 Execute_MNS_DischargeShotgun, /* Func. */
658 NULL, /* Misfire func. */
659 Execute_MNS_PanicFireShotgun, /* WeaponPanicFireFunction */
660 "hnpc_civvie", /* Riffname */
661 "Android shotgun", /* HierarchyName */
662 "flash dummy", /* GunflashName */
663 "shot gun", /* ElevationSection */
664 "male civvie", /* HitLocationTableName */
665 "Android template", /* TemplateName */
666 NULL, /* ClipName */
667 0, /* MinRange (Don't fire when closer) */
668 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
669 -1, /* MaxRange (Don't fire if further) */
670 0, /* Accuracy */
671 1, /* Firing Rate */
672 -1, /* Firing Time */
673 0, /* MinimumBurstSize */
674 AMMO_SHOTGUN, /* Ammo profile */
675 8, /* clip_size */
676 MSSS_Reload, /* Reload_Sequence */
677 0, /* TargetCallibrationShift */
678 SID_SHOTGUN, /* StartSound */
679 SID_NOSOUND, /* LoopSound */
680 SID_NOSOUND, /* EndSound */
681 0, /* Enable Grenades */
682 1, /* UseElevation */
683 0, /* EnableTracker */
684 0, /* ARealMarine */
685 1, /* Android */
686 },
687 {
688 MNPCW_AndroidSpecial, /* ID */
689 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
690
691 Execute_MNS_DischargeShotgun, /* Func. */
692 NULL, /* Misfire func. */
693 Execute_MNS_PanicFireShotgun, /* WeaponPanicFireFunction */
694 "hnpc_civvie", /* Riffname */
695 "Android Shotgun Special", /* HierarchyName */
696 "flash dummy", /* GunflashName */
697 "male right bicep", /* ElevationSection */
698 "male civvie", /* HitLocationTableName */
699 "Android template", /* TemplateName */
700 NULL, /* ClipName */
701 0, /* MinRange (Don't fire when closer) */
702 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
703 -1, /* MaxRange (Don't fire if further) */
704 0, /* Accuracy */
705 1, /* Firing Rate */
706 -1, /* Firing Time */
707 0, /* MinimumBurstSize */
708 AMMO_SHOTGUN, /* Ammo profile */
709 8, /* clip_size */
710 MSSS_Reload, /* Reload_Sequence */
711 0, /* TargetCallibrationShift */
712 SID_SHOTGUN, /* StartSound */
713 SID_NOSOUND, /* LoopSound */
714 SID_NOSOUND, /* EndSound */
715 0, /* Enable Grenades */
716 1, /* UseElevation */
717 0, /* EnableTracker */
718 0, /* ARealMarine */
719 1, /* Android */
720 },
721 {
722 MNPCW_Android_Pistol_Special, /* ID */
723 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
724
725 Execute_MNS_DischargePistol, /* Func. */
726 NULL, /* Misfire func. */
727 Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */
728 "hnpc_civvie", /* Riffname */
729 "Android Pistol Special", /* HierarchyName */
730 "flash dummy", /* GunflashName */
731 "male right bicep", /* ElevationSection */
732 "male civvie", /* HitLocationTableName */
733 "Android template", /* TemplateName */
734 NULL, /* ClipName */
735 0, /* MinRange (Don't fire when closer) */
736 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
737 -1, /* MaxRange (Don't fire if further) */
738 10000, /* Accuracy */
739 1, /* Firing Rate */
740 MARINE_NEAR_FIRE_TIME, /* Firing Time */
741 0, /* MinimumBurstSize */
742 AMMO_10MM_CULW_NPC, /* Ammo profile */
743 PISTOL_CLIP_SIZE, /* clip_size */
744 MSSS_Reload, /* Reload_Sequence */
745 0, /* TargetCallibrationShift */
746 SID_SHOTGUN, /* StartSound */
747 SID_NOSOUND, /* LoopSound */
748 SID_NOSOUND, /* EndSound */
749 0, /* Enable Grenades */
750 1, /* UseElevation */
751 0, /* EnableTracker */
752 0, /* ARealMarine */
753 1, /* Android */
754 },
755 {
756 MNPCW_TwoPistols, /* ID */
757 SFX_MUZZLE_FLASH_AMORPHOUS, /* enum SFX_ID SfxID; */
758
759 Execute_MNS_DischargeTwoPistols, /* Func. */
760 NULL, /* Misfire func. */
761 Execute_MNS_PanicFirePistol, /* WeaponPanicFireFunction */
762 "hnpcmarine", /* Riffname */
763 "Two Pistol", /* HierarchyName */
764 "dum flash", /* GunflashName */
765 "Rbicep", /* ElevationSection */
766 "marine with pulse rifle", /* HitLocationTableName */
767 "Template", /* TemplateName */
768 NULL, /* ClipName */
769 0, /* MinRange (Don't fire when closer) */
770 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
771 -1, /* MaxRange (Don't fire if further) */
772 30000, /* Accuracy */
773 12, /* Firing Rate */
774 (MARINE_NEAR_FIRE_TIME>>2), /* Firing Time */
775 0, /* MinimumBurstSize */
776 AMMO_MARINE_PISTOL, /* Ammo profile */
777 24, /* clip_size */
778 MSSS_Reload, /* Reload_Sequence */
779 250, /* TargetCallibrationShift */
780 SID_SHOTGUN, /* StartSound */
781 SID_NOSOUND, /* LoopSound */
782 SID_NOSOUND, /* EndSound */
783 0, /* Enable Grenades */
784 1, /* UseElevation */
785 0, /* EnableTracker */
786 1, /* ARealMarine */
787 0, /* Android */
788 },
789 {
790 MNPCW_Skeeter, /* ID */
791 SFX_MUZZLE_FLASH_SKEETER, /* enum SFX_ID SfxID; */
792
793 Execute_MNS_DischargeSkeeter, /* Func. */
794 NULL, /* Misfire func. */
795 Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */
796 "hnpcmarine", /* Riffname */
797 "skeeter", /* HierarchyName */
798 "dum flash", /* GunflashName */
799 "Skeeter Tube", /* ElevationSection */
800 "marine with pulse rifle", /* HitLocationTableName */
801 "Template", /* TemplateName */
802 "Skeeter", /* ClipName */
803 5000, /* MinRange (Don't fire when closer) */
804 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
805 -1, /* MaxRange (Don't fire if further) */
806 0, /* Accuracy */
807 ONE_FIXED, /* Firing Rate */
808 1625*65536/2000, /* Firing Time */
809 0, /* MinimumBurstSize */
810 AMMO_10MM_CULW, /* Ammo profile */
811 1, /* clip_size */
812 MSSS_Reload, /* Reload_Sequence */
813 300, /* TargetCallibrationShift */
814 SID_ED_SKEETERCHARGE, /* StartSound */
815 SID_NOSOUND, /* LoopSound */
816 SID_ED_SKEETERLAUNCH, /* EndSound */
817 1, /* Enable Grenades */
818 1, /* UseElevation */
819 1, /* EnableTracker */
820 1, /* ARealMarine */
821 0, /* Android */
822 },
823 {
824 MNPCW_Scientist_A, /* ID */
825 SFX_NONE, /* enum SFX_ID SfxID; */
826
827 NULL, /* Func. */
828 NULL, /* Misfire func. */
829 Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */
830 "scientist", /* Riffname */
831 "clip", /* HierarchyName */
832 "clip board", /* GunflashName */
833 NULL, /* ElevationSection */
834 "bub with molotov", /* HitLocationTableName */
835 "Template", /* TemplateName */
836 NULL, /* ClipName */
837 0, /* MinRange (Don't fire when closer) */
838 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
839 10000, /* MaxRange (Don't fire if further) */
840 -10000, /* Accuracy */
841 1, /* Firing Rate */
842 MARINE_NEAR_FIRE_TIME, /* Firing Time */
843 0, /* MinimumBurstSize */
844 AMMO_10MM_CULW, /* Ammo profile */
845 -1, /* clip_size */
846 MSSS_Standard, /* Reload_Sequence */
847 0, /* TargetCallibrationShift */
848 SID_NOSOUND, /* StartSound */
849 SID_NOSOUND, /* LoopSound */
850 SID_NOSOUND, /* EndSound */
851 0, /* Enable Grenades */
852 0, /* UseElevation */
853 0, /* EnableTracker */
854 0, /* ARealMarine */
855 0, /* Android */
856 },
857 {
858 MNPCW_Scientist_B, /* ID */
859 SFX_NONE, /* enum SFX_ID SfxID; */
860
861 NULL, /* Func. */
862 NULL, /* Misfire func. */
863 Execute_MNS_NullPanicFire, /* WeaponPanicFireFunction */
864 "scientist", /* Riffname */
865 "testtube", /* HierarchyName */
866 "test tube", /* GunflashName */
867 NULL, /* ElevationSection */
868 "bub with molotov", /* HitLocationTableName */
869 "Template", /* TemplateName */
870 NULL, /* ClipName */
871 0, /* MinRange (Don't fire when closer) */
872 MARINE_CLOSE_APPROACH_DISTANCE, /* ForceFireRange (Fire if closer) */
873 10000, /* MaxRange (Don't fire if further) */
874 -10000, /* Accuracy */
875 1, /* Firing Rate */
876 MARINE_NEAR_FIRE_TIME, /* Firing Time */
877 0, /* MinimumBurstSize */
878 AMMO_10MM_CULW, /* Ammo profile */
879 -1, /* clip_size */
880 MSSS_Standard, /* Reload_Sequence */
881 0, /* TargetCallibrationShift */
882 SID_NOSOUND, /* StartSound */
883 SID_NOSOUND, /* LoopSound */
884 SID_NOSOUND, /* EndSound */
885 0, /* Enable Grenades */
886 0, /* UseElevation */
887 0, /* EnableTracker */
888 0, /* ARealMarine */
889 0, /* Android */
890 },
891 {
892 MNPCW_End,
893 SFX_NONE,
894 NULL,
895 NULL,
896 NULL,
897 NULL,
898 NULL,
899 NULL,
900 NULL,
901 NULL,
902 NULL,
903 NULL,
904 0,
905 0,
906 0,
907 0,
908 0,
909 0,
910 0,
911 MAX_NO_OF_AMMO_TEMPLATES,
912 -1,
913 MSSS_Standard,
914 0,
915 SID_NOSOUND,
916 SID_NOSOUND,
917 SID_NOSOUND,
918 0,
919 0,
920 0,
921 0,
922 0,
923 },
924 };
925
926 VECTORCH ShotgunBlast[] = {
927 {0,0,400,},
928 {100,0,400,},
929 {-100,0,400,},
930 {50,0,400,},
931 {-50,0,400,},
932 {-1,-1,-1,},
933 };
934
935 SQUAD_COMMAND_STATE NpcSquad;
936 int ShowSquadState=0;
937 int ShowNearSquad=0;
938 extern SCENE Global_Scene;
939 static MODULE **Global_ModuleArrayPtr;
940 extern int ModuleArraySize;
941 static char tempstring[256];
942 static int tracker_noise;
943
ForceCaps(char * input)944 void ForceCaps(char *input) {
945 char *p;
946 p=input;
947 while (*p!=0) {
948 if ( (*p>=97) && (*p<=122) ) {
949 /* Force Caps */
950 *p-=32;
951 }
952 p++;
953 }
954 }
955
956 /* Squad functions, CDF 27/5/98 */
957
InitSquad(void)958 void InitSquad(void) {
959
960 /* Maybe level specific later? */
961
962 NpcSquad.alertStatus=0;
963 NpcSquad.responseLevel=0;
964 NpcSquad.alertZone=NULL;
965 NpcSquad.alertPriority=0;
966
967 NpcSquad.Squad_Suspicion=0;
968 NpcSquad.squad_suspect_point.vx=0;
969 NpcSquad.squad_suspect_point.vy=0;
970 NpcSquad.squad_suspect_point.vz=0;
971
972 NpcSquad.RespondingMarines=0;
973 NpcSquad.Alt_RespondingMarines=0;
974
975 NpcSquad.NearUnpanickedMarines=0;
976 NpcSquad.Alt_NearUnpanickedMarines=0;
977
978 NpcSquad.NearPanickedMarines=0;
979 NpcSquad.Alt_NearPanickedMarines=0;
980
981 NpcSquad.NearBurningMarines=0;
982 NpcSquad.Alt_NearBurningMarines=0;
983
984 NpcSquad.Squad_Delta_Morale=0;
985 NpcSquad.Nextframe_Squad_Delta_Morale=0;
986 }
987
DoSquad(void)988 void DoSquad(void) {
989
990 /* Maintain squad level stuff. */
991
992 if (NpcSquad.alertZone!=NULL) {
993 MaintainMarineTargetZone(NpcSquad.alertZone);
994 }
995
996 /* Maintain squad suspicion. */
997 if (NpcSquad.Squad_Suspicion>0) {
998 NpcSquad.Squad_Suspicion-=NormalFrameTime;
999 if (NpcSquad.Squad_Suspicion<0) {
1000 NpcSquad.Squad_Suspicion=0;
1001 }
1002 }
1003
1004 /* Maintain stats. */
1005 NpcSquad.RespondingMarines=NpcSquad.Alt_RespondingMarines;
1006 NpcSquad.Alt_RespondingMarines=0;
1007
1008 NpcSquad.NearUnpanickedMarines=NpcSquad.Alt_NearUnpanickedMarines;
1009 NpcSquad.Alt_NearUnpanickedMarines=0;
1010
1011 NpcSquad.NearPanickedMarines=NpcSquad.Alt_NearPanickedMarines;
1012 NpcSquad.Alt_NearPanickedMarines=0;
1013
1014 NpcSquad.NearBurningMarines=NpcSquad.Alt_NearBurningMarines;
1015 NpcSquad.Alt_NearBurningMarines=0;
1016
1017 NpcSquad.Squad_Delta_Morale=NpcSquad.Nextframe_Squad_Delta_Morale;
1018 NpcSquad.Nextframe_Squad_Delta_Morale=0;
1019
1020 /* Update morale. */
1021 NpcSquad.Nextframe_Squad_Delta_Morale+=MUL_FIXED(NormalFrameTime,(NpcSquad.NearUnpanickedMarines*50));
1022 NpcSquad.Nextframe_Squad_Delta_Morale-=MUL_FIXED(NormalFrameTime,(NpcSquad.NearPanickedMarines*1000));
1023 NpcSquad.Nextframe_Squad_Delta_Morale-=MUL_FIXED(NormalFrameTime,(NpcSquad.NearBurningMarines*3000));
1024
1025 if (TERROR_MODE) {
1026 NpcSquad.Nextframe_Squad_Delta_Morale=-100000000;
1027 }
1028
1029 /* Status display. */
1030 if (ShowSquadState) {
1031 PrintDebuggingText("Marine Alert Status = %d\n",NpcSquad.alertStatus);
1032 PrintDebuggingText("Marine Alert Priority = %d\n",NpcSquad.alertPriority);
1033 PrintDebuggingText("Responding Marines = %d\n",NpcSquad.RespondingMarines);
1034 PrintDebuggingText("NearPanicked Marines = %d\n",NpcSquad.NearPanickedMarines);
1035 PrintDebuggingText("NearUnpanicked Marines = %d\n",NpcSquad.NearUnpanickedMarines);
1036 PrintDebuggingText("NearBurning Marines = %d\n",NpcSquad.NearBurningMarines);
1037 PrintDebuggingText("Marine Outstanding Response Level = %d\n",NpcSquad.responseLevel);
1038 if (NpcSquad.alertZone==NULL) {
1039 PrintDebuggingText("Marine Alert Zone = NULL\n");
1040 } else {
1041 MODULE *sampleModule;
1042
1043 sampleModule=*(NpcSquad.alertZone->m_module_ptrs);
1044 if (sampleModule==NULL) {
1045 PrintDebuggingText("Marine Alert Zone = Totally Farped! %d\n",NpcSquad.alertZone->m_index);
1046 } else {
1047 PrintDebuggingText("Marine Alert Zone = %d, '%s'\n",sampleModule->m_index,sampleModule->name);
1048 }
1049 }
1050 PrintDebuggingText("Squad Suspicion = %d\n",NpcSquad.Squad_Suspicion);
1051 PrintDebuggingText("Squad Suspect Point = %d %d %d\n",NpcSquad.squad_suspect_point.vx,
1052 NpcSquad.squad_suspect_point.vy,NpcSquad.squad_suspect_point.vz);
1053 }
1054
1055 /* And now just for me... :-) */
1056 PrintSpottedNumber();
1057
1058 }
1059
ZoneAlert(int level,AIMODULE * targetModule)1060 void ZoneAlert(int level,AIMODULE *targetModule) {
1061
1062 int idealResponse;
1063 /* Bad stuff is going down. */
1064
1065 /* Switch to this one if it has a higher level than the current priority. */
1066
1067 if (level<NpcSquad.alertPriority) {
1068 /* Don't bother me with trifles! */
1069 return;
1070 }
1071
1072 if (level>=NpcSquad.alertStatus) {
1073 NpcSquad.alertStatus=level;
1074 }
1075
1076 NpcSquad.alertPriority=level;
1077 NpcSquad.alertZone=targetModule;
1078 switch (NpcSquad.alertStatus) {
1079 case 0:
1080 /* Can this ever happen? */
1081 idealResponse=1;
1082 break;
1083 case 1:
1084 idealResponse=1;
1085 break;
1086 case 2:
1087 idealResponse=3;
1088 break;
1089 case 3:
1090 idealResponse=5;
1091 break;
1092 default:
1093 idealResponse=1;
1094 break;
1095 }
1096
1097 if (NpcSquad.RespondingMarines<idealResponse) {
1098 NpcSquad.responseLevel=(idealResponse-NpcSquad.RespondingMarines);
1099 }
1100
1101 }
1102
PointAlert(int level,VECTORCH * point)1103 void PointAlert(int level, VECTORCH *point) {
1104
1105 MODULE *alertModule;
1106
1107 alertModule=ModuleFromPosition(point,playerPherModule);
1108
1109 if (NpcSquad.Squad_Suspicion!=SQUAD_PARANOIA_TIME) {
1110 NpcSquad.Squad_Suspicion=SQUAD_PARANOIA_TIME;
1111 NpcSquad.squad_suspect_point=*point;
1112 }
1113
1114 if (alertModule==NULL) {
1115 return;
1116 }
1117
1118 ZoneAlert(level,alertModule->m_aimodule);
1119
1120 }
1121
DeprioritiseAlert(AIMODULE * aimodule)1122 void DeprioritiseAlert(AIMODULE *aimodule) {
1123
1124 /* Parameterised, to make sure we're doing it right. */
1125
1126 if (aimodule==NpcSquad.alertZone) {
1127 NpcSquad.alertPriority=0;
1128 }
1129 }
1130
Console_ZoneAlert(int input)1131 void Console_ZoneAlert(int input) {
1132
1133 MODULE *target;
1134 SCENEMODULE *smptr;
1135
1136 smptr = Global_ModulePtr[Global_Scene];
1137 Global_ModuleArrayPtr = smptr->sm_marray;
1138
1139 if ((input==0)||(input>=ModuleArraySize)) {
1140 target=playerPherModule;
1141 } else {
1142 target=Global_ModuleArrayPtr[input];
1143 }
1144
1145 sprintf(tempstring,"NEW ZONE ALERT IN %d, '%s'\n",target->m_index,target->name);
1146 ForceCaps(tempstring);
1147 NewOnScreenMessage(tempstring);
1148
1149 ZoneAlert(3,target->m_aimodule);
1150 }
1151
1152 /* Interface function - 15/12/97 */
1153
GetThisNPCMarineWeapon(MARINE_NPC_WEAPONS this_id)1154 MARINE_WEAPON_DATA *GetThisNPCMarineWeapon(MARINE_NPC_WEAPONS this_id) {
1155
1156 int a;
1157
1158 a=0;
1159 while (NPC_Marine_Weapons[a].id!=MNPCW_End) {
1160 if (NPC_Marine_Weapons[a].id==this_id) {
1161 return(&NPC_Marine_Weapons[a]);
1162 }
1163 a++;
1164 }
1165
1166 return(NULL);
1167
1168 }
1169
GetThisManAWeapon(void)1170 MARINE_NPC_WEAPONS GetThisManAWeapon(void) {
1171
1172 int a;
1173 MARINE_NPC_WEAPONS thisweap;
1174
1175 a=FastRandom()&65535;
1176
1177 if (a<(ONE_FIXED>>3)) {
1178 /* 1/8: Smartgun. */
1179 thisweap=(MNPCW_Smartgun);
1180 } else if (a<(ONE_FIXED/3)) {
1181 /* 5/24: Flamethrower. */
1182 thisweap=(MNPCW_Flamethrower);
1183 } else if (a<((2*ONE_FIXED)/3)) {
1184 thisweap=(MNPCW_PulseRifle);
1185 //thisweap=(MNPCW_SADAR);
1186 } else {
1187 thisweap=(MNPCW_MShotgun);
1188 }
1189
1190 /* Check... */
1191 {
1192 MARINE_WEAPON_DATA *tempweap;
1193 SECTION *root_section;
1194
1195 tempweap=GetThisNPCMarineWeapon(thisweap);
1196 root_section=GetNamedHierarchyFromLibrary(tempweap->Riffname,tempweap->HierarchyName);
1197 if (!root_section) {
1198 thisweap=MNPCW_PulseRifle;
1199 }
1200 }
1201
1202 return(thisweap);
1203 }
1204
ChangeToAlternateAccoutrementSet(STRATEGYBLOCK * sbPtr,int index)1205 void ChangeToAlternateAccoutrementSet(STRATEGYBLOCK *sbPtr, int index) {
1206
1207 HIERARCHY_VARIANT_DATA* variant_data;
1208 HIERARCHY_SHAPE_REPLACEMENT* replacement_array;
1209 MARINE_STATUS_BLOCK *marineStatusPointer;
1210 int a;
1211
1212 LOCALASSERT(sbPtr);
1213 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
1214 LOCALASSERT(marineStatusPointer);
1215
1216 variant_data=GetHierarchyAlternateShapeSetCollectionFromLibrary(marineStatusPointer->My_Weapon->Riffname,index);
1217
1218 if (variant_data==NULL) {
1219 return;
1220 }
1221
1222 marineStatusPointer->Female=variant_data->female;
1223 marineStatusPointer->Voice=variant_data->voice;
1224
1225 replacement_array=(HIERARCHY_SHAPE_REPLACEMENT*)variant_data->replacements;
1226
1227 if (replacement_array==NULL) {
1228 return;
1229 }
1230
1231
1232 a=0;
1233
1234 while (replacement_array[a].replaced_section_name!=NULL) {
1235 SECTION_DATA *target_section;
1236
1237 target_section=GetThisSectionData(marineStatusPointer->HModelController.section_data,
1238 replacement_array[a].replaced_section_name);
1239 if (target_section) {
1240 target_section->Shape=replacement_array[a].replacement_shape;
1241 #if 1
1242 target_section->ShapeNum=replacement_array[a].replacement_shape_index;
1243 #endif
1244 target_section->replacement_id = replacement_array[a].replacement_id;
1245
1246 Setup_Texture_Animation_For_Section(target_section);
1247
1248 }
1249 a++;
1250 }
1251
1252 }
1253
ChangeToAlternateShapeSet(STRATEGYBLOCK * sbPtr,char * setname)1254 void ChangeToAlternateShapeSet(STRATEGYBLOCK *sbPtr, char *setname) {
1255
1256 HIERARCHY_SHAPE_REPLACEMENT* replacement_array;
1257 MARINE_STATUS_BLOCK *marineStatusPointer;
1258 int a;
1259
1260 LOCALASSERT(sbPtr);
1261 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
1262 LOCALASSERT(marineStatusPointer);
1263
1264 replacement_array=GetHierarchyAlternateShapeSetFromLibrary(marineStatusPointer->My_Weapon->Riffname,setname);
1265
1266 if (replacement_array==NULL) {
1267 return;
1268 }
1269
1270 a=0;
1271
1272 while (replacement_array[a].replaced_section_name!=NULL) {
1273 SECTION_DATA *target_section;
1274
1275 target_section=GetThisSectionData(marineStatusPointer->HModelController.section_data,
1276 replacement_array[a].replaced_section_name);
1277 if (target_section) {
1278 target_section->Shape=replacement_array[a].replacement_shape;
1279 #if 1
1280 target_section->ShapeNum=replacement_array[a].replacement_shape_index;
1281 #endif
1282
1283 Setup_Texture_Animation_For_Section(target_section);
1284 }
1285 a++;
1286 }
1287 }
1288
1289 /* CDF 3/4/98 */
1290
CastMarineBot(int weapon)1291 void CastMarineBot(int weapon) {
1292
1293 #define BOTRANGE 2000
1294
1295 VECTORCH position;
1296
1297 if (AvP.Network!=I_No_Network) {
1298 NewOnScreenMessage("NO MARINEBOTS IN MULTIPLAYER MODE");
1299 return;
1300 }
1301
1302 position=Player->ObStrategyBlock->DynPtr->Position;
1303 position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE);
1304 position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE);
1305 position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE);
1306
1307 CreateMarineBot(&position, weapon);
1308
1309 }
1310
CreateMarineBot(VECTORCH * Position,int weapon)1311 void CreateMarineBot(VECTORCH *Position, int weapon)
1312 {
1313 STRATEGYBLOCK* sbPtr;
1314
1315 /* create and initialise a strategy block */
1316 sbPtr = CreateActiveStrategyBlock();
1317 if(!sbPtr) {
1318 NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE");
1319 return; /* failure */
1320 }
1321 InitialiseSBValues(sbPtr);
1322
1323 sbPtr->I_SBtype = I_BehaviourMarine;
1324
1325 AssignNewSBName(sbPtr);
1326
1327 /* create, initialise and attach a dynamics block */
1328 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
1329 if(sbPtr->DynPtr)
1330 {
1331 EULER zeroEuler = {0,0,0};
1332 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1333 GLOBALASSERT(dynPtr);
1334 dynPtr->PrevPosition = dynPtr->Position = *Position;
1335 dynPtr->OrientEuler = zeroEuler;
1336 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
1337 TransposeMatrixCH(&dynPtr->OrientMat);
1338 }
1339 else
1340 {
1341 /* dynamics block allocation failed... */
1342 RemoveBehaviourStrategy(sbPtr);
1343 NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE");
1344 return;
1345 }
1346
1347 sbPtr->shapeIndex = 0;
1348
1349 sbPtr->maintainVisibility = 1;
1350 sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
1351
1352 /* create, initialise and attach a marine data block */
1353 sbPtr->SBdataptr = (void *)AllocateMem(sizeof(MARINE_STATUS_BLOCK));
1354 if(sbPtr->SBdataptr)
1355 {
1356 SECTION *root_section;
1357 MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr;
1358 GLOBALASSERT(marineStatus);
1359
1360 NPC_InitMovementData(&(marineStatus->moveData));
1361 NPC_InitWanderData(&(marineStatus->wanderData));
1362 marineStatus->health = MARINE_STARTING_HEALTH;
1363 sbPtr->integrity = marineStatus->health;
1364 marineStatus->volleySize = 0;
1365
1366 marineStatus->primaryWeaponDamage = MARINE_WEAPON_DAMAGE;
1367 marineStatus->stateTimer = MARINE_FAR_MOVE_TIME;
1368 marineStatus->weaponTarget.vx = marineStatus->weaponTarget.vy = marineStatus->weaponTarget.vz = 0;
1369 marineStatus->myGunFlash = (DISPLAYBLOCK *)0;
1370 marineStatus->soundHandle = SOUND_NOACTIVEINDEX;
1371 marineStatus->soundHandle2 = SOUND_NOACTIVEINDEX;
1372
1373 marineStatus->obstruction.environment=0;
1374 marineStatus->obstruction.destructableObject=0;
1375 marineStatus->obstruction.otherCharacter=0;
1376 marineStatus->obstruction.anySingleObstruction=0;
1377
1378 Initialise_AvoidanceManager(sbPtr,&marineStatus->avoidanceManager);
1379 InitWaypointManager(&marineStatus->waypointManager);
1380
1381 marineStatus->IAmCrouched = 0;
1382 marineStatus->lastroundhit=0;
1383 marineStatus->lasthitsection=NULL;
1384
1385 marineStatus->weapon_variable=0;
1386 marineStatus->weapon_variable2=0;
1387
1388 marineStatus->Skill=Marine_Skill;
1389 marineStatus->Courage=ONE_FIXED;
1390
1391 marineStatus->FiringAnim=0;
1392 marineStatus->SpotFlag=0;
1393
1394 //a generated marine won't have a death target
1395 {
1396 int i;
1397 for(i=0;i<SB_NAME_LENGTH;i++) marineStatus->death_target_ID[i] =0;
1398 marineStatus->death_target_request=0;
1399 marineStatus->death_target_sbptr=0;
1400 }
1401
1402 //this marine wasn't produced by a generator
1403 marineStatus->generator_sbptr=0;
1404
1405
1406 marineStatus->Target=NULL; //Player->ObStrategyBlock;
1407 if ( (weapon<=0)||(weapon>(int)MNPCW_End)) {
1408 marineStatus->My_Weapon=GetThisNPCMarineWeapon(GetThisManAWeapon());
1409 } else {
1410 #if (TWO_PISTOL_GUY==0)
1411 if (weapon>=MNPCW_TwoPistols) {
1412 marineStatus->My_Weapon=GetThisNPCMarineWeapon(GetThisManAWeapon());
1413 } else {
1414 marineStatus->My_Weapon=GetThisNPCMarineWeapon(weapon-1);
1415 }
1416 #else
1417 marineStatus->My_Weapon=GetThisNPCMarineWeapon(weapon-1);
1418 #endif
1419 }
1420
1421 /* Initialise marine's stats */
1422 {
1423 NPC_DATA *NpcData;
1424
1425 if (marineStatus->My_Weapon->Android) {
1426 NpcData=GetThisNpcData(I_NPC_Android);
1427 } else if (marineStatus->My_Weapon->ARealMarine) {
1428 NpcData=GetThisNpcData(I_NPC_Marine);
1429 } else {
1430 NpcData=GetThisNpcData(I_NPC_Civilian);
1431 }
1432 LOCALASSERT(NpcData);
1433 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
1434 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
1435 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
1436 }
1437
1438 {
1439 const MOVEMENT_DATA *movementData;
1440
1441 marineStatus->speedConstant=(ONE_FIXED-8192)+(FastRandom()&16383);
1442 marineStatus->accelerationConstant=(ONE_FIXED-8192)+(FastRandom()&16383);
1443
1444 if (marineStatus->My_Weapon->ARealMarine) {
1445 movementData=GetThisMovementData(MDI_Marine_Combat);
1446 } else {
1447 movementData=GetThisMovementData(MDI_Civilian_Combat);
1448 }
1449 GLOBALASSERT(movementData);
1450 marineStatus->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatus->speedConstant);
1451 marineStatus->acceleration = MUL_FIXED(movementData->acceleration,marineStatus->accelerationConstant);
1452 }
1453 COPY_NAME(marineStatus->Target_SBname,Null_Name);
1454 marineStatus->lastmodule=NULL;
1455 marineStatus->destinationmodule=NULL;
1456 marineStatus->missionmodule=NULL;
1457 marineStatus->fearmodule=NULL;
1458 marineStatus->my_facing_point=sbPtr->DynPtr->Position;
1459 marineStatus->path=-1;
1460 marineStatus->stepnumber=-1;
1461 marineStatus->sawlastframe=0;
1462 marineStatus->gotapoint=0;
1463 marineStatus->lastframe_fallingspeed=0;
1464 marineStatus->suspicious=0;
1465 marineStatus->previous_suspicion=0;
1466 marineStatus->using_squad_suspicion=0;
1467 marineStatus->suspect_point.vx=0;
1468 marineStatus->suspect_point.vy=0;
1469 marineStatus->suspect_point.vz=0;
1470 marineStatus->internalState=0;
1471 #if MOTIONTRACKERS
1472 if (marineStatus->My_Weapon->EnableTracker) {
1473 if ((FastRandom()&65535)<(ONE_FIXED>>2)) {
1474 marineStatus->mtracker_timer=FastRandom()&65535;
1475 } else {
1476 marineStatus->mtracker_timer=-1;
1477 }
1478 } else {
1479 marineStatus->mtracker_timer=-1;
1480 }
1481 #else
1482 marineStatus->mtracker_timer=-1;
1483 #endif
1484 marineStatus->GibbFactor=0;
1485 marineStatus->Wounds=0;
1486
1487 marineStatus->incidentFlag=0;
1488 marineStatus->incidentTimer=0;
1489
1490 if (marineStatus->My_Weapon->id==MNPCW_MPistol) {
1491 /* Special case for pistols? */
1492 marineStatus->lastroundhit=PISTOL_CLIP_SIZE;
1493 }
1494 marineStatus->clipammo=marineStatus->My_Weapon->clip_size;
1495 marineStatus->roundsForThisTarget=0;
1496
1497 marineStatus->HModelController.section_data=NULL;
1498 marineStatus->HModelController.Deltas=NULL;
1499 /* In case we need to deallocate it. */
1500 root_section=GetNamedHierarchyFromLibrary(marineStatus->My_Weapon->Riffname,marineStatus->My_Weapon->HierarchyName);
1501 if (!root_section) {
1502 RemoveBehaviourStrategy(sbPtr);
1503 NewOnScreenMessage("FAILED TO CREATE BOT: NO HMODEL");
1504 return;
1505 }
1506 Create_HModel(&marineStatus->HModelController,root_section);
1507 InitHModelSequence(&marineStatus->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,ONE_FIXED);
1508
1509 if (marineStatus->My_Weapon->UseElevation) {
1510 DELTA_CONTROLLER *delta;
1511 delta=Add_Delta_Sequence(&marineStatus->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0);
1512 GLOBALASSERT(delta);
1513 delta->timer=32767;
1514 }
1515
1516 if (marineStatus->My_Weapon->id==MNPCW_Minigun) {
1517 DELTA_CONTROLLER *delta;
1518 delta=Add_Delta_Sequence(&marineStatus->HModelController,"Minigun",(int)HMSQT_MarineStand,(int)MSSS_Minigun_Delta,(ONE_FIXED>>3));
1519 GLOBALASSERT(delta);
1520 delta->Playing=0;
1521 delta->Looped=1;
1522 }
1523
1524 /* Create blank hit delta sequence. */
1525 if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0)
1526 {
1527 if (HModelSequence_Exists(&marineStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
1528 DELTA_CONTROLLER *delta;
1529 delta=Add_Delta_Sequence(&marineStatus->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
1530 GLOBALASSERT(delta);
1531 delta->Playing=0;
1532 }
1533 }
1534
1535 marineStatus->My_Gunflash_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->GunflashName);
1536 marineStatus->My_Elevation_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->ElevationSection);
1537
1538 //initialise female to 0..
1539 //may be changed by ChangeToAlternateAccoutrementSet
1540 marineStatus->Female=0;
1541 marineStatus->Voice=0;
1542 marineStatus->Android=marineStatus->My_Weapon->Android;
1543
1544 //use accoutement set for both marine and civilian
1545 #if 0
1546 if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) {
1547 int dice=FastRandom()&65535;
1548 if (dice<16384) {
1549 ChangeToAlternateShapeSet(sbPtr, "Face Four");
1550 } else if (dice<32768) {
1551 ChangeToAlternateShapeSet(sbPtr, "Face Three");
1552 }
1553 } else if (strcmp("hnpc_civvie",marineStatus->My_Weapon->Riffname)==0) {
1554 #if 0
1555 int dice=FastRandom()&65535;
1556 if (dice<32767) {
1557 ChangeToAlternateShapeSet(sbPtr, "MedicalGuy");
1558 } else if (dice<49152) {
1559 ChangeToAlternateShapeSet(sbPtr, "CompanyGuy");
1560 }
1561 #else
1562 ChangeToAlternateAccoutrementSet(sbPtr, 0);
1563 #endif
1564 }
1565 #else
1566 //pick a random texture id rather than using 0 , so that we can get
1567 //texture ids not normally allowed by the level
1568 ChangeToAlternateAccoutrementSet(sbPtr, FastRandom());
1569 #endif
1570 marineStatus->VoicePitch = (FastRandom() & 255) - 128;
1571
1572 Marine_SwitchExpression(sbPtr,0);
1573 marineStatus->Target_Expression=0;
1574 marineStatus->Blink=-1;
1575
1576 ProveHModel_Far(&marineStatus->HModelController,sbPtr);
1577
1578 if(!(sbPtr->containingModule))
1579 {
1580 /* no containing module can be found... abort*/
1581 RemoveBehaviourStrategy(sbPtr);
1582 NewOnScreenMessage("FAILED TO CREATE BOT: MODULE CONTAINMENT FAILURE");
1583 return;
1584 }
1585 LOCALASSERT(sbPtr->containingModule);
1586
1587 if (marineStatus->My_Weapon->WeaponFireFunction==NULL) {
1588 InitMission(sbPtr,MM_NonCom);
1589 } else {
1590 InitMission(sbPtr,MM_Wander);
1591 }
1592
1593 MakeMarineNear(sbPtr);
1594
1595 NewOnScreenMessage("MARINEBOT CREATED");
1596 }
1597 else
1598 {
1599 /* no data block can be allocated */
1600 RemoveBehaviourStrategy(sbPtr);
1601 NewOnScreenMessage("FAILED TO CREATE BOT: MALLOC FAILURE");
1602 return;
1603 }
1604 }
1605
1606 /*------------------------Patrick 24/2/97-----------------------------
1607 Marine/Seal behaviour shell functions
1608 --------------------------------------------------------------------*/
1609
InitMarineBehaviour(void * bhdata,STRATEGYBLOCK * sbPtr)1610 void InitMarineBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
1611 {
1612 TOOLS_DATA_MARINE *toolsData = (TOOLS_DATA_MARINE *)bhdata;
1613 int i;
1614
1615 LOCALASSERT(sbPtr);
1616
1617 /* check we're not in a net game */
1618 if(AvP.Network != I_No_Network)
1619 {
1620 RemoveBehaviourStrategy(sbPtr);
1621 return;
1622 }
1623
1624 /* make the assumption that the loader has initialised the strategy block sensibly...
1625 so just set the shapeIndex from the tools data & copy the name id*/
1626 sbPtr->shapeIndex = toolsData->shapeIndex;
1627 for(i=0;i<SB_NAME_LENGTH;i++) sbPtr->SBname[i] = toolsData->nameID[i];
1628
1629 /* create, initialise and attach a dynamics block */
1630 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
1631 if(sbPtr->DynPtr)
1632 {
1633 EULER zeroEuler = {0,0,0};
1634 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1635 GLOBALASSERT(dynPtr);
1636 dynPtr->PrevPosition = dynPtr->Position = toolsData->position;
1637 dynPtr->OrientEuler = zeroEuler;
1638 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
1639 TransposeMatrixCH(&dynPtr->OrientMat);
1640
1641 /* zero linear velocity in dynamics block */
1642 dynPtr->LinVelocity.vx = 0;
1643 dynPtr->LinVelocity.vy = 0;
1644 dynPtr->LinVelocity.vz = 0;
1645
1646 sbPtr->containingModule=ModuleFromPosition(&dynPtr->Position,NULL);
1647
1648 GLOBALASSERT(sbPtr->containingModule);
1649 }
1650 else
1651 {
1652 /* allocation failed */
1653 RemoveBehaviourStrategy(sbPtr);
1654 return;
1655 }
1656
1657 /* create, initialise and attach a marine data block */
1658 sbPtr->SBdataptr = (void *)AllocateMem(sizeof(MARINE_STATUS_BLOCK));
1659 if(sbPtr->SBdataptr)
1660 {
1661 SECTION *root_section;
1662 MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr;
1663 GLOBALASSERT(marineStatus);
1664
1665 NPC_InitMovementData(&(marineStatus->moveData));
1666 NPC_InitWanderData(&(marineStatus->wanderData));
1667 marineStatus->health = MARINE_STARTING_HEALTH;
1668 sbPtr->integrity = marineStatus->health;
1669 marineStatus->volleySize = 0;
1670 marineStatus->primaryWeaponDamage = MARINE_WEAPON_DAMAGE;
1671 marineStatus->stateTimer = MARINE_FAR_MOVE_TIME;
1672 marineStatus->weaponTarget.vx = marineStatus->weaponTarget.vy = marineStatus->weaponTarget.vz = 0;
1673 marineStatus->myGunFlash = (DISPLAYBLOCK *)0;
1674 marineStatus->soundHandle = SOUND_NOACTIVEINDEX;
1675 marineStatus->soundHandle2 = SOUND_NOACTIVEINDEX;
1676
1677 marineStatus->obstruction.environment=0;
1678 marineStatus->obstruction.destructableObject=0;
1679 marineStatus->obstruction.otherCharacter=0;
1680 marineStatus->obstruction.anySingleObstruction=0;
1681
1682 Initialise_AvoidanceManager(sbPtr,&marineStatus->avoidanceManager);
1683 InitWaypointManager(&marineStatus->waypointManager);
1684
1685 marineStatus->IAmCrouched = 0;
1686 marineStatus->lastroundhit=0;
1687 marineStatus->lasthitsection=NULL;
1688
1689 marineStatus->weapon_variable=0;
1690 marineStatus->weapon_variable2=0;
1691
1692 marineStatus->Skill=Marine_Skill;
1693 marineStatus->Courage=ONE_FIXED;
1694
1695 marineStatus->FiringAnim=0;
1696 marineStatus->SpotFlag=0;
1697
1698 marineStatus->Target=NULL; //Player->ObStrategyBlock;
1699
1700 marineStatus->my_spot=sbPtr->DynPtr->Position;
1701
1702 #if ALL_PULSERIFLES
1703 marineStatus->My_Weapon=GetThisNPCMarineWeapon(MNPCW_PulseRifle);
1704 #else
1705 marineStatus->My_Weapon=GetThisNPCMarineWeapon(toolsData->marine_type);
1706 #endif
1707
1708 /* Initialise marine's stats */
1709 {
1710 NPC_DATA *NpcData;
1711
1712 if (marineStatus->My_Weapon->Android) {
1713 NpcData=GetThisNpcData(I_NPC_Android);
1714 } else if (marineStatus->My_Weapon->ARealMarine) {
1715 NpcData=GetThisNpcData(I_NPC_Marine);
1716 } else {
1717 NpcData=GetThisNpcData(I_NPC_Civilian);
1718 }
1719 LOCALASSERT(NpcData);
1720 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
1721 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
1722 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
1723 }
1724
1725 if (toolsData->Mission==MM_NonCom) {
1726 marineStatus->My_Weapon=GetThisNPCMarineWeapon(MNPCW_MUnarmed);
1727 }
1728
1729 if (marineStatus->My_Weapon->id==MNPCW_MPistol) {
1730 /* Special case for pistols? */
1731 marineStatus->lastroundhit=PISTOL_CLIP_SIZE;
1732 }
1733 marineStatus->clipammo=marineStatus->My_Weapon->clip_size;
1734 marineStatus->roundsForThisTarget=0;
1735
1736 {
1737 const MOVEMENT_DATA *movementData;
1738
1739 marineStatus->speedConstant=(ONE_FIXED-8192)+(FastRandom()&16383);
1740 marineStatus->accelerationConstant=(ONE_FIXED-8192)+(FastRandom()&16383);
1741
1742 if (marineStatus->My_Weapon->ARealMarine) {
1743 movementData=GetThisMovementData(MDI_Marine_Combat);
1744 } else {
1745 movementData=GetThisMovementData(MDI_Civilian_Combat);
1746 }
1747 GLOBALASSERT(movementData);
1748 marineStatus->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatus->speedConstant);
1749 marineStatus->acceleration = MUL_FIXED(movementData->acceleration,marineStatus->accelerationConstant);
1750 }
1751 COPY_NAME(marineStatus->Target_SBname,Null_Name);
1752 marineStatus->lastmodule=NULL;
1753 marineStatus->destinationmodule=NULL;
1754 marineStatus->missionmodule=NULL;
1755 marineStatus->fearmodule=NULL;
1756 marineStatus->my_facing_point=toolsData->facing_point;
1757 marineStatus->path=toolsData->path;
1758 marineStatus->stepnumber=toolsData->stepnumber;
1759 marineStatus->sawlastframe=0;
1760 marineStatus->gotapoint=0;
1761 marineStatus->lastframe_fallingspeed=0;
1762 marineStatus->suspicious=0;
1763 marineStatus->previous_suspicion=0;
1764 marineStatus->using_squad_suspicion=0;
1765 marineStatus->suspect_point.vx=0;
1766 marineStatus->suspect_point.vy=0;
1767 marineStatus->suspect_point.vz=0;
1768 marineStatus->internalState=0;
1769 #if MOTIONTRACKERS
1770 if (marineStatus->My_Weapon->EnableTracker) {
1771 if ((FastRandom()&65535)<(ONE_FIXED>>2)) {
1772 marineStatus->mtracker_timer=FastRandom()&65535;
1773 } else {
1774 marineStatus->mtracker_timer=-1;
1775 }
1776 } else {
1777 marineStatus->mtracker_timer=-1;
1778 }
1779 #else
1780 marineStatus->mtracker_timer=-1;
1781 #endif
1782 marineStatus->GibbFactor=0;
1783 marineStatus->Wounds=0;
1784
1785 marineStatus->incidentFlag=0;
1786 marineStatus->incidentTimer=0;
1787
1788 //InitShapeAnimationController(&marineStatus->ShpAnimCtrl, GetShapeData(sbPtr->shapeIndex));
1789
1790 GLOBALASSERT(marineStatus->My_Weapon->HierarchyName);
1791
1792 root_section=GetNamedHierarchyFromLibrary(marineStatus->My_Weapon->Riffname,marineStatus->My_Weapon->HierarchyName);
1793
1794 Create_HModel(&marineStatus->HModelController,root_section);
1795 InitHModelSequence(&marineStatus->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,ONE_FIXED);
1796
1797 if (marineStatus->My_Weapon->UseElevation) {
1798 DELTA_CONTROLLER *delta;
1799 delta=Add_Delta_Sequence(&marineStatus->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0);
1800 GLOBALASSERT(delta);
1801 delta->timer=32767;
1802 }
1803
1804 /* Create blank hit delta sequence. */
1805 if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0)
1806 {
1807 if (HModelSequence_Exists(&marineStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
1808 DELTA_CONTROLLER *delta;
1809 delta=Add_Delta_Sequence(&marineStatus->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
1810 GLOBALASSERT(delta);
1811 delta->Playing=0;
1812 }
1813 }
1814
1815 marineStatus->My_Gunflash_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->GunflashName);
1816 marineStatus->My_Elevation_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->ElevationSection);
1817
1818 for(i=0;i<SB_NAME_LENGTH;i++) marineStatus->death_target_ID[i] = toolsData->death_target_ID[i];
1819 marineStatus->death_target_request=toolsData->death_target_request;
1820 marineStatus->death_target_sbptr=0;
1821
1822 //this marine wasn't produced by a generator
1823 marineStatus->generator_sbptr=0;
1824
1825 //initialise female to 0..
1826 //may be changed by ChangeToAlternateAccoutrementSet
1827 marineStatus->Female=0;
1828 marineStatus->Voice=0;
1829 marineStatus->Android=marineStatus->My_Weapon->Android;
1830
1831 //use accoutement set for both marine and civilian
1832 #if 0
1833 if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) {
1834 /* Normal marine. */
1835 if ((toolsData->textureID==0)||(toolsData->textureID>4)) {
1836 /* Random. */
1837 int dice=FastRandom()&65535;
1838 if (dice<16384) {
1839 ChangeToAlternateShapeSet(sbPtr, "Face Four");
1840 } else if (dice<32768) {
1841 ChangeToAlternateShapeSet(sbPtr, "Face Three");
1842 }
1843 } else {
1844 switch (toolsData->textureID) {
1845 case 1:
1846 default:
1847 /* No change. */
1848 break;
1849 case 2:
1850 ChangeToAlternateShapeSet(sbPtr, "Face Four");
1851 break;
1852 case 3:
1853 ChangeToAlternateShapeSet(sbPtr, "Face Three");
1854 break;
1855 }
1856 }
1857 } else if (strcmp("hnpc_civvie",marineStatus->My_Weapon->Riffname)==0) {
1858 /* Civvies. */
1859 #if 0
1860 if ((toolsData->textureID==0)||(toolsData->textureID>3)) {
1861 int dice=FastRandom()&65535;
1862 if (dice<32767) {
1863 ChangeToAlternateShapeSet(sbPtr, "MedicalGuy");
1864 } else if (dice<49152) {
1865 ChangeToAlternateShapeSet(sbPtr, "CompanyGuy");
1866 }
1867 } else {
1868 switch (toolsData->textureID) {
1869 case 1:
1870 default:
1871 /* No change. */
1872 break;
1873 case 2:
1874 ChangeToAlternateShapeSet(sbPtr, "MedicalGuy");
1875 break;
1876 case 3:
1877 ChangeToAlternateShapeSet(sbPtr, "CompanyGuy");
1878 break;
1879 }
1880 }
1881 #else
1882 /* Gonna need a different handler for this? */
1883 ChangeToAlternateAccoutrementSet(sbPtr, toolsData->textureID);
1884 #endif
1885 }
1886 #else
1887 ChangeToAlternateAccoutrementSet(sbPtr, toolsData->textureID);
1888 #endif
1889 marineStatus->VoicePitch = (FastRandom() & 255) - 128;
1890
1891 Marine_SwitchExpression(sbPtr,0);
1892 marineStatus->Target_Expression=0;
1893 marineStatus->Blink=-1;
1894
1895 ProveHModel_Far(&marineStatus->HModelController,sbPtr);
1896
1897 if (marineStatus->My_Weapon->WeaponFireFunction==NULL) {
1898 InitMission(sbPtr,MM_NonCom);
1899 } else {
1900 InitMission(sbPtr,toolsData->Mission);
1901 }
1902 }
1903 else
1904 {
1905 /* allocation failed */
1906 RemoveBehaviourStrategy(sbPtr);
1907 return;
1908 }
1909 }
1910
InitSealBehaviour(void * bhdata,STRATEGYBLOCK * sbPtr)1911 void InitSealBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr)
1912 {
1913 /* Die, superfluous function!!! */
1914 InitMarineBehaviour(bhdata,sbPtr);
1915
1916 }
1917
CreateMarineDynamic(STRATEGYBLOCK * Generator,MARINE_NPC_WEAPONS weapon_for_marine)1918 void CreateMarineDynamic(STRATEGYBLOCK *Generator,MARINE_NPC_WEAPONS weapon_for_marine)
1919 {
1920 STRATEGYBLOCK* sbPtr;
1921 GENERATOR_BLOCK *generatorBlock;
1922
1923 generatorBlock=Generator->SBdataptr;
1924 GLOBALASSERT(generatorBlock);
1925
1926 /* check we're not in a net game */
1927 if(AvP.Network != I_No_Network)
1928 {
1929 return;
1930 }
1931
1932 /* create and initialise a strategy block */
1933 sbPtr = CreateActiveStrategyBlock();
1934 if(!sbPtr)
1935 {
1936 /* allocation failed */
1937 return;
1938 }
1939
1940 InitialiseSBValues(sbPtr);
1941 sbPtr->I_SBtype = I_BehaviourMarine;
1942
1943 /* Old way. *
1944 for(i = 0; i < SB_NAME_LENGTH; i++) {
1945 sbPtr->SBname[i] = '\0';
1946 }
1947 * CDF - 9/9/97 */
1948 AssignNewSBName(sbPtr);
1949 /* New way. */
1950
1951 /* create, initialise and attach a dynamics block */
1952 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
1953 if(sbPtr->DynPtr)
1954 {
1955 EULER zeroEuler = {0,0,0};
1956 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1957 GLOBALASSERT(dynPtr);
1958 dynPtr->PrevPosition = dynPtr->Position = ((GENERATOR_BLOCK* )Generator->SBdataptr)->Position;
1959 dynPtr->OrientEuler = zeroEuler;
1960 CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat);
1961 TransposeMatrixCH(&dynPtr->OrientMat);
1962 }
1963 else
1964 {
1965 /* allocation failed */
1966 RemoveBehaviourStrategy(sbPtr);
1967 return;
1968 }
1969
1970 /* set the shape */
1971 sbPtr->shapeIndex = Generator->shapeIndex;
1972
1973 sbPtr->maintainVisibility = 1;
1974 sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0);
1975 LOCALASSERT(sbPtr->containingModule);
1976 if(!(sbPtr->containingModule))
1977 {
1978 /* no containing module can be found... abort*/
1979 DestroyAnyStrategyBlock(sbPtr);
1980 return;
1981 }
1982
1983 /* assert marine is starting as invisible */
1984 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)] == 0);
1985
1986 /* create, initialise and attach a marine data block */
1987 sbPtr->SBdataptr = (void *)AllocateMem(sizeof(MARINE_STATUS_BLOCK));
1988 if(sbPtr->SBdataptr)
1989 {
1990 SECTION *root_section;
1991 MARINE_STATUS_BLOCK *marineStatus = (MARINE_STATUS_BLOCK *)sbPtr->SBdataptr;
1992 GLOBALASSERT(marineStatus);
1993
1994 NPC_InitMovementData(&(marineStatus->moveData));
1995 NPC_InitWanderData(&(marineStatus->wanderData));
1996 marineStatus->health = MARINE_STARTING_HEALTH;
1997 sbPtr->integrity = marineStatus->health;
1998 marineStatus->volleySize = 0;
1999 marineStatus->nearSpeed = MARINE_NEAR_SPEED;
2000 marineStatus->primaryWeaponDamage = MARINE_WEAPON_DAMAGE;
2001 marineStatus->stateTimer = MARINE_FAR_MOVE_TIME;
2002 marineStatus->weaponTarget.vx = marineStatus->weaponTarget.vy = marineStatus->weaponTarget.vz = 0;
2003 marineStatus->myGunFlash = (DISPLAYBLOCK *)0;
2004 marineStatus->soundHandle = SOUND_NOACTIVEINDEX;
2005 marineStatus->soundHandle2 = SOUND_NOACTIVEINDEX;
2006
2007 marineStatus->obstruction.environment=0;
2008 marineStatus->obstruction.destructableObject=0;
2009 marineStatus->obstruction.otherCharacter=0;
2010 marineStatus->obstruction.anySingleObstruction=0;
2011
2012 Initialise_AvoidanceManager(sbPtr,&marineStatus->avoidanceManager);
2013 InitWaypointManager(&marineStatus->waypointManager);
2014
2015 marineStatus->IAmCrouched = 0;
2016 marineStatus->lastroundhit=0;
2017 marineStatus->lasthitsection=NULL;
2018
2019 marineStatus->weapon_variable=0;
2020 marineStatus->weapon_variable2=0;
2021
2022 marineStatus->Skill=Marine_Skill;
2023 marineStatus->Courage=ONE_FIXED;
2024
2025 marineStatus->FiringAnim=0;
2026 marineStatus->SpotFlag=0;
2027
2028 //a generated marine won't have a death target
2029 {
2030 int i;
2031 for(i=0;i<SB_NAME_LENGTH;i++) marineStatus->death_target_ID[i] =0;
2032 marineStatus->death_target_request=0;
2033 marineStatus->death_target_sbptr=0;
2034 }
2035
2036 //note the generator that produced this marine
2037 marineStatus->generator_sbptr=Generator;
2038
2039 marineStatus->Target=NULL; //Player->ObStrategyBlock;
2040
2041 marineStatus->My_Weapon=GetThisNPCMarineWeapon(weapon_for_marine);
2042
2043 /* Initialise marine's stats */
2044 {
2045 NPC_DATA *NpcData;
2046
2047 if (marineStatus->My_Weapon->Android) {
2048 NpcData=GetThisNpcData(I_NPC_Android);
2049 } else if (marineStatus->My_Weapon->ARealMarine) {
2050 NpcData=GetThisNpcData(I_NPC_Marine);
2051 } else {
2052 NpcData=GetThisNpcData(I_NPC_Civilian);
2053 }
2054 LOCALASSERT(NpcData);
2055 sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<<ONE_FIXED_SHIFT;
2056 sbPtr->SBDamageBlock.Armour=NpcData->StartingStats.Armour<<ONE_FIXED_SHIFT;
2057 sbPtr->SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags;
2058 }
2059
2060 {
2061 const MOVEMENT_DATA *movementData;
2062
2063 marineStatus->speedConstant=(ONE_FIXED-8192)+(FastRandom()&16383);
2064 marineStatus->accelerationConstant=(ONE_FIXED-8192)+(FastRandom()&16383);
2065
2066 if (marineStatus->My_Weapon->ARealMarine) {
2067 movementData=GetThisMovementData(MDI_Marine_Combat);
2068 } else {
2069 movementData=GetThisMovementData(MDI_Civilian_Combat);
2070 }
2071 GLOBALASSERT(movementData);
2072 marineStatus->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatus->speedConstant);
2073 marineStatus->acceleration = MUL_FIXED(movementData->acceleration,marineStatus->accelerationConstant);
2074 }
2075
2076 COPY_NAME(marineStatus->Target_SBname,Null_Name);
2077 marineStatus->lastmodule=NULL;
2078 marineStatus->destinationmodule=NULL;
2079 marineStatus->missionmodule=NULL;
2080 marineStatus->fearmodule=NULL;
2081 marineStatus->my_facing_point=sbPtr->DynPtr->Position;
2082
2083 marineStatus->path=generatorBlock->path;
2084 marineStatus->stepnumber=generatorBlock->stepnumber;
2085
2086 marineStatus->sawlastframe=0;
2087 marineStatus->gotapoint=0;
2088 marineStatus->lastframe_fallingspeed=0;
2089 marineStatus->suspicious=0;
2090 marineStatus->previous_suspicion=0;
2091 marineStatus->using_squad_suspicion=0;
2092 marineStatus->suspect_point.vx=0;
2093 marineStatus->suspect_point.vy=0;
2094 marineStatus->suspect_point.vz=0;
2095 marineStatus->internalState=0;
2096 #if MOTIONTRACKERS
2097 if (marineStatus->My_Weapon->EnableTracker) {
2098 if ((FastRandom()&65535)<(ONE_FIXED>>2)) {
2099 marineStatus->mtracker_timer=FastRandom()&65535;
2100 } else {
2101 marineStatus->mtracker_timer=-1;
2102 }
2103 } else {
2104 marineStatus->mtracker_timer=-1;
2105 }
2106 #else
2107 marineStatus->mtracker_timer=-1;
2108 #endif
2109 marineStatus->GibbFactor=0;
2110 marineStatus->Wounds=0;
2111
2112 marineStatus->incidentFlag=0;
2113 marineStatus->incidentTimer=0;
2114
2115 if (marineStatus->My_Weapon->id==MNPCW_MPistol) {
2116 /* Special case for pistols? */
2117 marineStatus->lastroundhit=PISTOL_CLIP_SIZE;
2118 }
2119 marineStatus->clipammo=marineStatus->My_Weapon->clip_size;
2120 marineStatus->roundsForThisTarget=0;
2121
2122 //InitShapeAnimationController(&marineStatus->ShpAnimCtrl, GetShapeData(sbPtr->shapeIndex));
2123
2124 root_section=GetNamedHierarchyFromLibrary(marineStatus->My_Weapon->Riffname,marineStatus->My_Weapon->HierarchyName);
2125 Create_HModel(&marineStatus->HModelController,root_section);
2126 InitHModelSequence(&marineStatus->HModelController,(int)HMSQT_MarineRun,(int)MRSS_Standard,ONE_FIXED);
2127
2128 if (marineStatus->My_Weapon->UseElevation) {
2129 DELTA_CONTROLLER *delta;
2130 delta=Add_Delta_Sequence(&marineStatus->HModelController,"Elevation",(int)HMSQT_MarineStand,(int)MSSS_Elevation,0);
2131 GLOBALASSERT(delta);
2132 delta->timer=32767;
2133 }
2134
2135 /* Create blank hit delta sequence. */
2136 if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0)
2137 {
2138 if (HModelSequence_Exists(&marineStatus->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
2139 DELTA_CONTROLLER *delta;
2140 delta=Add_Delta_Sequence(&marineStatus->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
2141 GLOBALASSERT(delta);
2142 delta->Playing=0;
2143 }
2144 }
2145
2146 marineStatus->My_Gunflash_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->GunflashName);
2147 marineStatus->My_Elevation_Section=GetThisSectionData(marineStatus->HModelController.section_data,marineStatus->My_Weapon->ElevationSection);
2148
2149 //initialise female to 0..
2150 //may be changed by ChangeToAlternateAccoutrementSet
2151 marineStatus->Female=0;
2152 marineStatus->Voice=0;
2153 marineStatus->Android=marineStatus->My_Weapon->Android;
2154
2155 //use accoutement set for both marine and civilian
2156 #if 0
2157 if (strcmp("hnpcmarine",marineStatus->My_Weapon->Riffname)==0) {
2158 int dice=FastRandom()&65535;
2159 if (dice<16384) {
2160 ChangeToAlternateShapeSet(sbPtr, "Face Four");
2161 } else if (dice<32768) {
2162 ChangeToAlternateShapeSet(sbPtr, "Face Three");
2163 }
2164 } else if (strcmp("hnpc_civvie",marineStatus->My_Weapon->Riffname)==0) {
2165 #if 0
2166 int dice=FastRandom()&65535;
2167 if (dice<32767) {
2168 ChangeToAlternateShapeSet(sbPtr, "MedicalGuy");
2169 } else if (dice<49152) {
2170 ChangeToAlternateShapeSet(sbPtr, "CompanyGuy");
2171 }
2172 #else
2173 ChangeToAlternateAccoutrementSet(sbPtr, 0);
2174 #endif
2175 }
2176 #else
2177 //texture id 0 picks random one out of those allowed by the level
2178 ChangeToAlternateAccoutrementSet(sbPtr, 0);
2179 #endif
2180 marineStatus->VoicePitch = (FastRandom() & 255) - 128;
2181
2182 Marine_SwitchExpression(sbPtr,0);
2183 marineStatus->Target_Expression=0;
2184 marineStatus->Blink=-1;
2185
2186 ProveHModel_Far(&marineStatus->HModelController,sbPtr);
2187
2188 if (marineStatus->My_Weapon->WeaponFireFunction==NULL) {
2189 InitMission(sbPtr,MM_NonCom);
2190 } else if ( (marineStatus->path!=-1)&&(marineStatus->stepnumber!=-1)) {
2191 InitMission(sbPtr,MM_Pathfinder);
2192 } else {
2193 InitMission(sbPtr,MM_Wander);
2194 }
2195
2196 }
2197 else
2198 {
2199 /* allocation failed */
2200 RemoveBehaviourStrategy(sbPtr);
2201 return;
2202 }
2203 }
2204
SetMarineElevation(STRATEGYBLOCK * sbPtr)2205 void SetMarineElevation(STRATEGYBLOCK *sbPtr) {
2206
2207 MARINE_STATUS_BLOCK *marineStatusPointer;
2208 int offsetx,offsety,offsetz,offseta,angle1;
2209 DELTA_CONTROLLER *elevation_controller;
2210 VECTORCH *gunpos;
2211
2212 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
2213
2214 if (marineStatusPointer->My_Weapon->UseElevation==0) {
2215 /* Non elevating weapon. */
2216 return;
2217 }
2218
2219 if (marineStatusPointer->My_Elevation_Section) {
2220 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
2221 } else {
2222 gunpos=&sbPtr->DynPtr->Position;
2223 }
2224 /* Aim at weaponTarget. */
2225
2226 offsetx=(marineStatusPointer->weaponTarget.vx)-(gunpos->vx);
2227 offsety=(marineStatusPointer->weaponTarget.vz)-(gunpos->vz);
2228 offseta=-((marineStatusPointer->weaponTarget.vy)-(gunpos->vy));
2229
2230 while( (offsetx>(ONE_FIXED>>2))
2231 ||(offsety>(ONE_FIXED>>2))
2232 ||(offseta>(ONE_FIXED>>2))
2233 ||(offsetx<-(ONE_FIXED>>2))
2234 ||(offsety<-(ONE_FIXED>>2))
2235 ||(offseta<-(ONE_FIXED>>2))) {
2236
2237 offsetx>>=1;
2238 offsety>>=1;
2239 offseta>>=1;
2240
2241 }
2242
2243 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
2244 angle1=ArcTan(offseta,offsetz);
2245
2246 if (angle1>=3072) angle1-=4096;
2247 if (angle1>=2048) angle1=angle1-3072;
2248 if (angle1>1024) angle1=2048-angle1;
2249
2250 GLOBALASSERT(angle1>=-1024);
2251 GLOBALASSERT(angle1<=1024);
2252
2253
2254 elevation_controller=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation");
2255 GLOBALASSERT(elevation_controller);
2256
2257 if (marineStatusPointer->IAmCrouched) {
2258 elevation_controller->sequence_type=HMSQT_MarineCrouch;
2259 elevation_controller->sub_sequence=MCrSS_Elevation;
2260 } else {
2261 if (marineStatusPointer->FiringAnim==1) {
2262 elevation_controller->sequence_type=HMSQT_MarineStand;
2263 elevation_controller->sub_sequence=MSSS_Hip_Fire_Elevation;
2264 } else {
2265 elevation_controller->sequence_type=HMSQT_MarineStand;
2266 elevation_controller->sub_sequence=MSSS_Elevation;
2267 }
2268 }
2269
2270 {
2271 int fake_timer;
2272
2273 fake_timer=1024-angle1;
2274 fake_timer<<=5;
2275 if (fake_timer==65536) fake_timer=65535;
2276
2277 GLOBALASSERT(fake_timer>=0);
2278 GLOBALASSERT(fake_timer<65536);
2279
2280 elevation_controller->timer=fake_timer;
2281
2282 }
2283
2284 /* Unless you're a reloading pistol. */
2285 if (marineStatusPointer->My_Weapon->id==MNPCW_MPistol) {
2286 if (marineStatusPointer->lastroundhit==-1) {
2287 elevation_controller->timer=32767;
2288 }
2289 }
2290 /* Or a firing grenade launcher or shotgun in state 1. */
2291 if ((marineStatusPointer->My_Weapon->id==MNPCW_GrenadeLauncher)||(marineStatusPointer->My_Weapon->id==MNPCW_MShotgun)
2292 ||(marineStatusPointer->My_Weapon->id==MNPCW_Android)
2293 ||(marineStatusPointer->My_Weapon->id==MNPCW_AndroidSpecial)) {
2294 if ((marineStatusPointer->behaviourState==MBS_Firing)&&(marineStatusPointer->internalState)) {
2295 elevation_controller->timer=32767;
2296 }
2297 }
2298 }
2299
CentreMarineElevation(STRATEGYBLOCK * sbPtr)2300 void CentreMarineElevation(STRATEGYBLOCK *sbPtr) {
2301
2302 MARINE_STATUS_BLOCK *marineStatusPointer;
2303 DELTA_CONTROLLER *elevation_controller;
2304
2305 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
2306
2307 if (marineStatusPointer->My_Weapon->UseElevation==0) {
2308 /* Non elevating weapon. */
2309 return;
2310 }
2311
2312 elevation_controller=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation");
2313 GLOBALASSERT(elevation_controller);
2314
2315 if (marineStatusPointer->IAmCrouched) {
2316 elevation_controller->sequence_type=HMSQT_MarineCrouch;
2317 elevation_controller->sub_sequence=MCrSS_Elevation;
2318 } else {
2319 if (marineStatusPointer->FiringAnim==1) {
2320 elevation_controller->sequence_type=HMSQT_MarineStand;
2321 elevation_controller->sub_sequence=MSSS_Hip_Fire_Elevation;
2322 } else {
2323 elevation_controller->sequence_type=HMSQT_MarineStand;
2324 elevation_controller->sub_sequence=MSSS_Elevation;
2325 }
2326 }
2327
2328 elevation_controller->timer=32767;
2329
2330 }
2331
MarineBehaviour(STRATEGYBLOCK * sbPtr)2332 void MarineBehaviour(STRATEGYBLOCK *sbPtr)
2333 {
2334 MARINE_STATUS_BLOCK *marineStatusPointer;
2335 int marineIsNear;
2336
2337 LOCALASSERT(sbPtr);
2338 LOCALASSERT(sbPtr->containingModule);
2339 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
2340 LOCALASSERT(marineStatusPointer);
2341
2342 /* test if we've got a containing module: if we haven't, do nothing.
2343 This is important as the object could have been marked for deletion by the visibility
2344 management system...*/
2345 if(!sbPtr->containingModule)
2346 {
2347 DestroyAnyStrategyBlock(sbPtr); /* just to make sure */
2348 return;
2349 } else if (marineStatusPointer->behaviourState!=MBS_Dying) {
2350 #if SUPER_PHEROMONE_SYSTEM
2351 AddMarinePheromones(sbPtr->containingModule->m_aimodule);
2352 #endif
2353 }
2354
2355 if(sbPtr->SBdptr) {
2356 marineIsNear=1;
2357 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
2358 } else {
2359 marineIsNear=0;
2360 }
2361
2362 if (ShowSlack) {
2363 int synthSpeed,setSpeed,slack;
2364 VECTORCH offset;
2365 extern int SlackTotal;
2366 extern int SlackSize;
2367
2368 offset.vx=(sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx);
2369 offset.vy=(sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy);
2370 offset.vz=(sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz);
2371
2372 synthSpeed=Magnitude(&offset);
2373 synthSpeed=DIV_FIXED(synthSpeed,NormalFrameTime);
2374 setSpeed=Magnitude(&sbPtr->DynPtr->LinVelocity);
2375
2376 if (setSpeed) {
2377 slack=(ONE_FIXED-(DIV_FIXED(synthSpeed,setSpeed)));
2378 SlackTotal+=slack;
2379 SlackSize++;
2380 }
2381 #if 0
2382 PrintDebuggingText("MaxSpeed = %d, SynthSpeed = %d, SetSpeed = %d, Slack %d\n",alienStatusPointer->MaxSpeed,synthSpeed,setSpeed,slack);
2383 #endif
2384 }
2385
2386 GLOBALASSERT(marineStatusPointer->My_Weapon->WeaponPanicFireFunction);
2387
2388 InitWaypointSystem(0);
2389
2390 if ((Validate_Target(marineStatusPointer->Target,marineStatusPointer->Target_SBname)==0)
2391 &&((marineStatusPointer->Target!=Player->ObStrategyBlock)||(Observer))) {
2392 marineStatusPointer->Target=NULL;
2393 /* Were you suspicious of something before? */
2394 if (marineStatusPointer->previous_suspicion) {
2395 marineStatusPointer->suspicious=marineStatusPointer->previous_suspicion;
2396 marineStatusPointer->previous_suspicion=0;
2397 marineStatusPointer->using_squad_suspicion=0;
2398 }
2399 }
2400
2401 /* unset suspicion? */
2402
2403 if (marineStatusPointer->suspicious!=0) {
2404 if ((marineStatusPointer->behaviourState!=MBS_Approaching)
2405 &&(marineStatusPointer->behaviourState!=MBS_Responding)) {
2406 marineStatusPointer->suspicious-=NormalFrameTime;
2407 /* To fix the next trap... */
2408 if (marineStatusPointer->suspicious==0) {
2409 marineStatusPointer->suspicious=-1;
2410 }
2411 }
2412 if (marineStatusPointer->suspicious<0) {
2413 marineStatusPointer->suspicious=0;
2414 /* Set to zero on natural timeout, too. */
2415 marineStatusPointer->previous_suspicion=0;
2416 marineStatusPointer->using_squad_suspicion=0;
2417 if ((marineStatusPointer->behaviourState==MBS_Waiting)
2418 ||(marineStatusPointer->behaviourState==MBS_Sentry)) {
2419 /* We might concievably want to do this for all states. */
2420 marineStatusPointer->gotapoint=0;
2421 }
2422 }
2423 /* Approaching marines remain suspicious. */
2424 } else {
2425 /* Not suspicious. */
2426 if (marineStatusPointer->Target) {
2427 if (!MarineCanSeeTarget(sbPtr)) {
2428 /* Oh well, forget it, then. */
2429 marineStatusPointer->Target=NULL;
2430 }
2431 }
2432 }
2433 /* Squad level suspicion? */
2434 if (((marineStatusPointer->suspicious==0)||(marineStatusPointer->using_squad_suspicion))
2435 &&(NpcSquad.Squad_Suspicion!=0)
2436 &&(sbPtr->SBdptr)
2437 &&(marineStatusPointer->behaviourState!=MBS_Approaching)
2438 &&(marineStatusPointer->behaviourState!=MBS_Firing)
2439 &&(marineStatusPointer->behaviourState!=MBS_Dying)) {
2440 /* Use squad suspicion. */
2441 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
2442 marineStatusPointer->suspect_point=NpcSquad.squad_suspect_point;
2443 /* Set this to zero when you get a *new* suspicion. */
2444 marineStatusPointer->previous_suspicion=0;
2445 marineStatusPointer->using_squad_suspicion=1;
2446 }
2447
2448 if (marineStatusPointer->sawlastframe==2) {
2449 marineStatusPointer->sawlastframe=0;
2450 }
2451
2452 /* Unset incident flag. */
2453 marineStatusPointer->incidentFlag=0;
2454
2455 marineStatusPointer->incidentTimer-=NormalFrameTime;
2456
2457 if (marineStatusPointer->incidentTimer<0) {
2458 marineStatusPointer->incidentFlag=1;
2459 marineStatusPointer->incidentTimer=32767+(FastRandom()&65535);
2460 }
2461
2462 /* Run Motion Tracker. */
2463
2464 tracker_noise=0;
2465
2466 if (marineStatusPointer->mtracker_timer>=0) {
2467 marineStatusPointer->mtracker_timer+=NormalFrameTime;
2468 }
2469 /* Negative timer means no tracker. */
2470 if (marineStatusPointer->mtracker_timer>ONE_FIXED) {
2471 marineStatusPointer->mtracker_timer=0;
2472 tracker_noise=1;
2473 }
2474
2475 if ((marineStatusPointer->Target==NULL)
2476 #if ANARCHY
2477 || (marineStatusPointer->lastmodule!=sbPtr->containingModule->m_aimodule)
2478 || (marineStatusPointer->Target==Player->ObStrategyBlock)
2479 #endif
2480 ) {
2481
2482 if ((marineIsNear)||(marineStatusPointer->incidentFlag)) {
2483 /* Get new target. */
2484 marineStatusPointer->roundsForThisTarget=0;
2485 marineStatusPointer->sawlastframe=0;
2486 marineStatusPointer->Target=Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr);
2487
2488 if (marineStatusPointer->Target) {
2489 #if MARINE_STATE_PRINT
2490 textprint("Marine gets new target.\n");
2491 #endif
2492 COPY_NAME(marineStatusPointer->Target_SBname,marineStatusPointer->Target->SBname);
2493
2494 /* Remember your suspicion... */
2495 marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious;
2496 marineStatusPointer->suspicious=0;
2497
2498 /* Do stats. */
2499 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
2500 if (marineStatusPointer->SpotFlag==0) {
2501 CurrentGameStats_Spotted();
2502 marineStatusPointer->SpotFlag=1;
2503 }
2504 }
2505
2506 /* New Enemy! */
2507
2508 if (NpcSquad.alertStatus==0) {
2509 NpcSquad.alertStatus=1;
2510 }
2511 if (marineStatusPointer->Target->containingModule) {
2512 ZoneAlert(2,marineStatusPointer->Target->containingModule->m_aimodule);
2513 } else {
2514 ZoneAlert(2,sbPtr->containingModule->m_aimodule);
2515 }
2516
2517 } else {
2518 #if 0
2519 PrintDebuggingText("Marine found no target!\n");
2520 #endif
2521 }
2522 }
2523 } else if (marineStatusPointer->mtracker_timer==0) {
2524 /* Fake sweep for wheeps. */
2525 FakeTrackerWheepGenerator(&sbPtr->DynPtr->Position,sbPtr);
2526
2527 if (marineStatusPointer->Target->SBdptr) {
2528 if (NpcSquad.Squad_Suspicion!=SQUAD_PARANOIA_TIME) {
2529 if (MarineCanSeeTarget(sbPtr)) {
2530 /* Hey, guys! */
2531 GLOBALASSERT(marineStatusPointer->Target->DynPtr);
2532 NpcSquad.Squad_Suspicion=SQUAD_PARANOIA_TIME;
2533 NpcSquad.squad_suspect_point=marineStatusPointer->Target->DynPtr->Position;
2534 }
2535 }
2536 }
2537 }
2538
2539 /* Brushing Test. */
2540
2541 {
2542 struct collisionreport *nextReport;
2543 nextReport = sbPtr->DynPtr->CollisionReportPtr;
2544
2545 while(nextReport)
2546 {
2547 if(nextReport->ObstacleSBPtr)
2548 {
2549 if((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlien)||
2550 ((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarinePlayer)
2551 &&(AvP.PlayerType!=I_Marine))||
2552 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlienPlayer)||
2553 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorPlayer)||
2554 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourNetGhost)||
2555 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourXenoborg)||
2556 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorAlien)||
2557 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourQueenAlien)||
2558 (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourFaceHugger))
2559 {
2560 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
2561 marineStatusPointer->suspect_point=nextReport->ObstacleSBPtr->DynPtr->Position;
2562 /* Set this to zero when you get a *new* suspicion. */
2563 marineStatusPointer->previous_suspicion=0;
2564 marineStatusPointer->using_squad_suspicion=0;
2565 if (marineStatusPointer->Android==0) {
2566 marineStatusPointer->Courage-=(NormalFrameTime>>1);
2567 }
2568 }
2569 }
2570 nextReport = nextReport->NextCollisionReportPtr;
2571 }
2572 }
2573
2574 /* Blinking! */
2575 if (marineStatusPointer->behaviourState!=MBS_Dying) {
2576 if (marineStatusPointer->Expression<3) {
2577 if (marineStatusPointer->incidentFlag) {
2578 if ((FastRandom()&65535)<24000) {
2579 switch (marineStatusPointer->Expression) {
2580 default:
2581 GLOBALASSERT(0);
2582 break;
2583 case 0:
2584 Marine_SwitchExpression(sbPtr,3);
2585 break;
2586 case 1:
2587 Marine_SwitchExpression(sbPtr,4);
2588 break;
2589 case 2:
2590 Marine_SwitchExpression(sbPtr,5);
2591 break;
2592 }
2593 marineStatusPointer->Blink=0;
2594 }
2595 }
2596 } else if (marineStatusPointer->Expression>=3) {
2597 if (marineStatusPointer->Blink>=0) {
2598 marineStatusPointer->Blink+=NormalFrameTime;
2599 if (marineStatusPointer->Blink>(ONE_FIXED/7)) {
2600 switch (marineStatusPointer->Expression) {
2601 default:
2602 GLOBALASSERT(0);
2603 break;
2604 case 3:
2605 Marine_SwitchExpression(sbPtr,0);
2606 break;
2607 case 4:
2608 Marine_SwitchExpression(sbPtr,1);
2609 break;
2610 case 5:
2611 Marine_SwitchExpression(sbPtr,2);
2612 break;
2613 }
2614 }
2615 }
2616 }
2617 }
2618
2619 /* Now hearing. */
2620
2621 DoMarineHearing(sbPtr);
2622
2623 /* That was senses. Now courage. */
2624 if (marineStatusPointer->Android==0) {
2625
2626 if ((marineStatusPointer->Target==NULL)&&(marineStatusPointer->suspicious==0)) {
2627 marineStatusPointer->Courage+=MUL_FIXED(NormalFrameTime,300);
2628 }
2629
2630 marineStatusPointer->Courage+=NpcSquad.Squad_Delta_Morale;
2631
2632 if (marineStatusPointer->Courage>=(ONE_FIXED<<1)) {
2633 marineStatusPointer->Courage=(ONE_FIXED<<1);
2634 } else if (marineStatusPointer->Courage<0) {
2635 marineStatusPointer->Courage=0;
2636 }
2637 } else {
2638 marineStatusPointer->Courage=ONE_FIXED;
2639 }
2640
2641 /* Dead yet? */
2642
2643 if (marineStatusPointer->GibbFactor) {
2644 /* If you're gibbed, you're dead. */
2645 sbPtr->SBDamageBlock.Health = 0;
2646 }
2647
2648 if (sbPtr->SBDamageBlock.IsOnFire) {
2649
2650 CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL);
2651
2652 if (sbPtr->I_SBtype==I_BehaviourNetCorpse) {
2653 /* Gettin' out of here... */
2654 return;
2655 }
2656
2657 if (marineStatusPointer->Mission!=MM_RunAroundOnFire) {
2658 if (marineStatusPointer->Android==0) {
2659 Convert_To_RunningOnFire(sbPtr);
2660 } else {
2661 /* Handle sound for an android. */
2662 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
2663 Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
2664 } else {
2665 if (ActiveSounds[marineStatusPointer->soundHandle].soundIndex!=SID_FIRE) {
2666 Sound_Stop(marineStatusPointer->soundHandle);
2667 Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&marineStatusPointer->soundHandle,127);
2668 }
2669 }
2670 }
2671 }
2672
2673 }
2674
2675 /* Mission Control! */
2676
2677 if ((ShowSquadState)||((sbPtr->SBdptr)&&(ShowNearSquad))) {
2678 if (sbPtr->name) {
2679 PrintDebuggingText("%s: ",sbPtr->name);
2680 } else {
2681 PrintDebuggingText("Unnamed: ");
2682 }
2683 if (marineStatusPointer->suspicious) {
2684 PrintDebuggingText("Suspicious %d ",marineStatusPointer->suspicious);
2685 }
2686 }
2687
2688 if ((marineStatusPointer->Mission!=MM_NonCom)&&(marineStatusPointer->Mission!=MM_RunAroundOnFire)) {
2689 if (marineStatusPointer->My_Weapon->WeaponFireFunction==NULL) {
2690 LOGDXFMT(("Marine Weapon ID = %d\n",marineStatusPointer->My_Weapon->id));
2691 LOGDXFMT(("Mission %d\n",marineStatusPointer->Mission));
2692 }
2693 GLOBALASSERT(marineStatusPointer->My_Weapon->WeaponFireFunction);
2694 }
2695
2696 switch (marineStatusPointer->Mission) {
2697 case (MM_Wait_Then_Wander):
2698 case (MM_Wander):
2699 {
2700 WanderMission_Control(sbPtr);
2701 break;
2702 }
2703 case (MM_Guard):
2704 {
2705 GuardMission_Control(sbPtr);
2706 break;
2707 }
2708 case (MM_LocalGuard):
2709 {
2710 LocalGuardMission_Control(sbPtr);
2711 break;
2712 }
2713 case (MM_NonCom):
2714 {
2715 LoiterMission_Control(sbPtr);
2716 break;
2717 }
2718 case (MM_Pathfinder):
2719 {
2720 PathfinderMission_Control(sbPtr);
2721 break;
2722 }
2723 case (MM_RunAroundOnFire):
2724 {
2725 RunAroundOnFireMission_Control(sbPtr);
2726 break;
2727 }
2728 default:
2729 {
2730 GLOBALASSERT(0);
2731 break;
2732 }
2733 }
2734
2735 if (TERROR_MODE) {
2736 if ((marineStatusPointer->behaviourState!=MBS_PanicFire)
2737 &&(marineStatusPointer->behaviourState!=MBS_PanicReloading)
2738 &&(marineStatusPointer->behaviourState!=MBS_Retreating)
2739 &&(marineStatusPointer->behaviourState!=MBS_Approaching)
2740 &&(marineStatusPointer->behaviourState!=MBS_GetWeapon)
2741 &&(marineStatusPointer->behaviourState!=MBS_Taunting)
2742 &&(marineStatusPointer->behaviourState!=MBS_Avoidance)
2743 &&(marineStatusPointer->behaviourState!=MBS_Dying)
2744 ) {
2745 Marine_Enter_Retreat_State(sbPtr);
2746 }
2747 }
2748
2749 if (marineStatusPointer->My_Weapon->id==MNPCW_Minigun) {
2750 DELTA_CONTROLLER *mgd=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
2751 if (mgd) {
2752 NPC_Maintain_Minigun(sbPtr,mgd);
2753 }
2754 }
2755
2756 /* if we have actually died, we need to remove the strategyblock... so
2757 do this here */
2758 if((marineStatusPointer->behaviourState == MBS_Dying)&&(marineStatusPointer->stateTimer <= 0)) {
2759
2760 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle);
2761 if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle2);
2762
2763 DestroyAnyStrategyBlock(sbPtr);
2764 }
2765
2766 marineStatusPointer->lastmodule=sbPtr->containingModule->m_aimodule;
2767
2768 if (sbPtr->SBdptr) {
2769 /* I reckon only near trackers wheep. */
2770 if (tracker_noise==1) {
2771 Sound_Play(SID_TRACKER_CLICK,"d",&sbPtr->DynPtr->Position);
2772 } else if (tracker_noise==2) {
2773 Sound_Play(SID_TRACKER_WHEEP,"d",&sbPtr->DynPtr->Position);
2774 }
2775 }
2776
2777 /* Update squad stats. */
2778 if ((marineStatusPointer->behaviourState==MBS_Responding)
2779 ||((marineStatusPointer->behaviourState==MBS_Avoidance)
2780 &&(marineStatusPointer->lastState==MBS_Responding))) {
2781
2782 NpcSquad.Alt_RespondingMarines++;
2783 }
2784
2785 if ((marineStatusPointer->Mission==MM_RunAroundOnFire)
2786 &&(sbPtr->SBdptr)) {
2787
2788 NpcSquad.Alt_NearBurningMarines++;
2789 }
2790
2791 if ((sbPtr->SBdptr)&&(
2792 (marineStatusPointer->behaviourState==MBS_Retreating)
2793 ||(marineStatusPointer->Mission==MM_RunAroundOnFire)
2794 )) {
2795 /* Burning marines are considered panicked, too. */
2796
2797 NpcSquad.Alt_NearPanickedMarines++;
2798 }
2799
2800 if ((sbPtr->SBdptr)&&(marineStatusPointer->My_Weapon->ARealMarine)&&(
2801 (marineStatusPointer->behaviourState!=MBS_Retreating)
2802 &&(marineStatusPointer->behaviourState!=MBS_Dying)
2803 )) {
2804
2805 NpcSquad.Alt_NearUnpanickedMarines++;
2806 }
2807
2808 /* Make marines heal, really slowly? */
2809 HModel_Regen(&marineStatusPointer->HModelController,(120*ONE_FIXED));
2810 /* Two minutes. Only heals sections, too. */
2811
2812 /* Change the face if we can... */
2813 Marine_UpdateFace(sbPtr);
2814
2815 /* And finally, update lastframe flag. */
2816 Marine_ConsiderFallingDamage(sbPtr);
2817
2818 }
2819
EndMarineMuzzleFlash(STRATEGYBLOCK * sbPtr)2820 void EndMarineMuzzleFlash(STRATEGYBLOCK *sbPtr) {
2821
2822 MARINE_STATUS_BLOCK *marineStatusPointer;
2823
2824 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
2825 LOCALASSERT(marineStatusPointer);
2826
2827 if(marineStatusPointer->myGunFlash)
2828 {
2829 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
2830 marineStatusPointer->myGunFlash = NULL;
2831 }
2832
2833 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
2834 Sound_Stop(marineStatusPointer->soundHandle);
2835 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
2836 }
2837
2838 }
2839
InitMission(STRATEGYBLOCK * sbPtr,MARINE_MISSION mission)2840 void InitMission(STRATEGYBLOCK *sbPtr,MARINE_MISSION mission) {
2841
2842 MARINE_STATUS_BLOCK *marineStatus;
2843
2844 marineStatus = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
2845 LOCALASSERT(marineStatus);
2846
2847 switch (mission) {
2848 case MM_RunAroundOnFire:
2849 marineStatus->Mission=MM_RunAroundOnFire;
2850 marineStatus->behaviourState = MBS_Wandering;
2851 marineStatus->lastState = MBS_Waiting;
2852 /* Shouldn't need a sequence force. */
2853 break;
2854 case MM_Guard:
2855 marineStatus->Mission=MM_Guard;
2856 marineStatus->behaviourState = MBS_Sentry;
2857 marineStatus->lastState = MBS_Waiting;
2858 Marine_Enter_SentryMode_State(sbPtr);
2859 break;
2860 case MM_LocalGuard:
2861 marineStatus->Mission=MM_LocalGuard;
2862 marineStatus->behaviourState = MBS_Waiting;
2863 marineStatus->lastState = MBS_Waiting;
2864 Marine_Enter_Wait_State(sbPtr);
2865 break;
2866 case MM_NonCom:
2867 marineStatus->Mission=MM_NonCom;
2868 marineStatus->behaviourState = MBS_Waiting;
2869 marineStatus->lastState = MBS_Waiting;
2870 Marine_Enter_Wait_State(sbPtr);
2871 break;
2872 case MM_Wait_Then_Wander:
2873 marineStatus->Mission=MM_Wait_Then_Wander;
2874 marineStatus->behaviourState = MBS_Waiting;
2875 marineStatus->lastState = MBS_Waiting;
2876 Marine_Enter_Wait_State(sbPtr);
2877 break;
2878 case MM_Pathfinder:
2879 marineStatus->Mission=MM_Pathfinder;
2880 marineStatus->behaviourState = MBS_Pathfinding;
2881 marineStatus->lastState = MBS_Waiting;
2882 Marine_Enter_Pathfinder_State(sbPtr);
2883 break;
2884 case MM_Wander:
2885 default:
2886 marineStatus->Mission=MM_Wander;
2887 marineStatus->behaviourState = MBS_Approaching;
2888 marineStatus->lastState = MBS_Waiting;
2889 Marine_Enter_Approach_State(sbPtr);
2890 break;
2891 }
2892
2893 }
2894
WanderMission_Control(STRATEGYBLOCK * sbPtr)2895 void WanderMission_Control(STRATEGYBLOCK *sbPtr) {
2896
2897 MARINE_STATUS_BLOCK *marineStatusPointer;
2898 STATE_RETURN_CONDITION state_result;
2899 int marineIsNear;
2900
2901 LOCALASSERT(sbPtr);
2902 LOCALASSERT(sbPtr->containingModule);
2903 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
2904 LOCALASSERT(marineStatusPointer);
2905
2906
2907 /* Current Behaviour. */
2908
2909 if(sbPtr->SBdptr) {
2910 marineIsNear=1;
2911 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
2912 } else {
2913 marineIsNear=0;
2914 }
2915
2916 {
2917
2918 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
2919 if (marineStatusPointer->Mission==MM_Wait_Then_Wander) {
2920 /* A bit of a cheat. */
2921 PrintDebuggingText("Wait Then ");
2922 }
2923 }
2924
2925 switch(marineStatusPointer->behaviourState)
2926 {
2927 case(MBS_Approaching):
2928 {
2929 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
2930 PrintDebuggingText("Wander marine approach in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
2931 }
2932
2933 if(marineIsNear) {
2934 state_result=Execute_MNS_Approach(sbPtr);
2935 CentreMarineElevation(sbPtr);
2936 } else {
2937 state_result=Execute_MFS_Approach(sbPtr);
2938 }
2939 WanderMission_SwitchState(sbPtr,state_result);
2940 break;
2941 }
2942 case(MBS_Firing):
2943 {
2944 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
2945 PrintDebuggingText("Wander marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
2946 }
2947
2948 if (marineIsNear) {
2949 state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr);
2950 SetMarineElevation(sbPtr);
2951 } else {
2952 state_result=Execute_MFS_Firing(sbPtr);
2953 }
2954 WanderMission_SwitchState(sbPtr,state_result);
2955 break;
2956 }
2957 case(MBS_PumpAction):
2958 {
2959 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
2960 PrintDebuggingText("Wander marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
2961 }
2962
2963 if (marineIsNear) {
2964 state_result=Execute_MNS_PumpAction(sbPtr);
2965 CentreMarineElevation(sbPtr);
2966 } else {
2967 state_result=Execute_MNS_PumpAction(sbPtr);
2968 }
2969 WanderMission_SwitchState(sbPtr,state_result);
2970 break;
2971 }
2972 case(MBS_PanicFire):
2973 {
2974 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
2975 PrintDebuggingText("Wander marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
2976 }
2977
2978 if (marineIsNear) {
2979 state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr);
2980 CentreMarineElevation(sbPtr);
2981 } else {
2982 state_result=Execute_MFS_Firing(sbPtr);
2983 }
2984 WanderMission_SwitchState(sbPtr,state_result);
2985 break;
2986 }
2987 case(MBS_Avoidance):
2988 {
2989 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
2990 PrintDebuggingText("Wander marine ");
2991 switch (marineStatusPointer->avoidanceManager.substate) {
2992 default:
2993 case AvSS_FreeMovement:
2994 PrintDebuggingText("Avoidance Level 0");
2995 break;
2996 case AvSS_FirstAvoidance:
2997 PrintDebuggingText("Avoidance Level 1");
2998 break;
2999 case AvSS_SecondAvoidance:
3000 PrintDebuggingText("Avoidance Level 2");
3001 break;
3002 case AvSS_ThirdAvoidance:
3003 PrintDebuggingText("Avoidance Level 3");
3004 break;
3005 }
3006 PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3007 }
3008 if(marineIsNear) {
3009 state_result=Execute_MNS_Avoidance(sbPtr);
3010 CentreMarineElevation(sbPtr);
3011 } else {
3012 state_result=Execute_MFS_Avoidance(sbPtr);
3013 }
3014 WanderMission_SwitchState(sbPtr,state_result);
3015 break;
3016 }
3017 case(MBS_Wandering):
3018 {
3019 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3020 PrintDebuggingText("Wander marine wander in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3021 }
3022
3023 if (marineIsNear) {
3024 state_result=Execute_MNS_Wander(sbPtr);
3025 CentreMarineElevation(sbPtr);
3026 } else {
3027 state_result=Execute_MFS_Wander(sbPtr);
3028 }
3029 WanderMission_SwitchState(sbPtr,state_result);
3030 break;
3031 }
3032 case(MBS_Responding):
3033 {
3034 /* Closest to hunt. */
3035 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3036 PrintDebuggingText("Wander marine responding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3037 }
3038
3039 if (marineIsNear) {
3040 state_result=Execute_MNS_Respond(sbPtr);
3041 CentreMarineElevation(sbPtr);
3042 } else {
3043 state_result=Execute_MFS_Respond(sbPtr);
3044 }
3045 WanderMission_SwitchState(sbPtr,state_result);
3046 break;
3047 }
3048 case(MBS_Retreating):
3049 {
3050 /* Real men never retreat! */
3051 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3052 PrintDebuggingText("Wander marine Retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3053 }
3054
3055 if (marineIsNear) {
3056 state_result=Execute_MNS_Retreat(sbPtr);
3057 CentreMarineElevation(sbPtr);
3058 } else {
3059 state_result=Execute_MFS_Retreat(sbPtr);
3060 }
3061 WanderMission_SwitchState(sbPtr,state_result);
3062 break;
3063 }
3064 case(MBS_Waiting):
3065 {
3066 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3067 PrintDebuggingText("Wander marine wait in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3068 }
3069
3070 if (marineIsNear) {
3071 state_result=Execute_MNS_Wait(sbPtr);
3072 CentreMarineElevation(sbPtr);
3073 } else {
3074 state_result=Execute_MFS_Wait(sbPtr);
3075 }
3076 WanderMission_SwitchState(sbPtr,state_result);
3077 break;
3078 }
3079 case(MBS_Sentry):
3080 {
3081 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3082 PrintDebuggingText("Wander marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3083 }
3084 GLOBALASSERT(0);
3085 if(marineIsNear) {
3086 state_result=Execute_MNS_SentryMode(sbPtr);
3087 CentreMarineElevation(sbPtr);
3088 } else {
3089 state_result=Execute_MFS_Wait(sbPtr);
3090 }
3091 WanderMission_SwitchState(sbPtr,state_result);
3092 break;
3093 }
3094 case(MBS_Dying):
3095 {
3096 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3097 PrintDebuggingText("Wander marine dying in %s\n",sbPtr->containingModule->name);
3098 }
3099 if (marineIsNear) {
3100 Execute_Dying(sbPtr);
3101 } else {
3102 Execute_Dying(sbPtr);
3103 }
3104 break;
3105 }
3106 case(MBS_Taunting):
3107 {
3108 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3109 PrintDebuggingText("Wander marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3110 }
3111
3112 if(marineIsNear) {
3113 state_result=Execute_MNS_Taunting(sbPtr);
3114 CentreMarineElevation(sbPtr);
3115 } else {
3116 state_result=Execute_MNS_Taunting(sbPtr);
3117 }
3118 WanderMission_SwitchState(sbPtr,state_result);
3119 break;
3120 }
3121 case(MBS_Reloading):
3122 {
3123 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3124 PrintDebuggingText("Wander marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3125 }
3126
3127 if(marineIsNear) {
3128 state_result=Execute_MNS_Reloading(sbPtr);
3129 CentreMarineElevation(sbPtr);
3130 } else {
3131 state_result=Execute_MNS_Reloading(sbPtr);
3132 }
3133 WanderMission_SwitchState(sbPtr,state_result);
3134 break;
3135 }
3136 case(MBS_PanicReloading):
3137 {
3138 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3139 PrintDebuggingText("Wander marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3140 }
3141
3142 if(marineIsNear) {
3143 state_result=Execute_MNS_PanicReloading(sbPtr);
3144 CentreMarineElevation(sbPtr);
3145 } else {
3146 state_result=Execute_MNS_PanicReloading(sbPtr);
3147 }
3148 WanderMission_SwitchState(sbPtr,state_result);
3149 break;
3150 }
3151 case(MBS_GetWeapon):
3152 {
3153 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3154 PrintDebuggingText("Wander marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3155 }
3156
3157 if(marineIsNear) {
3158 state_result=Execute_MNS_GetWeapon(sbPtr);
3159 CentreMarineElevation(sbPtr);
3160 } else {
3161 state_result=Execute_MNS_GetWeapon(sbPtr);
3162 }
3163 WanderMission_SwitchState(sbPtr,state_result);
3164 break;
3165 }
3166 case MBS_Returning:
3167 case MBS_Pathfinding:
3168 {
3169 /* How the hell did you get here?!? */
3170 Marine_Enter_Wander_State(sbPtr);
3171 break;
3172 }
3173 case(MBS_AcidAvoidance):
3174 {
3175 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3176 PrintDebuggingText("Wander marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3177 }
3178
3179 if (marineIsNear) {
3180 state_result=Execute_MNS_AcidAvoidance(sbPtr);
3181 CentreMarineElevation(sbPtr);
3182 } else {
3183 Marine_Enter_Wait_State(sbPtr);
3184 break;
3185 }
3186 WanderMission_SwitchState(sbPtr,state_result);
3187 break;
3188 }
3189 default:
3190 {
3191 LOGDXFMT(("Marine in unsupported state %d!\n",marineStatusPointer->behaviourState));
3192 LOCALASSERT(1==0);
3193 }
3194 }
3195 }
3196
3197 if (!marineIsNear) {
3198
3199 /* check here to see if marine is in a proximity door - if so, trigger it to open. */
3200 {
3201 MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
3202
3203 if(doorType == MDT_ProxDoor)
3204 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1;
3205 }
3206
3207 /* lastly, do a containment test: to make sure that we are inside a module. */
3208 #if UseLocalAssert
3209 {
3210 VECTORCH localCoords;
3211 MODULE *thisModule = sbPtr->containingModule;
3212
3213 LOCALASSERT(thisModule);
3214
3215 localCoords = sbPtr->DynPtr->Position;
3216 localCoords.vx -= thisModule->m_world.vx;
3217 localCoords.vy -= thisModule->m_world.vy;
3218 localCoords.vz -= thisModule->m_world.vz;
3219
3220 if(PointIsInModule(thisModule, &localCoords)==0)
3221 {
3222 textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n");
3223 LOCALASSERT(1==0);
3224 }
3225 }
3226 #endif
3227 }
3228
3229 }
3230
PathfinderMission_Control(STRATEGYBLOCK * sbPtr)3231 void PathfinderMission_Control(STRATEGYBLOCK *sbPtr) {
3232
3233 MARINE_STATUS_BLOCK *marineStatusPointer;
3234 STATE_RETURN_CONDITION state_result;
3235 int marineIsNear;
3236
3237 LOCALASSERT(sbPtr);
3238 LOCALASSERT(sbPtr->containingModule);
3239 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
3240 LOCALASSERT(marineStatusPointer);
3241
3242
3243 /* Current Behaviour. */
3244
3245 if(sbPtr->SBdptr) {
3246 marineIsNear=1;
3247 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
3248 } else {
3249 marineIsNear=0;
3250 }
3251
3252 {
3253
3254 switch(marineStatusPointer->behaviourState)
3255 {
3256 case(MBS_Approaching):
3257 {
3258 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3259 PrintDebuggingText("Pathfinder marine approach in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3260 }
3261
3262 if(marineIsNear) {
3263 state_result=Execute_MNS_Approach(sbPtr);
3264 CentreMarineElevation(sbPtr);
3265 } else {
3266 state_result=Execute_MFS_Approach(sbPtr);
3267 }
3268 PathfinderMission_SwitchState(sbPtr,state_result);
3269 break;
3270 }
3271 case(MBS_Firing):
3272 {
3273 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3274 PrintDebuggingText("Pathfinder marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3275 }
3276
3277 if (marineIsNear) {
3278 state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr);
3279 SetMarineElevation(sbPtr);
3280 } else {
3281 state_result=Execute_MFS_Firing(sbPtr);
3282 }
3283 PathfinderMission_SwitchState(sbPtr,state_result);
3284 break;
3285 }
3286 case(MBS_PumpAction):
3287 {
3288 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3289 PrintDebuggingText("Pathfinder marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3290 }
3291
3292 if (marineIsNear) {
3293 state_result=Execute_MNS_PumpAction(sbPtr);
3294 CentreMarineElevation(sbPtr);
3295 } else {
3296 state_result=Execute_MNS_PumpAction(sbPtr);
3297 }
3298 PathfinderMission_SwitchState(sbPtr,state_result);
3299 break;
3300 }
3301 case(MBS_PanicFire):
3302 {
3303 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3304 PrintDebuggingText("Pathfinder marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3305 }
3306
3307 if (marineIsNear) {
3308 state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr);
3309 CentreMarineElevation(sbPtr);
3310 } else {
3311 state_result=Execute_MFS_Firing(sbPtr);
3312 }
3313 PathfinderMission_SwitchState(sbPtr,state_result);
3314 break;
3315 }
3316 case(MBS_Avoidance):
3317 {
3318 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3319 PrintDebuggingText("Pathfinder marine ");
3320 switch (marineStatusPointer->avoidanceManager.substate) {
3321 default:
3322 case AvSS_FreeMovement:
3323 PrintDebuggingText("Avoidance Level 0");
3324 break;
3325 case AvSS_FirstAvoidance:
3326 PrintDebuggingText("Avoidance Level 1");
3327 break;
3328 case AvSS_SecondAvoidance:
3329 PrintDebuggingText("Avoidance Level 2");
3330 break;
3331 case AvSS_ThirdAvoidance:
3332 PrintDebuggingText("Avoidance Level 3");
3333 break;
3334 }
3335 PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3336 }
3337 if(marineIsNear) {
3338 state_result=Execute_MNS_Avoidance(sbPtr);
3339 CentreMarineElevation(sbPtr);
3340 } else {
3341 state_result=Execute_MFS_Avoidance(sbPtr);
3342 }
3343 PathfinderMission_SwitchState(sbPtr,state_result);
3344 break;
3345 }
3346 case(MBS_Wandering):
3347 {
3348 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3349 PrintDebuggingText("Pathfinder marine wander in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3350 }
3351
3352 if (marineIsNear) {
3353 state_result=Execute_MNS_Wander(sbPtr);
3354 CentreMarineElevation(sbPtr);
3355 } else {
3356 state_result=Execute_MFS_Wander(sbPtr);
3357 }
3358 PathfinderMission_SwitchState(sbPtr,state_result);
3359 break;
3360 }
3361 case(MBS_Responding):
3362 {
3363 /* Closest to hunt. */
3364 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3365 PrintDebuggingText("Pathfinder marine responding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3366 }
3367
3368 if (marineIsNear) {
3369 state_result=Execute_MNS_Respond(sbPtr);
3370 CentreMarineElevation(sbPtr);
3371 } else {
3372 state_result=Execute_MFS_Respond(sbPtr);
3373 }
3374 PathfinderMission_SwitchState(sbPtr,state_result);
3375 break;
3376 }
3377 case(MBS_Retreating):
3378 {
3379 /* Real men never retreat! */
3380 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3381 PrintDebuggingText("Pathfinder marine retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3382 }
3383
3384 if (marineIsNear) {
3385 state_result=Execute_MNS_Retreat(sbPtr);
3386 CentreMarineElevation(sbPtr);
3387 } else {
3388 state_result=Execute_MFS_Retreat(sbPtr);
3389 }
3390 PathfinderMission_SwitchState(sbPtr,state_result);
3391 break;
3392 }
3393 case(MBS_Waiting):
3394 {
3395 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3396 PrintDebuggingText("Pathfinder marine wait in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3397 }
3398
3399 if (marineIsNear) {
3400 state_result=Execute_MNS_Wait(sbPtr);
3401 CentreMarineElevation(sbPtr);
3402 } else {
3403 state_result=Execute_MFS_Wait(sbPtr);
3404 }
3405 PathfinderMission_SwitchState(sbPtr,state_result);
3406 break;
3407 }
3408 case(MBS_Sentry):
3409 {
3410 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3411 PrintDebuggingText("Pathfinder marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3412 }
3413 GLOBALASSERT(0);
3414 if(marineIsNear) {
3415 state_result=Execute_MNS_SentryMode(sbPtr);
3416 CentreMarineElevation(sbPtr);
3417 } else {
3418 state_result=Execute_MFS_Wait(sbPtr);
3419 }
3420 PathfinderMission_SwitchState(sbPtr,state_result);
3421 break;
3422 }
3423 case(MBS_Dying):
3424 {
3425 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3426 PrintDebuggingText("Pathfinder marine dying in %s\n",sbPtr->containingModule->name);
3427 }
3428 if (marineIsNear) {
3429 Execute_Dying(sbPtr);
3430 } else {
3431 Execute_Dying(sbPtr);
3432 }
3433 break;
3434 }
3435 case(MBS_Pathfinding):
3436 {
3437 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3438 PrintDebuggingText("Pathfinder marine pathfinding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3439 }
3440
3441 if (marineIsNear) {
3442 state_result=Execute_MNS_Pathfinder(sbPtr);
3443 CentreMarineElevation(sbPtr);
3444 } else {
3445 state_result=Execute_MFS_Pathfinder(sbPtr);
3446 }
3447 PathfinderMission_SwitchState(sbPtr,state_result);
3448 break;
3449 }
3450 case(MBS_Taunting):
3451 {
3452 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3453 PrintDebuggingText("Pathfinder marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3454 }
3455
3456 if(marineIsNear) {
3457 state_result=Execute_MNS_Taunting(sbPtr);
3458 CentreMarineElevation(sbPtr);
3459 } else {
3460 state_result=Execute_MNS_Taunting(sbPtr);
3461 }
3462 PathfinderMission_SwitchState(sbPtr,state_result);
3463 break;
3464 }
3465 case(MBS_Returning):
3466 {
3467 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3468 PrintDebuggingText("Pathfinder marine returning in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3469 }
3470
3471 if (marineIsNear) {
3472 state_result=Execute_MNS_Return(sbPtr);
3473 CentreMarineElevation(sbPtr);
3474 } else {
3475 state_result=Execute_MFS_Return(sbPtr);
3476 }
3477 PathfinderMission_SwitchState(sbPtr,state_result);
3478 break;
3479 }
3480 case(MBS_Reloading):
3481 {
3482 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3483 PrintDebuggingText("Pathfinder marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3484 }
3485
3486 if(marineIsNear) {
3487 state_result=Execute_MNS_Reloading(sbPtr);
3488 CentreMarineElevation(sbPtr);
3489 } else {
3490 state_result=Execute_MNS_Reloading(sbPtr);
3491 }
3492 PathfinderMission_SwitchState(sbPtr,state_result);
3493 break;
3494 }
3495 case(MBS_PanicReloading):
3496 {
3497 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3498 PrintDebuggingText("Pathfinder marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3499 }
3500
3501 if(marineIsNear) {
3502 state_result=Execute_MNS_PanicReloading(sbPtr);
3503 CentreMarineElevation(sbPtr);
3504 } else {
3505 state_result=Execute_MNS_PanicReloading(sbPtr);
3506 }
3507 PathfinderMission_SwitchState(sbPtr,state_result);
3508 break;
3509 }
3510 case(MBS_GetWeapon):
3511 {
3512 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3513 PrintDebuggingText("Pathfinder marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3514 }
3515
3516 if(marineIsNear) {
3517 state_result=Execute_MNS_GetWeapon(sbPtr);
3518 CentreMarineElevation(sbPtr);
3519 } else {
3520 state_result=Execute_MNS_GetWeapon(sbPtr);
3521 }
3522 PathfinderMission_SwitchState(sbPtr,state_result);
3523 break;
3524 }
3525 case(MBS_AcidAvoidance):
3526 {
3527 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3528 PrintDebuggingText("Prahfinder marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3529 }
3530
3531 if (marineIsNear) {
3532 state_result=Execute_MNS_AcidAvoidance(sbPtr);
3533 CentreMarineElevation(sbPtr);
3534 } else {
3535 Marine_Enter_Wait_State(sbPtr);
3536 break;
3537 }
3538 PathfinderMission_SwitchState(sbPtr,state_result);
3539 break;
3540 }
3541 default:
3542 {
3543 LOGDXFMT(("Marine in unsupported state %d!\n",marineStatusPointer->behaviourState));
3544 LOCALASSERT(1==0);
3545 }
3546 }
3547 }
3548
3549 if (!marineIsNear) {
3550
3551 /* check here to see if marine is in a proximity door - if so, trigger it to open. */
3552 {
3553 MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
3554
3555 if(doorType == MDT_ProxDoor)
3556 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1;
3557 }
3558
3559 /* lastly, do a containment test: to make sure that we are inside a module. */
3560 #if UseLocalAssert
3561 {
3562 VECTORCH localCoords;
3563 MODULE *thisModule = sbPtr->containingModule;
3564
3565 LOCALASSERT(thisModule);
3566
3567 localCoords = sbPtr->DynPtr->Position;
3568 localCoords.vx -= thisModule->m_world.vx;
3569 localCoords.vy -= thisModule->m_world.vy;
3570 localCoords.vz -= thisModule->m_world.vz;
3571
3572 if(PointIsInModule(thisModule, &localCoords)==0)
3573 {
3574 textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n");
3575 LOCALASSERT(1==0);
3576 }
3577 }
3578 #endif
3579 }
3580
3581 }
3582
GuardMission_Control(STRATEGYBLOCK * sbPtr)3583 void GuardMission_Control(STRATEGYBLOCK *sbPtr) {
3584
3585 MARINE_STATUS_BLOCK *marineStatusPointer;
3586 STATE_RETURN_CONDITION state_result;
3587 int marineIsNear;
3588
3589 LOCALASSERT(sbPtr);
3590 LOCALASSERT(sbPtr->containingModule);
3591 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
3592 LOCALASSERT(marineStatusPointer);
3593
3594 /* Firstly, fix missionmodule. */
3595
3596 if (marineStatusPointer->missionmodule==NULL) {
3597 marineStatusPointer->missionmodule=sbPtr->containingModule->m_aimodule;
3598 marineStatusPointer->my_spot=sbPtr->DynPtr->Position;
3599 }
3600
3601 if(sbPtr->SBdptr) {
3602 marineIsNear=1;
3603 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
3604 } else {
3605 marineIsNear=0;
3606 }
3607
3608 {
3609
3610 switch(marineStatusPointer->behaviourState)
3611 {
3612 case(MBS_Approaching):
3613 {
3614 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3615 PrintDebuggingText("Guard marine approaching in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3616 }
3617
3618 GLOBALASSERT(0);
3619 if (marineIsNear) {
3620 state_result=Execute_MNS_Approach(sbPtr);
3621 CentreMarineElevation(sbPtr);
3622 } else {
3623 state_result=Execute_MFS_Wander(sbPtr);
3624 }
3625 GuardMission_SwitchState(sbPtr,state_result);
3626 break;
3627 }
3628 case(MBS_Firing):
3629 {
3630 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3631 PrintDebuggingText("Guard marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3632 }
3633
3634 if (marineIsNear) {
3635 state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr);
3636 SetMarineElevation(sbPtr);
3637 } else {
3638 state_result=Execute_MFS_Firing(sbPtr);
3639 }
3640 GuardMission_SwitchState(sbPtr,state_result);
3641 break;
3642 }
3643 case(MBS_PumpAction):
3644 {
3645 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3646 PrintDebuggingText("Guard marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3647 }
3648
3649 if (marineIsNear) {
3650 state_result=Execute_MNS_PumpAction(sbPtr);
3651 CentreMarineElevation(sbPtr);
3652 } else {
3653 state_result=Execute_MNS_PumpAction(sbPtr);
3654 }
3655 GuardMission_SwitchState(sbPtr,state_result);
3656 break;
3657 }
3658 case(MBS_PanicFire):
3659 {
3660 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3661 PrintDebuggingText("Guard marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3662 }
3663
3664 if (marineIsNear) {
3665 state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr);
3666 CentreMarineElevation(sbPtr);
3667 } else {
3668 state_result=Execute_MFS_Firing(sbPtr);
3669 }
3670 GuardMission_SwitchState(sbPtr,state_result);
3671 break;
3672 }
3673 case(MBS_Avoidance):
3674 {
3675 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3676 PrintDebuggingText("Guard marine ");
3677 switch (marineStatusPointer->avoidanceManager.substate) {
3678 default:
3679 case AvSS_FreeMovement:
3680 PrintDebuggingText("Avoidance Level 0");
3681 break;
3682 case AvSS_FirstAvoidance:
3683 PrintDebuggingText("Avoidance Level 1");
3684 break;
3685 case AvSS_SecondAvoidance:
3686 PrintDebuggingText("Avoidance Level 2");
3687 break;
3688 case AvSS_ThirdAvoidance:
3689 PrintDebuggingText("Avoidance Level 3");
3690 break;
3691 }
3692 PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3693 }
3694
3695 if (marineIsNear) {
3696 state_result=Execute_MNS_Avoidance(sbPtr);
3697 CentreMarineElevation(sbPtr);
3698 } else {
3699 state_result=Execute_MFS_Avoidance(sbPtr);
3700 }
3701 GuardMission_SwitchState(sbPtr,state_result);
3702 break;
3703 }
3704 case(MBS_Wandering):
3705 {
3706 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3707 PrintDebuggingText("Guard marine wandering in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3708 }
3709
3710 if (marineIsNear) {
3711 state_result=Execute_MNS_Wander(sbPtr);
3712 CentreMarineElevation(sbPtr);
3713 } else {
3714 state_result=Execute_MFS_Wait(sbPtr);
3715 }
3716 GuardMission_SwitchState(sbPtr,state_result);
3717 break;
3718 }
3719 case(MBS_Retreating):
3720 {
3721 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3722 PrintDebuggingText("Guard marine retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3723 }
3724
3725 /* Real men never retreat! */
3726 if (marineIsNear) {
3727 state_result=Execute_MNS_Retreat(sbPtr);
3728 CentreMarineElevation(sbPtr);
3729 } else {
3730 state_result=Execute_MFS_Retreat(sbPtr);
3731 }
3732 GuardMission_SwitchState(sbPtr,state_result);
3733 break;
3734 }
3735 case(MBS_Waiting):
3736 {
3737 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3738 PrintDebuggingText("Guard marine waiting in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3739 }
3740
3741 if (marineIsNear) {
3742 state_result=Execute_MNS_SentryMode(sbPtr);
3743 CentreMarineElevation(sbPtr);
3744 } else {
3745 state_result=Execute_MFS_SentryMode(sbPtr);
3746 }
3747 state_result=SRC_Request_Wait; /* Go back to sentry. */
3748 GuardMission_SwitchState(sbPtr,state_result);
3749 break;
3750 }
3751 case(MBS_Responding):
3752 case(MBS_Sentry):
3753 {
3754 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3755 PrintDebuggingText("Guard marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3756 }
3757
3758 if (marineIsNear) {
3759 state_result=Execute_MNS_SentryMode(sbPtr);
3760 CentreMarineElevation(sbPtr);
3761 } else {
3762 state_result=Execute_MFS_SentryMode(sbPtr);
3763 }
3764 GuardMission_SwitchState(sbPtr,state_result);
3765 break;
3766 }
3767 case(MBS_Dying):
3768 {
3769 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3770 PrintDebuggingText("Guard marine dying in %s\n",sbPtr->containingModule->name);
3771 }
3772
3773 if (marineIsNear) {
3774 Execute_Dying(sbPtr);
3775 } else {
3776 Execute_Dying(sbPtr);
3777 }
3778 break;
3779 }
3780 case(MBS_Taunting):
3781 {
3782 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3783 PrintDebuggingText("Guard marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3784 }
3785
3786 if(marineIsNear) {
3787 state_result=Execute_MNS_Taunting(sbPtr);
3788 CentreMarineElevation(sbPtr);
3789 } else {
3790 state_result=Execute_MNS_Taunting(sbPtr);
3791 }
3792 GuardMission_SwitchState(sbPtr,state_result);
3793 break;
3794 }
3795 case(MBS_Reloading):
3796 {
3797 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3798 PrintDebuggingText("Guard marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3799 }
3800
3801 if(marineIsNear) {
3802 state_result=Execute_MNS_Reloading(sbPtr);
3803 CentreMarineElevation(sbPtr);
3804 } else {
3805 state_result=Execute_MNS_Reloading(sbPtr);
3806 }
3807 GuardMission_SwitchState(sbPtr,state_result);
3808 break;
3809 }
3810 case(MBS_PanicReloading):
3811 {
3812 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3813 PrintDebuggingText("Guard marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3814 }
3815
3816 if(marineIsNear) {
3817 state_result=Execute_MNS_PanicReloading(sbPtr);
3818 CentreMarineElevation(sbPtr);
3819 } else {
3820 state_result=Execute_MNS_PanicReloading(sbPtr);
3821 }
3822 GuardMission_SwitchState(sbPtr,state_result);
3823 break;
3824 }
3825 case(MBS_GetWeapon):
3826 {
3827 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3828 PrintDebuggingText("Guard marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3829 }
3830
3831 if(marineIsNear) {
3832 state_result=Execute_MNS_GetWeapon(sbPtr);
3833 CentreMarineElevation(sbPtr);
3834 } else {
3835 state_result=Execute_MNS_GetWeapon(sbPtr);
3836 }
3837 GuardMission_SwitchState(sbPtr,state_result);
3838 break;
3839 }
3840 case MBS_Returning:
3841 case MBS_Pathfinding:
3842 {
3843 /* How the hell did you get here?!? */
3844 Marine_Enter_Wander_State(sbPtr);
3845 break;
3846 }
3847 case(MBS_AcidAvoidance):
3848 {
3849 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3850 PrintDebuggingText("Guard marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3851 }
3852
3853 if (marineIsNear) {
3854 state_result=Execute_MNS_AcidAvoidance(sbPtr);
3855 CentreMarineElevation(sbPtr);
3856 } else {
3857 Marine_Enter_Wait_State(sbPtr);
3858 break;
3859 }
3860 GuardMission_SwitchState(sbPtr,state_result);
3861 break;
3862 }
3863 default:
3864 {
3865 LOGDXFMT(("Guard marine in unsupported state %d!\n",marineStatusPointer->behaviourState));
3866 LOCALASSERT(1==0);
3867 }
3868 }
3869 }
3870
3871 if (!marineIsNear) {
3872
3873 /* check here to see if marine is in a proximity door - if so, trigger it to open. */
3874 {
3875 MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
3876
3877 if(doorType == MDT_ProxDoor)
3878 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1;
3879 }
3880
3881 /* lastly, do a containment test: to make sure that we are inside a module. */
3882 #if UseLocalAssert
3883 {
3884 VECTORCH localCoords;
3885 MODULE *thisModule = sbPtr->containingModule;
3886
3887 LOCALASSERT(thisModule);
3888
3889 localCoords = sbPtr->DynPtr->Position;
3890 localCoords.vx -= thisModule->m_world.vx;
3891 localCoords.vy -= thisModule->m_world.vy;
3892 localCoords.vz -= thisModule->m_world.vz;
3893
3894 if(PointIsInModule(thisModule, &localCoords)==0)
3895 {
3896 textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n");
3897 LOCALASSERT(1==0);
3898 }
3899 }
3900 #endif
3901 }
3902
3903 }
3904
LocalGuardMission_Control(STRATEGYBLOCK * sbPtr)3905 void LocalGuardMission_Control(STRATEGYBLOCK *sbPtr) {
3906
3907 MARINE_STATUS_BLOCK *marineStatusPointer;
3908 STATE_RETURN_CONDITION state_result;
3909 int marineIsNear;
3910
3911 LOCALASSERT(sbPtr);
3912 LOCALASSERT(sbPtr->containingModule);
3913 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
3914 LOCALASSERT(marineStatusPointer);
3915
3916 /* Firstly, fix missionmodule. */
3917
3918 if (marineStatusPointer->missionmodule==NULL) {
3919 marineStatusPointer->missionmodule=sbPtr->containingModule->m_aimodule;
3920 }
3921
3922 if(sbPtr->SBdptr) {
3923 marineIsNear=1;
3924 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
3925 } else {
3926 marineIsNear=0;
3927 }
3928
3929 {
3930
3931 switch(marineStatusPointer->behaviourState)
3932 {
3933 case(MBS_Approaching):
3934 {
3935 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3936 PrintDebuggingText("Local Guard marine approaching in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3937 }
3938
3939 if (marineIsNear) {
3940 state_result=Execute_MNS_Approach(sbPtr);
3941 CentreMarineElevation(sbPtr);
3942 } else {
3943 state_result=Execute_MFS_Wander(sbPtr);
3944 }
3945 LocalGuardMission_SwitchState(sbPtr,state_result);
3946 break;
3947 }
3948 case(MBS_Firing):
3949 {
3950 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3951 PrintDebuggingText("Local Guard marine firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3952 }
3953
3954 if (marineIsNear) {
3955 state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr);
3956 SetMarineElevation(sbPtr);
3957 } else {
3958 state_result=Execute_MFS_Firing(sbPtr);
3959 }
3960 LocalGuardMission_SwitchState(sbPtr,state_result);
3961 break;
3962 }
3963 case(MBS_PumpAction):
3964 {
3965 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3966 PrintDebuggingText("Local Guard marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3967 }
3968
3969 if (marineIsNear) {
3970 state_result=Execute_MNS_PumpAction(sbPtr);
3971 CentreMarineElevation(sbPtr);
3972 } else {
3973 state_result=Execute_MNS_PumpAction(sbPtr);
3974 }
3975 LocalGuardMission_SwitchState(sbPtr,state_result);
3976 break;
3977 }
3978 case(MBS_PanicFire):
3979 {
3980 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3981 PrintDebuggingText("Local Guard marine panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
3982 }
3983
3984 if (marineIsNear) {
3985 state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr);
3986 CentreMarineElevation(sbPtr);
3987 } else {
3988 state_result=Execute_MFS_Firing(sbPtr);
3989 }
3990 LocalGuardMission_SwitchState(sbPtr,state_result);
3991 break;
3992 }
3993 case(MBS_Avoidance):
3994 {
3995 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
3996 PrintDebuggingText("Local Guard marine ");
3997 switch (marineStatusPointer->avoidanceManager.substate) {
3998 default:
3999 case AvSS_FreeMovement:
4000 PrintDebuggingText("Avoidance Level 0");
4001 break;
4002 case AvSS_FirstAvoidance:
4003 PrintDebuggingText("Avoidance Level 1");
4004 break;
4005 case AvSS_SecondAvoidance:
4006 PrintDebuggingText("Avoidance Level 2");
4007 break;
4008 case AvSS_ThirdAvoidance:
4009 PrintDebuggingText("Avoidance Level 3");
4010 break;
4011 }
4012 PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4013 }
4014
4015 if (marineIsNear) {
4016 state_result=Execute_MNS_Avoidance(sbPtr);
4017 CentreMarineElevation(sbPtr);
4018 } else {
4019 state_result=Execute_MFS_Avoidance(sbPtr);
4020 }
4021 LocalGuardMission_SwitchState(sbPtr,state_result);
4022 break;
4023 }
4024 case(MBS_Wandering):
4025 {
4026 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4027 PrintDebuggingText("Local Guard marine wandering in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4028 }
4029
4030 if (marineIsNear) {
4031 state_result=Execute_MNS_Wander(sbPtr);
4032 CentreMarineElevation(sbPtr);
4033 } else {
4034 state_result=Execute_MFS_Wait(sbPtr);
4035 }
4036 LocalGuardMission_SwitchState(sbPtr,state_result);
4037 break;
4038 }
4039 case(MBS_Retreating):
4040 {
4041 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4042 PrintDebuggingText("Local Guard marine retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4043 }
4044
4045 /* Real men never retreat! */
4046 if (marineIsNear) {
4047 state_result=Execute_MNS_Retreat(sbPtr);
4048 CentreMarineElevation(sbPtr);
4049 } else {
4050 state_result=Execute_MFS_Retreat(sbPtr);
4051 }
4052 LocalGuardMission_SwitchState(sbPtr,state_result);
4053 break;
4054 }
4055 case(MBS_Waiting):
4056 {
4057 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4058 PrintDebuggingText("Local Guard marine waiting in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4059 }
4060
4061 if (marineIsNear) {
4062 state_result=Execute_MNS_Wait(sbPtr);
4063 CentreMarineElevation(sbPtr);
4064 } else {
4065 state_result=Execute_MFS_Wait(sbPtr);
4066 }
4067 LocalGuardMission_SwitchState(sbPtr,state_result);
4068 break;
4069 }
4070 case(MBS_Responding):
4071 {
4072 /* Well, it *might* happen... */
4073 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4074 PrintDebuggingText("Local Guard marine responding in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4075 }
4076
4077 if (marineIsNear) {
4078 state_result=Execute_MNS_Respond(sbPtr);
4079 CentreMarineElevation(sbPtr);
4080 } else {
4081 state_result=Execute_MFS_Respond(sbPtr);
4082 }
4083 LocalGuardMission_SwitchState(sbPtr,state_result);
4084 break;
4085 }
4086 case(MBS_Returning):
4087 {
4088 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4089 PrintDebuggingText("Local Guard marine returning in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4090 }
4091
4092 if (marineIsNear) {
4093 state_result=Execute_MNS_Return(sbPtr);
4094 CentreMarineElevation(sbPtr);
4095 } else {
4096 state_result=Execute_MFS_Return(sbPtr);
4097 }
4098 LocalGuardMission_SwitchState(sbPtr,state_result);
4099 break;
4100 }
4101 case(MBS_Sentry):
4102 {
4103 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4104 PrintDebuggingText("Local Guard marine sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4105 }
4106
4107 if (marineIsNear) {
4108 state_result=Execute_MNS_SentryMode(sbPtr);
4109 CentreMarineElevation(sbPtr);
4110 } else {
4111 state_result=Execute_MFS_Wait(sbPtr);
4112 }
4113 LocalGuardMission_SwitchState(sbPtr,state_result);
4114 break;
4115 }
4116 case(MBS_Taunting):
4117 {
4118 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4119 PrintDebuggingText("Local Guard marine taunt in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4120 }
4121
4122 if(marineIsNear) {
4123 state_result=Execute_MNS_Taunting(sbPtr);
4124 CentreMarineElevation(sbPtr);
4125 } else {
4126 state_result=Execute_MNS_Taunting(sbPtr);
4127 }
4128 LocalGuardMission_SwitchState(sbPtr,state_result);
4129 break;
4130 }
4131 case(MBS_Reloading):
4132 {
4133 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4134 PrintDebuggingText("Local Guard marine reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4135 }
4136
4137 if(marineIsNear) {
4138 state_result=Execute_MNS_Reloading(sbPtr);
4139 CentreMarineElevation(sbPtr);
4140 } else {
4141 state_result=Execute_MNS_Reloading(sbPtr);
4142 }
4143 LocalGuardMission_SwitchState(sbPtr,state_result);
4144 break;
4145 }
4146 case(MBS_PanicReloading):
4147 {
4148 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4149 PrintDebuggingText("Local Guard marine panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4150 }
4151
4152 if(marineIsNear) {
4153 state_result=Execute_MNS_PanicReloading(sbPtr);
4154 CentreMarineElevation(sbPtr);
4155 } else {
4156 state_result=Execute_MNS_PanicReloading(sbPtr);
4157 }
4158 LocalGuardMission_SwitchState(sbPtr,state_result);
4159 break;
4160 }
4161 case(MBS_Dying):
4162 {
4163 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4164 PrintDebuggingText("Local Guard marine dying in %s\n",sbPtr->containingModule->name);
4165 }
4166
4167 if (marineIsNear) {
4168 Execute_Dying(sbPtr);
4169 } else {
4170 Execute_Dying(sbPtr);
4171 }
4172 break;
4173 }
4174 case(MBS_GetWeapon):
4175 {
4176 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4177 PrintDebuggingText("Local Guard marine get weapon in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4178 }
4179
4180 if(marineIsNear) {
4181 state_result=Execute_MNS_GetWeapon(sbPtr);
4182 CentreMarineElevation(sbPtr);
4183 } else {
4184 state_result=Execute_MNS_GetWeapon(sbPtr);
4185 }
4186 LocalGuardMission_SwitchState(sbPtr,state_result);
4187 break;
4188 }
4189 case MBS_Pathfinding:
4190 {
4191 /* How the hell did you get here?!? */
4192 Marine_Enter_Return_State(sbPtr);
4193 break;
4194 }
4195 case(MBS_AcidAvoidance):
4196 {
4197 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4198 PrintDebuggingText("Local Guard marine acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4199 }
4200
4201 if (marineIsNear) {
4202 state_result=Execute_MNS_AcidAvoidance(sbPtr);
4203 CentreMarineElevation(sbPtr);
4204 } else {
4205 Marine_Enter_Wait_State(sbPtr);
4206 break;
4207 }
4208 LocalGuardMission_SwitchState(sbPtr,state_result);
4209 break;
4210 }
4211 default:
4212 {
4213 LOGDXFMT(("Local Guard marine in unsupported state %d!\n",marineStatusPointer->behaviourState));
4214 LOCALASSERT(1==0);
4215 }
4216 }
4217 }
4218
4219 if (!marineIsNear) {
4220
4221 /* check here to see if marine is in a proximity door - if so, trigger it to open. */
4222 {
4223 MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
4224
4225 if(doorType == MDT_ProxDoor)
4226 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1;
4227 }
4228
4229 /* lastly, do a containment test: to make sure that we are inside a module. */
4230 #if UseLocalAssert
4231 {
4232 VECTORCH localCoords;
4233 MODULE *thisModule = sbPtr->containingModule;
4234
4235 LOCALASSERT(thisModule);
4236
4237 localCoords = sbPtr->DynPtr->Position;
4238 localCoords.vx -= thisModule->m_world.vx;
4239 localCoords.vy -= thisModule->m_world.vy;
4240 localCoords.vz -= thisModule->m_world.vz;
4241
4242 if(PointIsInModule(thisModule, &localCoords)==0)
4243 {
4244 textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n");
4245 LOCALASSERT(1==0);
4246 }
4247 }
4248 #endif
4249 }
4250
4251 }
4252
LoiterMission_Control(STRATEGYBLOCK * sbPtr)4253 void LoiterMission_Control(STRATEGYBLOCK *sbPtr) {
4254
4255 MARINE_STATUS_BLOCK *marineStatusPointer;
4256 STATE_RETURN_CONDITION state_result;
4257 int marineIsNear;
4258
4259 LOCALASSERT(sbPtr);
4260 LOCALASSERT(sbPtr->containingModule);
4261 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
4262 LOCALASSERT(marineStatusPointer);
4263
4264 /* Fleeing Behaviour. */
4265
4266 if(sbPtr->SBdptr) {
4267 marineIsNear=1;
4268 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
4269 } else {
4270 marineIsNear=0;
4271 }
4272
4273 {
4274
4275 switch(marineStatusPointer->behaviourState)
4276 {
4277 case(MBS_Approaching):
4278 {
4279 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4280 PrintDebuggingText("Noncombatant approaching in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4281 }
4282
4283 if (marineIsNear) {
4284 state_result=Execute_MNS_Approach(sbPtr);
4285 CentreMarineElevation(sbPtr);
4286 } else {
4287 state_result=Execute_MFS_Wait(sbPtr);
4288 }
4289 LoiterMission_SwitchState(sbPtr,state_result);
4290 break;
4291 }
4292 case(MBS_Firing):
4293 {
4294
4295 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4296 PrintDebuggingText("Noncombatant firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4297 }
4298
4299 if (marineIsNear) {
4300 GLOBALASSERT(0);
4301 state_result=(*marineStatusPointer->My_Weapon->WeaponFireFunction)(sbPtr);
4302 SetMarineElevation(sbPtr);
4303 } else {
4304 state_result=Execute_MFS_Firing(sbPtr);
4305 }
4306 LoiterMission_SwitchState(sbPtr,state_result);
4307 break;
4308 }
4309 case(MBS_PumpAction):
4310 {
4311 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4312 PrintDebuggingText("Noncombatant marine pump action in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4313 }
4314
4315 if (marineIsNear) {
4316 state_result=Execute_MNS_PumpAction(sbPtr);
4317 CentreMarineElevation(sbPtr);
4318 } else {
4319 state_result=Execute_MNS_PumpAction(sbPtr);
4320 }
4321 LoiterMission_SwitchState(sbPtr,state_result);
4322 break;
4323 }
4324 case(MBS_PanicFire):
4325 {
4326 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4327 PrintDebuggingText("Noncombatant panic firing in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4328 }
4329
4330 if (marineIsNear) {
4331 state_result=(*marineStatusPointer->My_Weapon->WeaponPanicFireFunction)(sbPtr);
4332 CentreMarineElevation(sbPtr);
4333 } else {
4334 state_result=Execute_MFS_Firing(sbPtr);
4335 }
4336 LoiterMission_SwitchState(sbPtr,state_result);
4337 break;
4338 }
4339 case(MBS_Avoidance):
4340 {
4341
4342 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4343 PrintDebuggingText("Noncombatant ");
4344 switch (marineStatusPointer->avoidanceManager.substate) {
4345 default:
4346 case AvSS_FreeMovement:
4347 PrintDebuggingText("Avoidance Level 0");
4348 break;
4349 case AvSS_FirstAvoidance:
4350 PrintDebuggingText("Avoidance Level 1");
4351 break;
4352 case AvSS_SecondAvoidance:
4353 PrintDebuggingText("Avoidance Level 2");
4354 break;
4355 case AvSS_ThirdAvoidance:
4356 PrintDebuggingText("Avoidance Level 3");
4357 break;
4358 }
4359 PrintDebuggingText(" in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4360 }
4361
4362 if (marineIsNear) {
4363 state_result=Execute_MNS_Avoidance(sbPtr);
4364 CentreMarineElevation(sbPtr);
4365 } else {
4366 state_result=Execute_MFS_Avoidance(sbPtr);
4367 }
4368 LoiterMission_SwitchState(sbPtr,state_result);
4369 break;
4370 }
4371 case(MBS_Responding):
4372 case(MBS_Wandering):
4373 {
4374
4375 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4376 PrintDebuggingText("Noncombatant wandering in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4377 }
4378
4379 if (marineIsNear) {
4380 state_result=Execute_MNS_Wander(sbPtr);
4381 CentreMarineElevation(sbPtr);
4382 } else {
4383 state_result=Execute_MFS_Wander(sbPtr);
4384 }
4385 LoiterMission_SwitchState(sbPtr,state_result);
4386 break;
4387 }
4388 case(MBS_Retreating):
4389 {
4390
4391 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4392 PrintDebuggingText("Noncombatant retreating in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4393 }
4394
4395 /* Wusses, now: they retreat. */
4396 if (marineIsNear) {
4397 state_result=Execute_MNS_Retreat(sbPtr);
4398 CentreMarineElevation(sbPtr);
4399 } else {
4400 state_result=Execute_MFS_Retreat(sbPtr);
4401 }
4402 LoiterMission_SwitchState(sbPtr,state_result);
4403 break;
4404 }
4405 case(MBS_Waiting):
4406 {
4407
4408 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4409 PrintDebuggingText("Noncombatant waiting in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4410 }
4411
4412 if (marineIsNear) {
4413 state_result=Execute_MNS_Wait(sbPtr);
4414 CentreMarineElevation(sbPtr);
4415 } else {
4416 state_result=Execute_MFS_Wait(sbPtr);
4417 }
4418 LoiterMission_SwitchState(sbPtr,state_result);
4419 break;
4420 }
4421 case(MBS_Sentry):
4422 {
4423 GLOBALASSERT(0);
4424
4425 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4426 PrintDebuggingText("Noncombatant sentry in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4427 }
4428
4429 if (marineIsNear) {
4430 state_result=Execute_MNS_SentryMode(sbPtr);
4431 CentreMarineElevation(sbPtr);
4432 } else {
4433 state_result=Execute_MFS_Wait(sbPtr);
4434 }
4435 LoiterMission_SwitchState(sbPtr,state_result);
4436 break;
4437 }
4438 case(MBS_Reloading):
4439 {
4440 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4441 PrintDebuggingText("Noncombatant reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4442 }
4443
4444 if(marineIsNear) {
4445 state_result=Execute_MNS_Reloading(sbPtr);
4446 CentreMarineElevation(sbPtr);
4447 } else {
4448 state_result=Execute_MNS_Reloading(sbPtr);
4449 }
4450 LoiterMission_SwitchState(sbPtr,state_result);
4451 break;
4452 }
4453 case(MBS_PanicReloading):
4454 {
4455 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4456 PrintDebuggingText("Noncombatant panic reloading in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4457 }
4458
4459 if(marineIsNear) {
4460 state_result=Execute_MNS_PanicReloading(sbPtr);
4461 CentreMarineElevation(sbPtr);
4462 } else {
4463 state_result=Execute_MNS_PanicReloading(sbPtr);
4464 }
4465 LoiterMission_SwitchState(sbPtr,state_result);
4466 break;
4467 }
4468 case(MBS_Dying):
4469 {
4470
4471 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4472 PrintDebuggingText("Noncombatant dying in %s\n",sbPtr->containingModule->name);
4473 }
4474
4475 if (marineIsNear) {
4476 Execute_Dying(sbPtr);
4477 } else {
4478 Execute_Dying(sbPtr);
4479 }
4480 break;
4481 }
4482 case MBS_Returning:
4483 case MBS_Pathfinding:
4484 {
4485 /* How the hell did you get here?!? */
4486 Marine_Enter_Wander_State(sbPtr);
4487 break;
4488 }
4489 case(MBS_AcidAvoidance):
4490 {
4491 if ((ShowSquadState)||((marineIsNear)&&(ShowNearSquad))) {
4492 PrintDebuggingText("Noncombatant acid avoidance in %s: %d\n",sbPtr->containingModule->name,marineStatusPointer->Courage);
4493 }
4494
4495 if (marineIsNear) {
4496 state_result=Execute_MNS_AcidAvoidance(sbPtr);
4497 CentreMarineElevation(sbPtr);
4498 } else {
4499 Marine_Enter_Wait_State(sbPtr);
4500 break;
4501 }
4502 LoiterMission_SwitchState(sbPtr,state_result);
4503 break;
4504 }
4505 default:
4506 {
4507 /* NonComs can't taunt. */
4508 LOGDXFMT(("Marine in unsupported state %d!\n",marineStatusPointer->behaviourState));
4509 LOCALASSERT(1==0);
4510 }
4511 }
4512 }
4513
4514 if (!marineIsNear) {
4515
4516 /* check here to see if marine is in a proximity door - if so, trigger it to open. */
4517 {
4518 MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
4519
4520 if(doorType == MDT_ProxDoor)
4521 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1;
4522 }
4523
4524 /* lastly, do a containment test: to make sure that we are inside a module. */
4525 #if UseLocalAssert
4526 {
4527 VECTORCH localCoords;
4528 MODULE *thisModule = sbPtr->containingModule;
4529
4530 LOCALASSERT(thisModule);
4531
4532 localCoords = sbPtr->DynPtr->Position;
4533 localCoords.vx -= thisModule->m_world.vx;
4534 localCoords.vy -= thisModule->m_world.vy;
4535 localCoords.vz -= thisModule->m_world.vz;
4536
4537 if(PointIsInModule(thisModule, &localCoords)==0)
4538 {
4539 textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n");
4540 LOCALASSERT(1==0);
4541 }
4542 }
4543 #endif
4544 }
4545
4546 }
4547
WanderMission_SwitchState(STRATEGYBLOCK * sbPtr,STATE_RETURN_CONDITION state_result)4548 void WanderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) {
4549
4550 STATE_RETURN_CONDITION real_state_result;
4551 /* Experiment: override result? */
4552 switch (state_result) {
4553 case (SRC_Request_Fire):
4554 case (SRC_Request_Approach):
4555 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
4556 real_state_result=SRC_Request_Retreat;
4557 EndMarineMuzzleFlash(sbPtr);
4558 } else {
4559 real_state_result=state_result;
4560 }
4561 break;
4562 default:
4563 real_state_result=state_result;
4564 break;
4565 }
4566
4567 switch (real_state_result) {
4568 case (SRC_No_Change):
4569 {
4570 /* No action. */
4571 break;
4572 }
4573 case (SRC_Request_Taunt):
4574 {
4575 Marine_Enter_Taunt_State(sbPtr);
4576 break;
4577 }
4578 case (SRC_Request_Wait):
4579 {
4580 Marine_Enter_Wait_State(sbPtr);
4581 break;
4582 }
4583 case (SRC_Request_Fire):
4584 {
4585 Marine_Enter_Firing_State(sbPtr);
4586 break;
4587 }
4588 case (SRC_Request_PanicFire):
4589 {
4590 Marine_Enter_PanicFire_State(sbPtr);
4591 break;
4592 }
4593 case (SRC_Request_Avoidance):
4594 {
4595 Marine_Enter_Avoidance_State(sbPtr);
4596 break;
4597 }
4598 case (SRC_Request_Approach):
4599 {
4600 Marine_Enter_Approach_State(sbPtr);
4601 break;
4602 }
4603 case (SRC_Request_Wander):
4604 {
4605 Marine_Enter_Wander_State(sbPtr);
4606 break;
4607 }
4608 case (SRC_Request_Retreat):
4609 {
4610 Marine_Enter_Retreat_State(sbPtr);
4611 break;
4612 }
4613 case (SRC_Request_Respond):
4614 {
4615 Marine_Enter_Respond_State(sbPtr);
4616 break;
4617 }
4618 case (SRC_Request_Reload):
4619 {
4620 Marine_Enter_Reload_State(sbPtr);
4621 break;
4622 }
4623 case (SRC_Request_PanicReload):
4624 {
4625 Marine_Enter_PanicReload_State(sbPtr);
4626 break;
4627 }
4628 case (SRC_Request_PumpAction):
4629 {
4630 Marine_Enter_PumpAction_State(sbPtr);
4631 break;
4632 }
4633 case (SRC_Request_PullPistol):
4634 {
4635 Marine_Enter_PullPistol_State(sbPtr);
4636 break;
4637 }
4638 default:
4639 {
4640 /* How did we end up here? */
4641 GLOBALASSERT(0);
4642 break;
4643 }
4644
4645 }
4646
4647 }
4648
PathfinderMission_SwitchState(STRATEGYBLOCK * sbPtr,STATE_RETURN_CONDITION state_result)4649 void PathfinderMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) {
4650
4651 STATE_RETURN_CONDITION real_state_result;
4652 /* Experiment: override result? */
4653 switch (state_result) {
4654 case (SRC_Request_Fire):
4655 case (SRC_Request_Approach):
4656 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
4657 real_state_result=SRC_Request_Retreat;
4658 EndMarineMuzzleFlash(sbPtr);
4659 } else {
4660 real_state_result=state_result;
4661 }
4662 break;
4663 default:
4664 real_state_result=state_result;
4665 break;
4666 }
4667
4668 switch (real_state_result) {
4669 case (SRC_No_Change):
4670 {
4671 /* No action. */
4672 break;
4673 }
4674 case (SRC_Request_Taunt):
4675 {
4676 Marine_Enter_Taunt_State(sbPtr);
4677 break;
4678 }
4679 case (SRC_Request_Wait):
4680 {
4681 Marine_Enter_Pathfinder_State(sbPtr);
4682 break;
4683 }
4684 case (SRC_Request_Fire):
4685 {
4686 Marine_Enter_Firing_State(sbPtr);
4687 break;
4688 }
4689 case (SRC_Request_PanicFire):
4690 {
4691 Marine_Enter_PanicFire_State(sbPtr);
4692 break;
4693 }
4694 case (SRC_Request_Avoidance):
4695 {
4696 Marine_Enter_Avoidance_State(sbPtr);
4697 break;
4698 }
4699 case (SRC_Request_Approach):
4700 {
4701 Marine_Enter_Approach_State(sbPtr);
4702 break;
4703 }
4704 case (SRC_Request_Wander):
4705 {
4706 Marine_Enter_Wander_State(sbPtr);
4707 break;
4708 }
4709 case (SRC_Request_Retreat):
4710 {
4711 Marine_Enter_Retreat_State(sbPtr);
4712 break;
4713 }
4714 case (SRC_Request_Respond):
4715 {
4716 Marine_Enter_Respond_State(sbPtr);
4717 break;
4718 }
4719 case (SRC_Request_Return):
4720 {
4721 Marine_Enter_Return_State(sbPtr);
4722 break;
4723 }
4724 case (SRC_Request_Reload):
4725 {
4726 Marine_Enter_Reload_State(sbPtr);
4727 break;
4728 }
4729 case (SRC_Request_PanicReload):
4730 {
4731 Marine_Enter_PanicReload_State(sbPtr);
4732 break;
4733 }
4734 case (SRC_Request_PumpAction):
4735 {
4736 Marine_Enter_PumpAction_State(sbPtr);
4737 break;
4738 }
4739 case (SRC_Request_PullPistol):
4740 {
4741 Marine_Enter_PullPistol_State(sbPtr);
4742 break;
4743 }
4744 default:
4745 {
4746 /* How did we end up here? */
4747 GLOBALASSERT(0);
4748 break;
4749 }
4750
4751 }
4752
4753 }
4754
GuardMission_SwitchState(STRATEGYBLOCK * sbPtr,STATE_RETURN_CONDITION state_result)4755 void GuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) {
4756
4757 STATE_RETURN_CONDITION real_state_result;
4758 MARINE_STATUS_BLOCK *marineStatusPointer;
4759
4760 LOCALASSERT(sbPtr);
4761 LOCALASSERT(sbPtr->containingModule);
4762 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
4763 LOCALASSERT(marineStatusPointer);
4764
4765 /* Experiment: override result? */
4766 switch (state_result) {
4767 case (SRC_Request_Fire):
4768 case (SRC_Request_Approach):
4769 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
4770 real_state_result=SRC_Request_PanicFire;
4771 EndMarineMuzzleFlash(sbPtr);
4772 } else {
4773 real_state_result=state_result;
4774 }
4775 break;
4776 default:
4777 real_state_result=state_result;
4778 break;
4779 }
4780
4781 switch (real_state_result) {
4782 case (SRC_No_Change):
4783 {
4784 /* No action. */
4785 break;
4786 }
4787 case (SRC_Request_Taunt):
4788 {
4789 Marine_Enter_Taunt_State(sbPtr);
4790 break;
4791 }
4792 case (SRC_Request_Wait):
4793 {
4794 Marine_Enter_SentryMode_State(sbPtr);
4795 break;
4796 }
4797 case (SRC_Request_Fire):
4798 {
4799 Marine_Enter_Firing_State(sbPtr);
4800 break;
4801 }
4802 case (SRC_Request_PanicFire):
4803 {
4804 Marine_Enter_PanicFire_State(sbPtr);
4805 break;
4806 }
4807 case (SRC_Request_Avoidance):
4808 {
4809 Marine_Enter_SentryMode_State(sbPtr);
4810 break;
4811 }
4812 case (SRC_Request_Approach):
4813 {
4814 Marine_Enter_SentryMode_State(sbPtr);
4815 break;
4816 }
4817 case (SRC_Request_Wander):
4818 {
4819 Marine_Enter_SentryMode_State(sbPtr);
4820 break;
4821 }
4822 case (SRC_Request_Retreat):
4823 {
4824 Marine_Enter_Retreat_State(sbPtr);
4825 break;
4826 }
4827 case (SRC_Request_Reload):
4828 {
4829 Marine_Enter_Reload_State(sbPtr);
4830 break;
4831 }
4832 case (SRC_Request_PanicReload):
4833 {
4834 Marine_Enter_PanicReload_State(sbPtr);
4835 break;
4836 }
4837 case (SRC_Request_PumpAction):
4838 {
4839 Marine_Enter_PumpAction_State(sbPtr);
4840 break;
4841 }
4842 case (SRC_Request_PullPistol):
4843 {
4844 Marine_Enter_PullPistol_State(sbPtr);
4845 break;
4846 }
4847 default:
4848 {
4849 /* How did we end up here? */
4850 GLOBALASSERT(0);
4851 break;
4852 }
4853
4854 }
4855
4856 }
4857
LocalGuardMission_SwitchState(STRATEGYBLOCK * sbPtr,STATE_RETURN_CONDITION state_result)4858 void LocalGuardMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) {
4859
4860 STATE_RETURN_CONDITION real_state_result;
4861 MARINE_STATUS_BLOCK *marineStatusPointer;
4862
4863 LOCALASSERT(sbPtr);
4864 LOCALASSERT(sbPtr->containingModule);
4865 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
4866 LOCALASSERT(marineStatusPointer);
4867
4868 /* Experiment: override result? */
4869 switch (state_result) {
4870 case (SRC_Request_Fire):
4871 case (SRC_Request_Approach):
4872 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
4873 real_state_result=SRC_Request_Retreat;
4874 EndMarineMuzzleFlash(sbPtr);
4875 } else {
4876 real_state_result=state_result;
4877 }
4878 break;
4879 default:
4880 real_state_result=state_result;
4881 break;
4882 }
4883
4884 switch (real_state_result) {
4885 case (SRC_No_Change):
4886 {
4887 /* No action. */
4888 break;
4889 }
4890 case (SRC_Request_Taunt):
4891 {
4892 Marine_Enter_Taunt_State(sbPtr);
4893 break;
4894 }
4895 case (SRC_Request_Wait):
4896 {
4897 if (marineStatusPointer->missionmodule==sbPtr->containingModule->m_aimodule) {
4898 Marine_Enter_Wait_State(sbPtr);
4899 } else {
4900 Marine_Enter_Return_State(sbPtr);
4901 }
4902 break;
4903 }
4904 case (SRC_Request_Fire):
4905 {
4906 Marine_Enter_Firing_State(sbPtr);
4907 break;
4908 }
4909 case (SRC_Request_PanicFire):
4910 {
4911 Marine_Enter_PanicFire_State(sbPtr);
4912 break;
4913 }
4914 case (SRC_Request_Avoidance):
4915 {
4916 Marine_Enter_Avoidance_State(sbPtr);
4917 break;
4918 }
4919 case (SRC_Request_Approach):
4920 {
4921 Marine_Enter_Approach_State(sbPtr);
4922 break;
4923 }
4924 case (SRC_Request_Wander):
4925 {
4926 Marine_Enter_Wander_State(sbPtr);
4927 break;
4928 }
4929 case (SRC_Request_Retreat):
4930 {
4931 Marine_Enter_Retreat_State(sbPtr);
4932 break;
4933 }
4934 case (SRC_Request_Return):
4935 {
4936 Marine_Enter_Return_State(sbPtr);
4937 break;
4938 }
4939 case (SRC_Request_Reload):
4940 {
4941 Marine_Enter_Reload_State(sbPtr);
4942 break;
4943 }
4944 case (SRC_Request_PanicReload):
4945 {
4946 Marine_Enter_PanicReload_State(sbPtr);
4947 break;
4948 }
4949 case (SRC_Request_PumpAction):
4950 {
4951 Marine_Enter_PumpAction_State(sbPtr);
4952 break;
4953 }
4954 case (SRC_Request_PullPistol):
4955 {
4956 Marine_Enter_PullPistol_State(sbPtr);
4957 break;
4958 }
4959 default:
4960 {
4961 /* How did we end up here? */
4962 GLOBALASSERT(0);
4963 break;
4964 }
4965
4966 }
4967
4968 }
4969
LoiterMission_SwitchState(STRATEGYBLOCK * sbPtr,STATE_RETURN_CONDITION state_result)4970 void LoiterMission_SwitchState(STRATEGYBLOCK *sbPtr,STATE_RETURN_CONDITION state_result) {
4971
4972 STATE_RETURN_CONDITION real_state_result;
4973
4974 MARINE_STATUS_BLOCK *marineStatusPointer;
4975
4976 LOCALASSERT(sbPtr);
4977 LOCALASSERT(sbPtr->containingModule);
4978 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
4979 LOCALASSERT(marineStatusPointer);
4980
4981 /* Experiment: override result? */
4982 switch (state_result) {
4983 case (SRC_Request_Fire):
4984 case (SRC_Request_Approach):
4985 if ((MarineRetreatsInTheFaceOfDanger(sbPtr))&&(marineStatusPointer->Target)) {
4986 real_state_result=SRC_Request_Retreat;
4987 EndMarineMuzzleFlash(sbPtr);
4988 } else {
4989 real_state_result=state_result;
4990 }
4991 break;
4992 default:
4993 real_state_result=state_result;
4994 break;
4995 }
4996
4997 switch (real_state_result) {
4998 case (SRC_No_Change):
4999 {
5000 /* No action. */
5001 break;
5002 }
5003 case (SRC_Request_Taunt):
5004 {
5005 Marine_Enter_Taunt_State(sbPtr);
5006 break;
5007 }
5008 case (SRC_Request_Wait):
5009 {
5010 Marine_Enter_Wait_State(sbPtr);
5011 break;
5012 }
5013 case (SRC_Request_Fire):
5014 case (SRC_Request_Reload):
5015 case (SRC_Request_PanicReload):
5016 case (SRC_Request_PumpAction):
5017 {
5018 Marine_Enter_Retreat_State(sbPtr);
5019 break;
5020 }
5021 case (SRC_Request_Avoidance):
5022 {
5023 Marine_Enter_Avoidance_State(sbPtr);
5024 break;
5025 }
5026 case (SRC_Request_Approach):
5027 {
5028 if (marineStatusPointer->Target) {
5029 /* Approach? You must be mad! */
5030 Marine_Enter_Retreat_State(sbPtr);
5031 } else {
5032 /* We must be just suspicious. */
5033 Marine_Enter_Approach_State(sbPtr);
5034 }
5035 break;
5036 }
5037 case (SRC_Request_Retreat):
5038 {
5039 Marine_Enter_Retreat_State(sbPtr);
5040 break;
5041 }
5042 case (SRC_Request_Wander):
5043 {
5044 Marine_Enter_Wander_State(sbPtr);
5045 break;
5046 }
5047 case (SRC_Request_PanicFire):
5048 {
5049 Marine_Enter_PanicFire_State(sbPtr);
5050 break;
5051 }
5052 default:
5053 {
5054 /* How did we end up here? */
5055 GLOBALASSERT(0);
5056 break;
5057 }
5058
5059 }
5060
5061 }
5062
MakeMarineNear(STRATEGYBLOCK * sbPtr)5063 void MakeMarineNear(STRATEGYBLOCK *sbPtr)
5064 {
5065 extern MODULEMAPBLOCK AlienDefaultMap;
5066
5067 MODULE tempModule;
5068 DISPLAYBLOCK *dPtr;
5069 DYNAMICSBLOCK *dynPtr;
5070 MARINE_STATUS_BLOCK *marineStatusPointer;
5071
5072 LOCALASSERT(sbPtr);
5073 LOCALASSERT(sbPtr->SBdptr == NULL);
5074 dynPtr = sbPtr->DynPtr;
5075 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5076 LOCALASSERT(marineStatusPointer);
5077 LOCALASSERT(dynPtr);
5078
5079 /* first of all, see how many marines are currently near: if there are too many,
5080 destroy this one, and try to force a generator to make a replacement */
5081 if(sbPtr->I_SBtype==I_BehaviourMarine)
5082 {
5083 if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS)
5084 {
5085 DestroyAnyStrategyBlock(sbPtr);
5086 ForceAGenerator();
5087 }
5088 }
5089
5090 AlienDefaultMap.MapShape = sbPtr->shapeIndex;
5091 tempModule.m_mapptr = &AlienDefaultMap;
5092 tempModule.m_sbptr = (STRATEGYBLOCK*)NULL;
5093 tempModule.m_numlights = 0;
5094 tempModule.m_lightarray = (struct lightblock *)0;
5095 tempModule.m_extraitemdata = (struct extraitemdata *)0;
5096 tempModule.m_dptr = NULL;
5097 AllocateModuleObject(&tempModule);
5098 dPtr = tempModule.m_dptr;
5099 if(dPtr==NULL) return; /* cannot allocate displayblock, so leave far */
5100
5101 sbPtr->SBdptr = dPtr;
5102 dPtr->ObStrategyBlock = sbPtr;
5103 dPtr->ObMyModule = NULL;
5104
5105 /* need to initialise positional information in the new display block */
5106 dPtr->ObWorld = dynPtr->Position;
5107 dPtr->ObEuler = dynPtr->OrientEuler;
5108 dPtr->ObMat = dynPtr->OrientMat;
5109
5110 /* marine data block init */
5111 marineStatusPointer->weaponTarget.vx = marineStatusPointer->weaponTarget.vy = marineStatusPointer->weaponTarget.vz = 0;
5112
5113 /* zero linear velocity in dynamics block */
5114 sbPtr->DynPtr->LinVelocity.vx = 0;
5115 sbPtr->DynPtr->LinVelocity.vy = 0;
5116 sbPtr->DynPtr->LinVelocity.vz = 0;
5117
5118 /* state and sequence initialisation */
5119 //dPtr->ShapeAnimControlBlock = &marineStatusPointer->ShpAnimCtrl;
5120
5121 dPtr->HModelControlBlock=&marineStatusPointer->HModelController;
5122
5123 /* Just in case. */
5124 CentreMarineElevation(sbPtr);
5125 InitWaypointManager(&marineStatusPointer->waypointManager);
5126
5127 ProveHModel(dPtr->HModelControlBlock,dPtr);
5128
5129 if(MarineShouldBeCrawling(sbPtr)) marineStatusPointer->IAmCrouched = 1;
5130 else marineStatusPointer->IAmCrouched = 0;
5131
5132 if (marineStatusPointer->behaviourState==MBS_Firing) {
5133 Marine_Enter_Firing_State(sbPtr);
5134 /* To avoid negative volleys */
5135 }
5136
5137 /*Copy extents from the collision extents in extents.c*/
5138 dPtr->ObMinX=-CollisionExtents[CE_MARINE].CollisionRadius;
5139 dPtr->ObMaxX=CollisionExtents[CE_MARINE].CollisionRadius;
5140 dPtr->ObMinZ=-CollisionExtents[CE_MARINE].CollisionRadius;
5141 dPtr->ObMaxZ=CollisionExtents[CE_MARINE].CollisionRadius;
5142 dPtr->ObMinY=CollisionExtents[CE_MARINE].CrouchingTop;
5143 dPtr->ObMaxY=CollisionExtents[CE_MARINE].Bottom;
5144 dPtr->ObRadius = 1000;
5145
5146 marineStatusPointer->gotapoint=0;
5147
5148 /* Once they become near, Wait_Then_Hunt marines become Wander marines. */
5149
5150 if (marineStatusPointer->Mission==MM_Wait_Then_Wander) {
5151 marineStatusPointer->Mission=MM_Wander;
5152 }
5153
5154 /* And force pathfinders to get a new module? */
5155 if (marineStatusPointer->Mission==MM_Pathfinder) {
5156 if (marineStatusPointer->behaviourState==MBS_Pathfinding) {
5157 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
5158 }
5159 }
5160
5161 marineStatusPointer->lastframe_fallingspeed=-1;
5162 }
5163
MakeMarineFar(STRATEGYBLOCK * sbPtr)5164 void MakeMarineFar(STRATEGYBLOCK *sbPtr)
5165 {
5166 MARINE_STATUS_BLOCK *marineStatusPointer;
5167 int i;
5168
5169 LOCALASSERT(sbPtr);
5170 LOCALASSERT(sbPtr->SBdptr != NULL);
5171 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5172 LOCALASSERT(marineStatusPointer);
5173
5174 /* get rid of the displayblock */
5175 i = DestroyActiveObject(sbPtr->SBdptr);
5176 LOCALASSERT(i==0);
5177 sbPtr->SBdptr = NULL;
5178
5179 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
5180
5181 /* zero linear velocity in dynamics block */
5182 sbPtr->DynPtr->LinVelocity.vx = 0;
5183 sbPtr->DynPtr->LinVelocity.vy = 0;
5184 sbPtr->DynPtr->LinVelocity.vz = 0;
5185
5186 /* if we have a gun flash, get rid of it */
5187 if(marineStatusPointer->myGunFlash)
5188 {
5189 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
5190 marineStatusPointer->myGunFlash = NULL;
5191 }
5192 /* stop sound, if we have one */
5193 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle);
5194 if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle2);
5195
5196 /* set the correct state(s) or remove, if we're dying */
5197 if(marineStatusPointer->behaviourState == MBS_Dying)
5198 {
5199 /* if we're dying, we can be removed at this point */
5200 DestroyAnyStrategyBlock(sbPtr);
5201 return;
5202 }
5203
5204 }
5205
KillMarine(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int wounds,SECTION_DATA * Section,VECTORCH * incoming)5206 void KillMarine(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming) {
5207
5208 int deathtype,gibbFactor;
5209 int a;
5210 STRATEGYBLOCK *candidate;
5211
5212 MARINE_STATUS_BLOCK *marineStatusPointer;
5213 SECTION_DATA *head;
5214
5215 LOCALASSERT(sbPtr);
5216 LOCALASSERT(sbPtr->containingModule);
5217 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5218 LOCALASSERT(marineStatusPointer);
5219
5220 /* Morale. */
5221 if (marineStatusPointer->My_Weapon->ARealMarine) {
5222 /* Only marine deaths get 'spotted' everywhere, by the APC guy! */
5223 NpcSquad.Nextframe_Squad_Delta_Morale-=10000;
5224 /* So, warn the squad? */
5225 ZoneAlert(3,sbPtr->containingModule->m_aimodule);
5226 }
5227
5228 Marine_MuteVoice(sbPtr);
5229
5230 /*notify death target ,if marine has one*/
5231 if(marineStatusPointer->death_target_sbptr)
5232 {
5233 RequestState(marineStatusPointer->death_target_sbptr,marineStatusPointer->death_target_request, 0);
5234 }
5235
5236 /* get rid of the gun flash, if we've got it */
5237 if(marineStatusPointer->myGunFlash)
5238 {
5239 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
5240 marineStatusPointer->myGunFlash = NULL;
5241 }
5242
5243 /* stop sound, if we have one, and it's not the fire */
5244 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
5245 if (ActiveSounds[marineStatusPointer->soundHandle].soundIndex!=SID_FIRE) {
5246 Sound_Stop(marineStatusPointer->soundHandle);
5247 }
5248 }
5249
5250 /* Set GibbFactor */
5251 gibbFactor=0;
5252 {
5253 int tkd;
5254
5255 tkd=TotalKineticDamage(damage);
5256 deathtype=0;
5257
5258 if (damage->ExplosivePower==1) {
5259 if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) {
5260 /* Okay, you can gibb now. */
5261 marineStatusPointer->GibbFactor=ONE_FIXED>>1;
5262 marineStatusPointer->mtracker_timer=-1;
5263 deathtype=2;
5264 }
5265 } else if ((tkd>60)&&((multiple>>16)>1)) {
5266 int newmult;
5267
5268 newmult=DIV_FIXED(multiple,NormalFrameTime);
5269 if (MUL_FIXED(tkd,newmult)>(500)) {
5270 /* Loadsabullets! */
5271 marineStatusPointer->GibbFactor=-(ONE_FIXED>>2);
5272 marineStatusPointer->mtracker_timer=-1;
5273 deathtype=2;
5274 }
5275 }
5276
5277 if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) {
5278 /* Basically SADARS only. */
5279 marineStatusPointer->GibbFactor=ONE_FIXED;
5280 marineStatusPointer->mtracker_timer=-1;
5281 deathtype=3;
5282 }
5283 }
5284 gibbFactor=marineStatusPointer->GibbFactor;
5285
5286 if (damage->ForceBoom) {
5287 deathtype+=damage->ForceBoom;
5288 }
5289
5290 {
5291 SECTION_DATA *chest;
5292
5293 chest=GetThisSectionData(marineStatusPointer->HModelController.section_data,"chest");
5294
5295 if (chest==NULL) {
5296 /* I'm impressed. */
5297 deathtype+=2;
5298 } else if ((chest->flags§ion_data_notreal)
5299 &&(chest->flags§ion_data_terminate_here)) {
5300 /* That's gotta hurt. */
5301 deathtype++;
5302 }
5303 }
5304
5305 /* make a sound... if you have a head. */
5306 head=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head");
5307
5308 /* Is it still attached? */
5309 if (head) {
5310 if (head->flags§ion_data_notreal) {
5311 head=NULL;
5312 }
5313 }
5314
5315 if (marineStatusPointer->GibbFactor) {
5316 /* Probably want to make some sort of splatting noise... */
5317 } else if (head) {
5318 if (marineStatusPointer->Expression!=3) {
5319 /* Expression 3 just looks too peaceful. */
5320 if (marineStatusPointer->Mission==MM_RunAroundOnFire) {
5321 /* More burning screams. */
5322 Marine_BurningDeathScream(sbPtr);
5323 } else if ((damage->Impact==0)
5324 &&(damage->Cutting==0)
5325 &&(damage->Penetrative==0)
5326 &&(damage->Fire==0)
5327 &&(damage->Electrical>0)
5328 &&(damage->Acid==0)
5329 ) {
5330 Marine_ElectrocutionScream(sbPtr);
5331 } else if ((Section)&&(damage->Id==AMMO_PRED_RIFLE)) {
5332 /* Hit in the chest or pelvis by a speargun? */
5333 if( (strcmp(Section->sempai->Section_Name,"pelvis")==0)
5334 ||(strcmp(Section->sempai->Section_Name,"pelvis presley")==0)
5335 ||(strcmp(Section->sempai->Section_Name,"chest")==0) ){
5336 Marine_OoophSound(sbPtr);
5337 } else {
5338 Marine_DeathScream(sbPtr);
5339 }
5340 } else {
5341 Marine_DeathScream(sbPtr);
5342 }
5343 }
5344 }
5345
5346 /* Now final stage. */
5347 {
5348 DEATH_DATA *this_death;
5349 HIT_FACING facing;
5350 SECTION *root;
5351 int burning,electrical;
5352
5353 root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName);
5354
5355 facing.Front=0;
5356 facing.Back=0;
5357 facing.Left=0;
5358 facing.Right=0;
5359
5360 if (incoming) {
5361 if (incoming->vz>0) {
5362 facing.Back=1;
5363 } else {
5364 facing.Front=1;
5365 }
5366 if (incoming->vx>0) {
5367 facing.Right=1;
5368 } else {
5369 facing.Left=1;
5370 }
5371 }
5372
5373 if ((marineStatusPointer->Mission==MM_RunAroundOnFire)
5374 &&(damage->Impact==0)
5375 &&(damage->Cutting==0)
5376 &&(damage->Penetrative==0)
5377 &&(damage->Fire>0)
5378 &&(damage->Electrical==0)
5379 &&(damage->Acid==0)
5380 ) {
5381 burning=1;
5382 } else {
5383 burning=0;
5384 }
5385
5386 if ((damage->Impact==0)
5387 &&(damage->Cutting==0)
5388 &&(damage->Penetrative==0)
5389 &&(damage->Fire==0)
5390 &&(damage->Electrical>0)
5391 &&(damage->Acid==0)
5392 ) {
5393 electrical=1;
5394 } else {
5395 electrical=0;
5396 }
5397
5398 this_death=GetMarineDeathSequence(&marineStatusPointer->HModelController,root,marineStatusPointer->Wounds,marineStatusPointer->Wounds,
5399 deathtype,&facing,burning,marineStatusPointer->IAmCrouched,electrical);
5400
5401 GLOBALASSERT(this_death);
5402
5403 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation");
5404 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
5405 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
5406 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
5407
5408 Convert_Marine_To_Corpse(sbPtr,this_death);
5409 }
5410
5411 /* See if anyone saw that? */
5412 for (a=0; a<NumActiveStBlocks; a++) {
5413 candidate=ActiveStBlockList[a];
5414 GLOBALASSERT(candidate);
5415
5416 if (candidate->I_SBtype==I_BehaviourMarine) {
5417 /* Are you already suspicious? */
5418 marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr);
5419
5420 /* Did you see that? */
5421 if (NPCCanSeeTarget(candidate,sbPtr,MARINE_NEAR_VIEW_WIDTH)) {
5422
5423 if (marineStatusPointer->Android==0) {
5424 if (gibbFactor) {
5425 marineStatusPointer->Courage-=20000;
5426 } else if (head==NULL) {
5427 marineStatusPointer->Courage-=15000;
5428 } else {
5429 marineStatusPointer->Courage-=10000;
5430 }
5431 }
5432
5433 if ((marineStatusPointer->suspicious==0)||(marineStatusPointer->using_squad_suspicion)) {
5434 /* Okay, react. */
5435 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
5436 marineStatusPointer->suspect_point=sbPtr->DynPtr->Position;
5437 /* Set this to zero when you get a *new* suspicion. */
5438 marineStatusPointer->previous_suspicion=0;
5439 marineStatusPointer->using_squad_suspicion=0;
5440 }
5441 }
5442 }
5443 }
5444 }
5445
MarineIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int wounds,SECTION_DATA * Section,VECTORCH * incoming)5446 void MarineIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming)
5447 {
5448
5449 MARINE_STATUS_BLOCK *marineStatusPointer;
5450
5451 LOCALASSERT(sbPtr);
5452 LOCALASSERT(sbPtr->containingModule);
5453 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5454 LOCALASSERT(marineStatusPointer);
5455
5456 /* if we're dying, do nothing */
5457 if(marineStatusPointer->behaviourState==MBS_Dying)
5458 {
5459 /* MFS should be dying, too */
5460 return;
5461 }
5462
5463 if(!(sbPtr->SBdptr))
5464 {
5465 DestroyAnyStrategyBlock(sbPtr);
5466 return;
5467 }
5468
5469 marineStatusPointer->Wounds|=wounds;
5470
5471 if (sbPtr->SBDamageBlock.Health > 0) {
5472
5473 if (marineStatusPointer->Mission==MM_RunAroundOnFire) {
5474 Marine_BurningScream(sbPtr);
5475 } else if ((damage->Impact==0)
5476 &&(damage->Cutting==0)
5477 &&(damage->Penetrative==0)
5478 &&(damage->Fire==0)
5479 &&(damage->Electrical==0)
5480 &&(damage->Acid>0)
5481 ) {
5482 Marine_AcidScream(sbPtr);
5483 if ((marineStatusPointer->behaviourState!=MBS_AcidAvoidance)
5484 &&(marineStatusPointer->behaviourState!=MBS_Firing)
5485 &&(marineStatusPointer->behaviourState!=MBS_Avoidance)
5486 &&(marineStatusPointer->behaviourState!=MBS_Dying)
5487 &&(marineStatusPointer->behaviourState!=MBS_PanicFire)
5488 &&(marineStatusPointer->behaviourState!=MBS_Reloading)
5489 &&(marineStatusPointer->behaviourState!=MBS_PumpAction)
5490 &&(marineStatusPointer->behaviourState!=MBS_GetWeapon)
5491 &&(marineStatusPointer->behaviourState!=MBS_PanicReloading))
5492 {
5493 Marine_Activate_AcidAvoidance_State(sbPtr,incoming);
5494 }
5495 } else {
5496 Marine_WoundedScream(sbPtr);
5497 }
5498 /* Open the mouth? */
5499 Marine_AssumePanicExpression(sbPtr);
5500 }
5501
5502 /* Might want to get a new target? */
5503
5504 marineStatusPointer->Target=NULL;
5505
5506 if (marineStatusPointer->Android) {
5507 /* Kill non-functional androids. */
5508 if ((marineStatusPointer->Wounds§ion_flag_left_hand)
5509 &&(marineStatusPointer->Wounds§ion_flag_right_hand)) {
5510 sbPtr->SBDamageBlock.Health=0;
5511 }
5512 }
5513
5514 /* reduce marine health */
5515 if(sbPtr->SBDamageBlock.Health <= 0) {
5516 /* marine experiences death */
5517 int dice=FastRandom()&65535;
5518 #if 0
5519 if ((dice<16384)||(marineStatusPointer->Android)) {
5520 #else
5521 if (marineStatusPointer->Android) {
5522 #endif
5523 Marine_SwitchExpression(sbPtr,3);
5524 } else if (dice<32768) {
5525 Marine_SwitchExpression(sbPtr,5);
5526 } else {
5527 Marine_SwitchExpression(sbPtr,4);
5528 }
5529 if (AvP.PlayerType!=I_Marine) {
5530 CurrentGameStats_CreatureKilled(sbPtr,Section);
5531 }
5532 KillMarine(sbPtr,damage,multiple,wounds,Section,incoming);
5533 } else {
5534 /* If not dead, play a hit delta. */
5535 DELTA_CONTROLLER *hitdelta;
5536 int frontback;
5537
5538 hitdelta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
5539
5540 if (incoming) {
5541 if (incoming->vz>=0) {
5542 frontback=0;
5543 } else {
5544 frontback=1;
5545 }
5546 } else {
5547 /* Default to front. */
5548 frontback=1;
5549 }
5550
5551 if (hitdelta) {
5552 /* A hierarchy with hit deltas! */
5553 int CrouchSubSequence;
5554 int StandSubSequence;
5555
5556 if (Section==NULL) {
5557 if (frontback==0) {
5558 CrouchSubSequence=MCrSS_HitChestBack;
5559 StandSubSequence=MSSS_HitChestBack;
5560 } else {
5561 CrouchSubSequence=MCrSS_HitChestFront;
5562 StandSubSequence=MSSS_HitChestFront;
5563 }
5564 } else if (Section->sempai->flags§ion_flag_head) {
5565 if (frontback==0) {
5566 CrouchSubSequence=MCrSS_HitHeadBack;
5567 StandSubSequence=MSSS_HitHeadBack;
5568 } else {
5569 CrouchSubSequence=MCrSS_HitHeadFront;
5570 StandSubSequence=MSSS_HitHeadFront;
5571 }
5572 } else if ((Section->sempai->flags§ion_flag_left_arm)
5573 ||(Section->sempai->flags§ion_flag_left_hand)) {
5574 if (frontback==0) {
5575 CrouchSubSequence=MCrSS_HitRightArm;
5576 StandSubSequence=MSSS_HitRightArm;
5577 } else {
5578 CrouchSubSequence=MCrSS_HitLeftArm;
5579 StandSubSequence=MSSS_HitLeftArm;
5580 }
5581 } else if ((Section->sempai->flags§ion_flag_right_arm)
5582 ||(Section->sempai->flags§ion_flag_right_hand)) {
5583 if (frontback==0) {
5584 CrouchSubSequence=MCrSS_HitLeftArm;
5585 StandSubSequence=MSSS_HitLeftArm;
5586 } else {
5587 CrouchSubSequence=MCrSS_HitRightArm;
5588 StandSubSequence=MSSS_HitRightArm;
5589 }
5590 } else if ((Section->sempai->flags§ion_flag_left_leg)
5591 ||(Section->sempai->flags§ion_flag_left_foot)) {
5592 if (frontback==0) {
5593 CrouchSubSequence=MCrSS_HitRightLeg;
5594 StandSubSequence=MSSS_HitRightLeg;
5595 } else {
5596 CrouchSubSequence=MCrSS_HitLeftLeg;
5597 StandSubSequence=MSSS_HitLeftLeg;
5598 }
5599 } else if ((Section->sempai->flags§ion_flag_right_leg)
5600 ||(Section->sempai->flags§ion_flag_right_foot)) {
5601 if (frontback==0) {
5602 CrouchSubSequence=MCrSS_HitLeftLeg;
5603 StandSubSequence=MSSS_HitLeftLeg;
5604 } else {
5605 CrouchSubSequence=MCrSS_HitRightLeg;
5606 StandSubSequence=MSSS_HitRightLeg;
5607 }
5608 } else {
5609 /* Chest or misc. hit. */
5610 if (frontback==0) {
5611 CrouchSubSequence=MCrSS_HitChestBack;
5612 StandSubSequence=MSSS_HitChestBack;
5613 } else {
5614 CrouchSubSequence=MCrSS_HitChestFront;
5615 StandSubSequence=MSSS_HitChestFront;
5616 }
5617 }
5618
5619
5620 if(marineStatusPointer->IAmCrouched) {
5621 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineCrouch,CrouchSubSequence)) {
5622 Start_Delta_Sequence(hitdelta,(int)HMSQT_MarineCrouch,CrouchSubSequence,-1); /* Was (ONE_FIXED>>2) */
5623 }
5624 } else {
5625 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,StandSubSequence)) {
5626 Start_Delta_Sequence(hitdelta,(int)HMSQT_MarineStand,StandSubSequence,-1); /* Was (ONE_FIXED>>2) */
5627 }
5628 }
5629 hitdelta->Playing=1;
5630 /* Not looped. */
5631
5632 }
5633
5634 /* Finally, warn the squad. */
5635 ZoneAlert(3,sbPtr->containingModule->m_aimodule);
5636 /* And become suspicious. */
5637 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
5638 /* Set this to zero when you get a *new* suspicion. */
5639 marineStatusPointer->previous_suspicion=0;
5640 marineStatusPointer->using_squad_suspicion=0;
5641 if (incoming) {
5642 marineStatusPointer->suspect_point=*incoming;
5643 /* Flip it round! */
5644 marineStatusPointer->suspect_point.vx=-marineStatusPointer->suspect_point.vx;
5645 marineStatusPointer->suspect_point.vy=-marineStatusPointer->suspect_point.vy;
5646 marineStatusPointer->suspect_point.vz=-marineStatusPointer->suspect_point.vz;
5647 Normalise(&marineStatusPointer->suspect_point);
5648 marineStatusPointer->suspect_point.vx>>=5;
5649 marineStatusPointer->suspect_point.vy>>=5;
5650 marineStatusPointer->suspect_point.vz>>=5;
5651 } else {
5652 marineStatusPointer->suspect_point.vx=0;
5653 marineStatusPointer->suspect_point.vy=0;
5654 marineStatusPointer->suspect_point.vz=-2000;
5655 }
5656 RotateVector(&marineStatusPointer->suspect_point,&sbPtr->DynPtr->OrientMat);
5657
5658 marineStatusPointer->suspect_point.vx+=sbPtr->DynPtr->Position.vx;
5659 marineStatusPointer->suspect_point.vy+=sbPtr->DynPtr->Position.vy;
5660 marineStatusPointer->suspect_point.vz+=sbPtr->DynPtr->Position.vz;
5661
5662 /* Switch wounded androids into an appropriate state. */
5663 if (marineStatusPointer->Android) {
5664 if (marineStatusPointer->Wounds§ion_flag_left_hand) {
5665 if (marineStatusPointer->My_Weapon->id!=MNPCW_AndroidSpecial) {
5666 Marine_Enter_OneArmShotgun_State(sbPtr);
5667 }
5668 } else if (marineStatusPointer->Wounds§ion_flag_right_hand) {
5669 if (marineStatusPointer->My_Weapon->id!=MNPCW_Android_Pistol_Special) {
5670 Marine_Enter_OneArmPistol_State(sbPtr);
5671 }
5672 }
5673
5674 }
5675
5676 }
5677
5678 }
5679
5680
5681
5682 /*------------------------Patrick 24/2/97-----------------------------
5683 Marine far state behaviour functions
5684 --------------------------------------------------------------------*/
5685
5686 static STATE_RETURN_CONDITION Execute_MFS_Firing(STRATEGYBLOCK *sbPtr)
5687 {
5688
5689 MARINE_STATUS_BLOCK *marineStatusPointer;
5690
5691 LOCALASSERT(sbPtr);
5692 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5693 LOCALASSERT(marineStatusPointer);
5694
5695 /* I can't deal with this right now. Better wait instead. */
5696
5697 /* Remove the gunflash */
5698 if(marineStatusPointer->myGunFlash)
5699 {
5700 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
5701 marineStatusPointer->myGunFlash = NULL;
5702 }
5703 /* .... and stop the sound */
5704 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
5705 Sound_Stop(marineStatusPointer->soundHandle);
5706 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
5707 }
5708
5709 return(SRC_Request_Wait);
5710
5711 }
5712
5713 static STATE_RETURN_CONDITION Execute_MFS_Avoidance(STRATEGYBLOCK *sbPtr) {
5714
5715 MARINE_STATUS_BLOCK *marineStatusPointer;
5716
5717 LOCALASSERT(sbPtr);
5718 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5719 LOCALASSERT(marineStatusPointer);
5720
5721 /* High on the list of Things Not To Be Doing. */
5722
5723 #if ALL_NEW_AVOIDANCE
5724 Initialise_AvoidanceManager(sbPtr,&marineStatusPointer->avoidanceManager);
5725 #endif
5726
5727 switch (marineStatusPointer->lastState) {
5728 case MBS_Retreating:
5729 return(SRC_Request_Retreat);
5730 break;
5731 case MBS_Returning:
5732 return(SRC_Request_Return);
5733 break;
5734 case MBS_Responding:
5735 return(SRC_Request_Respond);
5736 break;
5737 case MBS_Approaching:
5738 /* Go directly to approach. Do not pass GO. Do not collect 200 zorkmids. */
5739 return(SRC_Request_Approach);
5740 break;
5741 default:
5742 return(SRC_Request_Wander);
5743 break;
5744 }
5745 /* Still here? */
5746 return(SRC_Request_Wander);
5747
5748 }
5749
5750 static STATE_RETURN_CONDITION Execute_MFS_Wait(STRATEGYBLOCK *sbPtr)
5751 {
5752
5753 MARINE_STATUS_BLOCK *marineStatusPointer;
5754 AIMODULE *targetModule=0;
5755
5756 LOCALASSERT(sbPtr);
5757 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5758 LOCALASSERT(marineStatusPointer);
5759
5760 if (marineStatusPointer->suspicious) {
5761 int correctlyOrientated;
5762 VECTORCH orientationDirn;
5763
5764 orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx;
5765 orientationDirn.vy = 0;
5766 orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz;
5767 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
5768 marineStatusPointer->gotapoint=0;
5769 }
5770
5771 /* Might want to spin on the spot. */
5772 if (marineStatusPointer->gotapoint==1) {
5773
5774 VECTORCH orientationDirn;
5775 int correctlyOrientated;
5776
5777 orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx;
5778 orientationDirn.vy = 0;
5779 orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz;
5780
5781 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,ONE_FIXED,NULL);
5782
5783 if (correctlyOrientated) {
5784 marineStatusPointer->gotapoint=2;
5785 /* Done. */
5786 }
5787
5788 } else if (marineStatusPointer->gotapoint==0) {
5789 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
5790 }
5791
5792
5793 /* See if you're allowed to respond. */
5794
5795 if (
5796 (marineStatusPointer->Mission==MM_Wait_Then_Wander)
5797 ||(marineStatusPointer->Mission==MM_Guard)
5798 ) {
5799 return(SRC_No_Change);
5800 }
5801
5802 /* Possible response? LocalGuarders are allowed to wander. */
5803
5804 if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard)
5805 &&(marineStatusPointer->Mission!=MM_NonCom)) {
5806 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
5807 if (NpcSquad.responseLevel>0) {
5808 /* Picked up a target. Can we move to respond? */
5809 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
5810 if (targetModule) {
5811 NpcSquad.responseLevel--;
5812 return(SRC_Request_Respond);
5813 }
5814 }
5815 }
5816 }
5817
5818 /* Decrement the Far state timer */
5819 marineStatusPointer->stateTimer -= NormalFrameTime;
5820 /* check if far state timer has timed-out. If so, it is time
5821 to do something. Otherwise just return. */
5822 if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change);
5823
5824 /* Might want to wander. */
5825
5826 if ((FastRandom()&65535)<2048)
5827 {
5828 /* we should be wandering... we're bored of waiting. */
5829 return(SRC_Request_Wander);
5830 }
5831
5832 /* reset timer */
5833 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
5834 return(SRC_No_Change);
5835
5836 }
5837
5838 static STATE_RETURN_CONDITION Execute_MFS_SentryMode(STRATEGYBLOCK *sbPtr)
5839 {
5840 MARINE_STATUS_BLOCK *marineStatusPointer;
5841 AIMODULE *targetModule = 0;
5842
5843 LOCALASSERT(sbPtr);
5844 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5845 LOCALASSERT(marineStatusPointer);
5846
5847 /* Okay, so you're a Sentry who's been pushed off his spot. */
5848
5849 if ((sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule)
5850 ||(marineStatusPointer->missionmodule==NULL)) {
5851
5852 if (marineStatusPointer->missionmodule!=NULL) {
5853 int dist;
5854 VECTORCH offset;
5855 /* Relocate? */
5856
5857 offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->my_spot.vx;
5858 offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->my_spot.vy;
5859 offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->my_spot.vz;
5860 /* Fix for midair start points, grrrr. */
5861 offset.vy>>=2;
5862
5863 dist=Approximate3dMagnitude(&offset);
5864
5865 if (dist>SENTRY_SENSITIVITY) {
5866 sbPtr->DynPtr->Position=marineStatusPointer->my_spot;
5867 sbPtr->containingModule = (ModuleFromPosition(&(sbPtr->DynPtr->Position), sbPtr->containingModule));
5868
5869 }
5870 }
5871
5872 if (marineStatusPointer->suspicious) {
5873 int correctlyOrientated;
5874 VECTORCH orientationDirn;
5875
5876 orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx;
5877 orientationDirn.vy = 0;
5878 orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz;
5879 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
5880 marineStatusPointer->gotapoint=0;
5881 }
5882
5883 /* Might want to spin on the spot. */
5884 if (marineStatusPointer->gotapoint==1) {
5885
5886 VECTORCH orientationDirn;
5887 int correctlyOrientated;
5888
5889 orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx;
5890 orientationDirn.vy = 0;
5891 orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz;
5892
5893 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,ONE_FIXED,NULL);
5894
5895 if (correctlyOrientated) {
5896 marineStatusPointer->gotapoint=2;
5897 /* Done. */
5898 }
5899
5900 } else if (marineStatusPointer->gotapoint==0) {
5901 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
5902 }
5903
5904 } else {
5905
5906 /* Decrement the Far state timer */
5907 marineStatusPointer->stateTimer -= NormalFrameTime;
5908 /* check if far state timer has timed-out. If so, it is time
5909 to do something. Otherwise just return. */
5910 if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change);
5911
5912 /* Never engage, and ignore alerts. */
5913
5914 if (sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) {
5915 /* Same state next frame. */
5916 return(SRC_No_Change);
5917 }
5918
5919 /* get the target module... */
5920
5921 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0);
5922
5923 /* If there is no target module, we're way out there. Better wander a bit more. */
5924 if(!targetModule)
5925 {
5926 targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,marineStatusPointer->lastmodule,0);
5927 }
5928 /* Examine target, and decide what to do */
5929 GLOBALASSERT(AIModuleIsPhysical(targetModule));
5930 ProcessFarMarineTargetModule(sbPtr, targetModule);
5931 /* reset timer */
5932 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
5933 }
5934 return(SRC_No_Change);
5935 }
5936 #if 0
5937 static STATE_RETURN_CONDITION Execute_MFS_Hunt(STRATEGYBLOCK *sbPtr)
5938 {
5939 MARINE_STATUS_BLOCK *marineStatusPointer;
5940 AIMODULE *targetModule = 0;
5941
5942 LOCALASSERT(sbPtr);
5943 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5944 LOCALASSERT(marineStatusPointer);
5945
5946 /* Decrement the Far state timer */
5947 marineStatusPointer->stateTimer -= NormalFrameTime;
5948 /* check if far state timer has timed-out. If so, it is time
5949 to do something. Otherwise just return. */
5950 if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change);
5951
5952 /* check for state changes */
5953
5954 if ((!MarineIsAwareOfTarget(sbPtr))
5955 ||(marineStatusPointer->Target!=Player->ObStrategyBlock))
5956 {
5957 /* we should be wandering... can't hunt other NPCs */
5958 return(SRC_Request_Wander);
5959 }
5960
5961 /* get the target module... */
5962 targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0);
5963
5964 /* if there is no target module, it means that the pred is trapped in an
5965 unlinked module. In this case, reset the timer and return. */
5966 if(!targetModule)
5967 {
5968 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
5969 return(SRC_Request_Wait);
5970 }
5971 /* Examine target, and decide what to do */
5972 GLOBALASSERT(AIModuleIsPhysical(targetModule));
5973 ProcessFarMarineTargetModule(sbPtr, targetModule);
5974 /* reset timer */
5975 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
5976 return(SRC_No_Change);
5977 }
5978 #endif
5979
5980 static STATE_RETURN_CONDITION Execute_MFS_Approach(STRATEGYBLOCK *sbPtr) {
5981
5982 MARINE_STATUS_BLOCK *marineStatusPointer;
5983 AIMODULE *targetModule = 0;
5984 MODULE *tcm;
5985
5986 LOCALASSERT(sbPtr);
5987 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
5988 LOCALASSERT(marineStatusPointer);
5989
5990 if (!MarineIsAwareOfTarget(sbPtr))
5991 {
5992 /* we should be wandering... can't hunt other NPCs */
5993 return(SRC_Request_Wander);
5994 }
5995
5996 /* See if we can fire? */
5997
5998 if (marineStatusPointer->Target) {
5999 if (marineStatusPointer->Target->containingModule) {
6000 if (IsModuleVisibleFromModule(marineStatusPointer->Target->containingModule,sbPtr->containingModule)) {
6001 /* Take the shot? */
6002 return(SRC_Request_Fire);
6003 }
6004 }
6005 }
6006
6007 /* Can't fire. We want to get closer, then. */
6008
6009 if (marineStatusPointer->Target->containingModule) {
6010 tcm=marineStatusPointer->Target->containingModule;
6011 } else {
6012 tcm=ModuleFromPosition(&marineStatusPointer->Target->DynPtr->Position,sbPtr->containingModule);
6013 }
6014
6015 if (tcm) {
6016 targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0);
6017 }
6018
6019 if (targetModule) {
6020 /* We have somewhere to go. */
6021 GLOBALASSERT(AIModuleIsPhysical(targetModule));
6022 ProcessFarMarineTargetModule(sbPtr, targetModule);
6023 /* reset timer */
6024 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6025 marineStatusPointer->destinationmodule=targetModule;
6026 return(SRC_No_Change);
6027 }
6028
6029 /* Can't do nothin. Better wait, then. Everything else will see to itself. */
6030 if (marineStatusPointer->Mission==MM_Pathfinder) {
6031 return(SRC_Request_Return);
6032 } else {
6033 return(SRC_Request_Wait);
6034 }
6035 }
6036
6037
6038 static STATE_RETURN_CONDITION Execute_MFS_Respond(STRATEGYBLOCK *sbPtr)
6039 {
6040 MARINE_STATUS_BLOCK *marineStatusPointer;
6041 AIMODULE *targetModule = 0;
6042
6043 LOCALASSERT(sbPtr);
6044 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6045 LOCALASSERT(marineStatusPointer);
6046
6047 /* Decrement the Far state timer */
6048 marineStatusPointer->stateTimer -= NormalFrameTime;
6049
6050 if (ShowSquadState) {
6051 if (marineStatusPointer->destinationmodule==NULL) {
6052 PrintDebuggingText("Target module is NULL\n");
6053 } else {
6054 PrintDebuggingText("Target module is %s\n",(*(marineStatusPointer->destinationmodule->m_module_ptrs))->name);
6055 }
6056 }
6057
6058 /* check if far state timer has timed-out. If so, it is time
6059 to do something. Otherwise just return. */
6060 if(marineStatusPointer->stateTimer > 0) {
6061 return(SRC_No_Change);
6062 }
6063
6064 /* check for state changes */
6065
6066 if (MarineIsAwareOfTarget(sbPtr)) {
6067 /* Picked up a target. */
6068 return(SRC_Request_Approach);
6069 }
6070
6071 /* get the target module... */
6072 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
6073
6074 if (targetModule==sbPtr->containingModule->m_aimodule) {
6075 /* We've arrived. */
6076 DeprioritiseAlert(sbPtr->containingModule->m_aimodule);
6077 /* Hey, if it's real, there'll be a new one soon enough. */
6078 return(SRC_Request_Wait);
6079 }
6080
6081 /* if there is no target module, it means that the pred is trapped in an
6082 unlinked module. In this case, reset the timer and return. */
6083 if(!targetModule)
6084 {
6085 /* We can't do it. */
6086 return(SRC_Request_Wait);
6087 }
6088 /* Examine target, and decide what to do */
6089 GLOBALASSERT(AIModuleIsPhysical(targetModule));
6090 ProcessFarMarineTargetModule(sbPtr, targetModule);
6091 /* reset timer */
6092 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6093 marineStatusPointer->destinationmodule=targetModule;
6094 return(SRC_No_Change);
6095
6096 }
6097
6098 static STATE_RETURN_CONDITION Execute_MFS_Wander(STRATEGYBLOCK *sbPtr)
6099 {
6100 MARINE_STATUS_BLOCK *marineStatusPointer;
6101 AIMODULE *targetModule = 0;
6102
6103 LOCALASSERT(sbPtr);
6104 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6105 LOCALASSERT(marineStatusPointer);
6106
6107 /* Decrement the Far state timer */
6108 marineStatusPointer->stateTimer -= NormalFrameTime;
6109 /* check if far state timer has timed-out. If so, it is time
6110 to do something. Otherwise just return. */
6111 if(marineStatusPointer->stateTimer > 0) {
6112 return(SRC_No_Change);
6113 }
6114
6115 /* check for state changes */
6116 if(MarineIsAwareOfTarget(sbPtr))
6117 /* Hack! */
6118 {
6119 /* we should be hunting */
6120 return(SRC_Request_Approach);
6121 }
6122
6123 /* New alert? */
6124 if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard)
6125 &&(marineStatusPointer->Mission!=MM_NonCom)) {
6126 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
6127 if (NpcSquad.responseLevel>0) {
6128 /* Picked up a target. Can we move to respond? */
6129 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
6130 if (targetModule) {
6131 NpcSquad.responseLevel--;
6132 return(SRC_Request_Respond);
6133 }
6134 }
6135 }
6136 }
6137
6138 /* Bored of wandering? How about we wait a while? */
6139 if ((FastRandom()&65535)<2048)
6140 {
6141 /* we should be wandering... we're bored of waiting. */
6142 return(SRC_Request_Wait);
6143 }
6144
6145 /* get the target module... */
6146 targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,marineStatusPointer->lastmodule,0);
6147
6148 /* if there is no target module, it means that the pred is trapped in an
6149 unlinked module. In this case, reset the timer and return. */
6150 if(!targetModule)
6151 {
6152 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6153 return(SRC_No_Change);
6154 }
6155 /* Examine target, and decide what to do */
6156 GLOBALASSERT(AIModuleIsPhysical(targetModule));
6157 ProcessFarMarineTargetModule(sbPtr, targetModule);
6158 /* reset timer */
6159 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6160 return(SRC_No_Change);
6161 }
6162
6163 static STATE_RETURN_CONDITION Execute_MFS_Return(STRATEGYBLOCK *sbPtr)
6164 {
6165 MARINE_STATUS_BLOCK *marineStatusPointer;
6166 AIMODULE *targetModule = 0;
6167
6168 LOCALASSERT(sbPtr);
6169 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6170 LOCALASSERT(marineStatusPointer);
6171
6172 /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */
6173
6174 /* Decrement the Far state timer */
6175 marineStatusPointer->stateTimer -= NormalFrameTime;
6176 /* check if far state timer has timed-out. If so, it is time
6177 to do something. Otherwise just return. */
6178 if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change);
6179
6180 /* check for state changes */
6181 if(MarineIsAwareOfTarget(sbPtr))
6182 /* Hack! */
6183 {
6184 /* we should be engaging */
6185 return(SRC_Request_Approach);
6186 }
6187
6188 /* Ignore alerts? */
6189 #if 0
6190 if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard)
6191 &&(marineStatusPointer->Mission!=MM_NonCom)) {
6192 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
6193 if (NpcSquad.responseLevel>0) {
6194 /* Picked up a target. Can we move to respond? */
6195 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
6196 if (targetModule) {
6197 NpcSquad.responseLevel--;
6198 return(SRC_Request_Respond);
6199 }
6200 }
6201 }
6202 }
6203 #endif
6204
6205 /* Never break out of return unless your life is in danger! */
6206
6207 /* Or unless we're back. */
6208
6209 if (sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) {
6210 return(SRC_Request_Wait);
6211 }
6212
6213 /* get the target module... */
6214
6215 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0);
6216
6217 /* If there is no target module, we're way out there. Better wander a bit more. */
6218 if(!targetModule)
6219 {
6220 targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr,marineStatusPointer->lastmodule,0);
6221 }
6222 /* Examine target, and decide what to do */
6223 if (AIModuleIsPhysical(targetModule)==0) {
6224 #if 0
6225 /* No longer a straight assert: not it's breakpointable. */
6226 GLOBALASSERT(0);
6227 #else
6228 /* We're probably fubared. Change to Wander. */
6229 if (marineStatusPointer->Mission!=MM_NonCom) {
6230 /* Dunno what a NonCom is doing here, but Code Defensively! */
6231 marineStatusPointer->Mission=MM_Wander;
6232 }
6233 return(SRC_Request_Wait);
6234 #endif
6235 }
6236 ProcessFarMarineTargetModule(sbPtr, targetModule);
6237 /* reset timer */
6238 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6239 return(SRC_No_Change);
6240 }
6241
6242 static STATE_RETURN_CONDITION Execute_MFS_Pathfinder(STRATEGYBLOCK *sbPtr)
6243 {
6244 MARINE_STATUS_BLOCK *marineStatusPointer;
6245 AIMODULE *targetModule = 0;
6246 int nextModuleIndex;
6247
6248 LOCALASSERT(sbPtr);
6249 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6250 LOCALASSERT(marineStatusPointer);
6251
6252 /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */
6253
6254 /* Decrement the Far state timer */
6255 marineStatusPointer->stateTimer -= NormalFrameTime;
6256 /* check if far state timer has timed-out. If so, it is time
6257 to do something. Otherwise just return. */
6258 if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change);
6259
6260 /* check for state changes */
6261 if(MarineIsAwareOfTarget(sbPtr))
6262 /* Hack! */
6263 {
6264 /* we should be engaging */
6265 return(SRC_Request_Approach);
6266 }
6267
6268 /* Ignore alerts. */
6269
6270 /* Never break out of pathfinder unless your life is in danger! */
6271
6272 /* Okay, so where are we exactly? */
6273
6274 if ((marineStatusPointer->stepnumber<0)||(marineStatusPointer->path<0)) {
6275 /* Get OUT! */
6276 return(SRC_Request_Wander);
6277 }
6278
6279 targetModule = TranslatePathIndex(marineStatusPointer->stepnumber,marineStatusPointer->path);
6280
6281 if (targetModule==NULL) {
6282 /* Oh, to heck with this. Try to wander. */
6283 return(SRC_Request_Wander);
6284 }
6285
6286 /* Right, so there is a somewhere to get to. */
6287
6288 if (targetModule!=sbPtr->containingModule->m_aimodule) {
6289 /* But we're nowhere near it. Geeze... */
6290 marineStatusPointer->missionmodule=targetModule;
6291 return(SRC_Request_Return);
6292 }
6293
6294 /* Okay, so now we need to know where to go now. */
6295
6296 nextModuleIndex=GetNextModuleInPath(marineStatusPointer->stepnumber,marineStatusPointer->path);
6297 GLOBALASSERT(nextModuleIndex>=0);
6298 /* If that fires, it's Richard's fault. */
6299 targetModule=TranslatePathIndex(nextModuleIndex,marineStatusPointer->path);
6300 GLOBALASSERT(targetModule);
6301 /* Ditto. */
6302 marineStatusPointer->stepnumber=nextModuleIndex;
6303
6304 /* Examine target, and decide what to do */
6305 GLOBALASSERT(AIModuleIsPhysical(targetModule));
6306 ProcessFarMarineTargetModule(sbPtr, targetModule);
6307 /* reset timer */
6308 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6309 return(SRC_No_Change);
6310 }
6311
6312 static STATE_RETURN_CONDITION Execute_MFS_Retreat(STRATEGYBLOCK *sbPtr)
6313 {
6314 MARINE_STATUS_BLOCK *marineStatusPointer;
6315 AIMODULE *targetModule = 0;
6316 AIMODULE *old_fearmod;
6317
6318 LOCALASSERT(sbPtr);
6319 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6320 LOCALASSERT(marineStatusPointer);
6321
6322 /* Decrement the Far state timer */
6323 marineStatusPointer->stateTimer -= (NormalFrameTime<<1);
6324 /* Double speed, remember? */
6325
6326 /* check if far state timer has timed-out. If so, it is time
6327 to do something. Otherwise just return. */
6328 if(marineStatusPointer->stateTimer > 0) {
6329 return(SRC_No_Change);
6330 }
6331
6332 old_fearmod=marineStatusPointer->fearmodule;
6333
6334 /* From where am I running? */
6335 if(MarineIsAwareOfTarget(sbPtr)) {
6336 marineStatusPointer->fearmodule=marineStatusPointer->Target->containingModule->m_aimodule;
6337 } else if (marineStatusPointer->fearmodule==NULL) {
6338 marineStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule;
6339 }
6340
6341 if (marineStatusPointer->fearmodule!=old_fearmod) {
6342 marineStatusPointer->destinationmodule = General_GetAIModuleForRetreat(sbPtr,marineStatusPointer->fearmodule,5);
6343 }
6344
6345 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->destinationmodule,6,0);
6346
6347 if(!targetModule)
6348 {
6349 /* We can't do it. */
6350 return(SRC_Request_Wait);
6351 }
6352 /* Examine target, and decide what to do */
6353 GLOBALASSERT(AIModuleIsPhysical(targetModule));
6354 ProcessFarMarineTargetModule(sbPtr, targetModule);
6355 /* reset timer */
6356 marineStatusPointer->stateTimer = MARINE_FAR_MOVE_TIME;
6357 marineStatusPointer->destinationmodule=targetModule;
6358 return(SRC_No_Change);
6359
6360 }
6361
6362 static void ProcessFarMarineTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule)
6363 {
6364 NPC_TARGETMODULESTATUS targetStatus;
6365 MARINE_STATUS_BLOCK *marineStatusPointer;
6366
6367 LOCALASSERT(sbPtr);
6368 LOCALASSERT(targetModule);
6369 LOCALASSERT(sbPtr->I_SBtype == I_BehaviourMarine);
6370 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6371 LOCALASSERT(marineStatusPointer);
6372
6373 targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0);
6374 switch(targetStatus)
6375 {
6376 case(NPCTM_NoEntryPoint):
6377 {
6378 /* do nothing */
6379 FarNpc_FlipAround(sbPtr);
6380 break;
6381 }
6382 case(NPCTM_NormalRoom):
6383 {
6384 /* locate to target */
6385 LocateFarNPCInAIModule(sbPtr, targetModule);
6386 break;
6387 }
6388 case(NPCTM_AirDuct):
6389 {
6390 /* loacate to target */
6391 LocateFarNPCInAIModule(sbPtr, targetModule);
6392 break;
6393 }
6394 case(NPCTM_LiftTeleport):
6395 {
6396 /* do nothing */
6397 FarNpc_FlipAround(sbPtr);
6398 break;
6399 }
6400 case(NPCTM_ProxDoorOpen):
6401 {
6402 LocateFarNPCInAIModule(sbPtr, targetModule);
6403 break;
6404 }
6405 case(NPCTM_ProxDoorNotOpen):
6406 {
6407 MODULE *renderModule;
6408 renderModule=*(targetModule->m_module_ptrs);
6409 /* trigger the door, and set timer to quick so we can catch the door when it's open */
6410 ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->SBdataptr)->marineTrigger = 1;
6411 break;
6412 }
6413 case(NPCTM_LiftDoorOpen):
6414 {
6415 ///* do nothing - can't use lifts */
6416 //FarNpc_FlipAround(sbPtr);
6417 /* What the hell!!! */
6418 LocateFarNPCInAIModule(sbPtr, targetModule);
6419 break;
6420 }
6421 case(NPCTM_LiftDoorNotOpen):
6422 {
6423 /* do nothing - can't open lift doors */
6424 FarNpc_FlipAround(sbPtr);
6425 break;
6426 }
6427 case(NPCTM_SecurityDoorOpen):
6428 {
6429 /* locate to target, and move thro' quick as we can't retrigger */
6430 LocateFarNPCInAIModule(sbPtr, targetModule);
6431 break;
6432 }
6433 case(NPCTM_SecurityDoorNotOpen):
6434 {
6435 MODULE *renderModule;
6436 renderModule=*(targetModule->m_module_ptrs);
6437 /* do some door opening stuff here. Door should stay open for long enough
6438 for us to catch it open next time */
6439 RequestState((renderModule->m_sbptr),1,0);
6440 break;
6441 }
6442 default:
6443 {
6444 LOCALASSERT(1==0);
6445 }
6446 }
6447 }
6448
6449
6450 /*------------------------Patrick 24/2/97-----------------------------
6451 Marine near state behaviour functions
6452 --------------------------------------------------------------------*/
6453
6454 void Marine_Enter_SentryMode_State(STRATEGYBLOCK *sbPtr) {
6455
6456 MARINE_STATUS_BLOCK *marineStatusPointer;
6457
6458 LOCALASSERT(sbPtr);
6459 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6460 LOCALASSERT(marineStatusPointer);
6461
6462 marineStatusPointer->gotapoint=0;
6463
6464 marineStatusPointer->volleySize = 0;
6465 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6466 marineStatusPointer->behaviourState = MBS_Sentry;
6467 marineStatusPointer->stateTimer = ONE_FIXED; /* Ignored anyway... */
6468
6469 Marine_QueueNeutralExpression(sbPtr);
6470
6471 #if 0
6472 if(marineStatusPointer->IAmCrouched) {
6473 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6474 } else {
6475 if (marineStatusPointer->suspicious) {
6476 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Wait_Alert)) {
6477 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Wait_Alert,(ONE_FIXED<<2),(ONE_FIXED>>3));
6478 } else {
6479 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6480 }
6481 } else {
6482 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6483 }
6484 }
6485 #else
6486 HandleWaitingAnimations(sbPtr);
6487 #endif
6488
6489 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
6490
6491 }
6492
6493 void Marine_Enter_Wait_State(STRATEGYBLOCK *sbPtr) {
6494
6495 MARINE_STATUS_BLOCK *marineStatusPointer;
6496
6497 LOCALASSERT(sbPtr);
6498 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6499 LOCALASSERT(marineStatusPointer);
6500
6501 marineStatusPointer->gotapoint=0;
6502
6503 marineStatusPointer->internalState=0;
6504 marineStatusPointer->volleySize = 0;
6505 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6506 marineStatusPointer->behaviourState = MBS_Waiting;
6507 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
6508
6509 Marine_QueueNeutralExpression(sbPtr);
6510
6511 #if 0
6512 if(marineStatusPointer->IAmCrouched) {
6513 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6514 } else {
6515 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Stand_To_Fidget)) {
6516 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Stand_To_Fidget,((ONE_FIXED*3)/2),(ONE_FIXED>>3));
6517 marineStatusPointer->HModelController.LoopAfterTweening=0;
6518 } else {
6519 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6520 }
6521 }
6522 #else
6523 HandleWaitingAnimations(sbPtr);
6524 #endif
6525
6526 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
6527
6528 }
6529
6530 void Marine_Enter_Firing_State(STRATEGYBLOCK *sbPtr) {
6531
6532 MARINE_STATUS_BLOCK *marineStatusPointer;
6533 int range;
6534
6535 LOCALASSERT(sbPtr);
6536 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6537 LOCALASSERT(marineStatusPointer);
6538
6539 marineStatusPointer->gotapoint=0;
6540 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
6541
6542 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6543 marineStatusPointer->behaviourState = MBS_Firing;
6544 marineStatusPointer->volleySize = 0;
6545
6546 if (marineStatusPointer->My_Weapon->id!=MNPCW_MPistol) {
6547 marineStatusPointer->lastroundhit=0;
6548 }
6549 if ((marineStatusPointer->My_Weapon->id==MNPCW_Flamethrower)||
6550 (marineStatusPointer->My_Weapon->id==MNPCW_MFlamer)) {
6551 marineStatusPointer->weapon_variable=0;
6552 }
6553
6554 marineStatusPointer->lasthitsection=NULL;
6555 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
6556 GLOBALASSERT(marineStatusPointer->Target);
6557 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
6558
6559 {
6560 DELTA_CONTROLLER *delta;
6561 /* There should be NO head turn delta. */
6562 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
6563 if (delta) {
6564 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
6565 }
6566 }
6567
6568 /* Arbitrarily decide to crouch? */
6569 if (marineStatusPointer->Android) {
6570 marineStatusPointer->IAmCrouched=0;
6571 } else {
6572 int prob;
6573
6574 prob=20000;
6575
6576 if (range<6000) {
6577 prob+=10000;
6578 }
6579
6580 if ((marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy)>3000) {
6581 prob+=20000;
6582 }
6583
6584 if ((FastRandom()&65535)<prob) {
6585 marineStatusPointer->IAmCrouched=1;
6586 }
6587 }
6588
6589 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_FireFromHips)) {
6590 int target;
6591
6592 target=(marineStatusPointer->Courage>>1);
6593 if (marineStatusPointer->Mission==MM_Guard) {
6594 target+=32767;
6595 }
6596
6597 if ((FastRandom()&((ONE_FIXED<<1)-1))>target) {
6598 marineStatusPointer->FiringAnim=1;
6599 } else {
6600 marineStatusPointer->FiringAnim=0;
6601 }
6602 } else {
6603 marineStatusPointer->FiringAnim=0;
6604 }
6605
6606 if(marineStatusPointer->IAmCrouched) {
6607 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCrSS_Attack_Primary,-1,(ONE_FIXED>>3));
6608 } else {
6609 if (marineStatusPointer->FiringAnim==1) {
6610 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_FireFromHips,-1,(ONE_FIXED>>3));
6611 } else {
6612 if (marineStatusPointer->My_Weapon->id!=MNPCW_TwoPistols) {
6613 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Attack_Primary,-1,(ONE_FIXED>>3));
6614 } else {
6615 /* Two Pistols uses Stand Standard. */
6616 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,-1,(ONE_FIXED>>3));
6617 }
6618 }
6619 }
6620
6621 if (marineStatusPointer->My_Weapon->id==MNPCW_PulseRifle) {
6622 if ((marineStatusPointer->FiringAnim==0)&&(marineStatusPointer->IAmCrouched==0)) {
6623 /* Wink 2. */
6624 Marine_QueueWink2Expression(sbPtr);
6625 } else {
6626 Marine_QueueGrimaceExpression(sbPtr);
6627 }
6628 } else {
6629 Marine_QueueGrimaceExpression(sbPtr);
6630 }
6631
6632 /* This next for firing only! */
6633 marineStatusPointer->HModelController.StopAfterTweening=1;
6634
6635 if (marineStatusPointer->My_Weapon->id==MNPCW_GrenadeLauncher) {
6636 /* Why do we need internalState 1 here again? */
6637 marineStatusPointer->internalState=1;
6638 marineStatusPointer->HModelController.Looped=0;
6639 marineStatusPointer->HModelController.LoopAfterTweening=0;
6640
6641 /* Put loft in now? */
6642 {
6643 int range;
6644 range=VectorDistance((&marineStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position));
6645
6646 marineStatusPointer->weaponTarget.vy-=(range/8);
6647 }
6648 }
6649
6650 if ((marineStatusPointer->My_Weapon->id==MNPCW_MShotgun)
6651 ||(marineStatusPointer->My_Weapon->id==MNPCW_Android)
6652 ||(marineStatusPointer->My_Weapon->id==MNPCW_AndroidSpecial)) {
6653 marineStatusPointer->internalState=1;
6654 marineStatusPointer->HModelController.Looped=0;
6655 marineStatusPointer->HModelController.LoopAfterTweening=0;
6656 }
6657
6658 }
6659
6660 void Marine_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) {
6661
6662 MARINE_STATUS_BLOCK *marineStatusPointer;
6663
6664 LOCALASSERT(sbPtr);
6665 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6666 LOCALASSERT(marineStatusPointer);
6667
6668 /* Make sure obstruction is set! */
6669
6670 marineStatusPointer->gotapoint=0;
6671
6672 NPC_InitMovementData(&(marineStatusPointer->moveData));
6673 InitWaypointManager(&marineStatusPointer->waypointManager);
6674 NPCGetAvoidanceDirection(sbPtr, &(marineStatusPointer->moveData.avoidanceDirn),&marineStatusPointer->obstruction);
6675 marineStatusPointer->volleySize = 0;
6676 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6677 marineStatusPointer->behaviourState = MBS_Avoidance;
6678 marineStatusPointer->stateTimer = NPC_AVOIDTIME;
6679
6680 #if 0
6681 if(marineStatusPointer->IAmCrouched) {
6682 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6683 } else {
6684 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6685 }
6686 #else
6687 HandleMovingAnimations(sbPtr);
6688 #endif
6689
6690 /* Don't interfere with expression... */
6691
6692 }
6693
6694 void Marine_Enter_Wander_State(STRATEGYBLOCK *sbPtr) {
6695
6696 MARINE_STATUS_BLOCK *marineStatusPointer;
6697
6698 LOCALASSERT(sbPtr);
6699 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6700 LOCALASSERT(marineStatusPointer);
6701
6702 marineStatusPointer->gotapoint=0;
6703
6704 NPC_InitMovementData(&(marineStatusPointer->moveData));
6705 NPC_InitWanderData(&(marineStatusPointer->wanderData));
6706 InitWaypointManager(&marineStatusPointer->waypointManager);
6707 marineStatusPointer->volleySize = 0;
6708 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6709 marineStatusPointer->behaviourState = MBS_Wandering;
6710 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6711
6712 Marine_QueueNeutralExpression(sbPtr);
6713
6714 #if 0
6715 if(marineStatusPointer->IAmCrouched) {
6716 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6717 } else {
6718 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Bored)) {
6719 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Bored,ONE_FIXED,(ONE_FIXED>>3));
6720 } else {
6721 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6722 }
6723 }
6724 #else
6725 HandleMovingAnimations(sbPtr);
6726 #endif
6727
6728 }
6729
6730 void Marine_Enter_Approach_State(STRATEGYBLOCK *sbPtr) {
6731
6732 MARINE_STATUS_BLOCK *marineStatusPointer;
6733
6734 LOCALASSERT(sbPtr);
6735 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6736 LOCALASSERT(marineStatusPointer);
6737
6738 marineStatusPointer->gotapoint=0;
6739
6740 marineStatusPointer->volleySize = 0;
6741 NPC_InitMovementData(&(marineStatusPointer->moveData));
6742 InitWaypointManager(&marineStatusPointer->waypointManager);
6743 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6744 marineStatusPointer->behaviourState = MBS_Approaching;
6745
6746 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6747
6748 /* Neutral??? */
6749 Marine_QueueNeutralExpression(sbPtr);
6750
6751 #if 0
6752 if(marineStatusPointer->IAmCrouched) {
6753 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6754 } else {
6755 if (marineStatusPointer->Target==NULL) {
6756 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Alert)) {
6757 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Alert,ONE_FIXED,(ONE_FIXED>>3));
6758 } else {
6759 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6760 }
6761 } else {
6762 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6763 }
6764 }
6765 #else
6766 HandleMovingAnimations(sbPtr);
6767 #endif
6768
6769 marineStatusPointer->destinationmodule=NULL;
6770
6771 }
6772
6773 void Marine_Enter_Hunt_State(STRATEGYBLOCK *sbPtr) {
6774
6775 MARINE_STATUS_BLOCK *marineStatusPointer;
6776
6777 LOCALASSERT(sbPtr);
6778 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6779 LOCALASSERT(marineStatusPointer);
6780
6781 marineStatusPointer->gotapoint=0;
6782
6783 marineStatusPointer->volleySize = 0;
6784 NPC_InitMovementData(&(marineStatusPointer->moveData));
6785 InitWaypointManager(&marineStatusPointer->waypointManager);
6786 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6787 marineStatusPointer->behaviourState = MBS_Wandering; /* CHANGE ME!!! */
6788
6789 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6790
6791 /* This really shouldn't be called, should it? */
6792 Marine_QueueNeutralExpression(sbPtr);
6793
6794 if(marineStatusPointer->IAmCrouched) {
6795 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6796 } else {
6797 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6798 }
6799
6800 }
6801
6802 void Marine_Enter_Respond_State(STRATEGYBLOCK *sbPtr) {
6803
6804 MARINE_STATUS_BLOCK *marineStatusPointer;
6805
6806 LOCALASSERT(sbPtr);
6807 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6808 LOCALASSERT(marineStatusPointer);
6809
6810 marineStatusPointer->gotapoint=0;
6811
6812 marineStatusPointer->volleySize = 0;
6813 NPC_InitMovementData(&(marineStatusPointer->moveData));
6814 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6815 marineStatusPointer->behaviourState = MBS_Responding;
6816
6817 if (NpcSquad.responseLevel) {
6818 NpcSquad.responseLevel--;
6819 }
6820
6821 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6822
6823 /* Determined! */
6824 Marine_QueueNeutralExpression(sbPtr);
6825
6826 /* We must now be suspicious. */
6827 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
6828 marineStatusPointer->suspect_point=NpcSquad.squad_suspect_point;
6829 /* That'll do as a default. */
6830 if (NpcSquad.alertZone) {
6831 /* Gotta have a point. */
6832 marineStatusPointer->suspect_point=NpcSquad.alertZone->m_world;
6833 }
6834 /* Set this to zero when you get a *new* suspicion. */
6835 marineStatusPointer->previous_suspicion=0;
6836 marineStatusPointer->using_squad_suspicion=1;
6837
6838 #if 0
6839 if(marineStatusPointer->IAmCrouched) {
6840 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6841 } else {
6842 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6843 }
6844 #else
6845 HandleMovingAnimations(sbPtr);
6846 #endif
6847
6848 }
6849
6850 void Marine_Enter_Return_State(STRATEGYBLOCK *sbPtr) {
6851
6852 MARINE_STATUS_BLOCK *marineStatusPointer;
6853
6854 LOCALASSERT(sbPtr);
6855 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6856 LOCALASSERT(marineStatusPointer);
6857
6858 marineStatusPointer->gotapoint=0;
6859
6860 marineStatusPointer->volleySize = 0;
6861 NPC_InitMovementData(&(marineStatusPointer->moveData));
6862 InitWaypointManager(&marineStatusPointer->waypointManager);
6863 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6864 marineStatusPointer->behaviourState = MBS_Returning;
6865
6866 marineStatusPointer->destinationmodule=NULL;
6867
6868 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6869
6870 Marine_QueueNeutralExpression(sbPtr);
6871
6872 #if 0
6873 if(marineStatusPointer->IAmCrouched) {
6874 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6875 } else {
6876 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6877 }
6878 #else
6879 HandleMovingAnimations(sbPtr);
6880 #endif
6881
6882 }
6883
6884 void Marine_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr) {
6885
6886 MARINE_STATUS_BLOCK *marineStatusPointer;
6887
6888 LOCALASSERT(sbPtr);
6889 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6890 LOCALASSERT(marineStatusPointer);
6891
6892 marineStatusPointer->gotapoint=0;
6893
6894 marineStatusPointer->volleySize = 0;
6895 NPC_InitMovementData(&(marineStatusPointer->moveData));
6896 InitWaypointManager(&marineStatusPointer->waypointManager);
6897 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6898 marineStatusPointer->behaviourState = MBS_Pathfinding;
6899
6900 marineStatusPointer->destinationmodule=NULL;
6901
6902 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6903
6904 Marine_QueueNeutralExpression(sbPtr);
6905
6906 #if 0
6907 if(marineStatusPointer->IAmCrouched) {
6908 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6909 } else {
6910 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6911 }
6912 #else
6913 HandleMovingAnimations(sbPtr);
6914 #endif
6915
6916 }
6917
6918 void Marine_Enter_Retreat_State(STRATEGYBLOCK *sbPtr) {
6919
6920 MARINE_STATUS_BLOCK *marineStatusPointer;
6921
6922 LOCALASSERT(sbPtr);
6923 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6924 LOCALASSERT(marineStatusPointer);
6925
6926 marineStatusPointer->gotapoint=0;
6927
6928 marineStatusPointer->volleySize = 0;
6929 NPC_InitMovementData(&(marineStatusPointer->moveData));
6930 InitWaypointManager(&marineStatusPointer->waypointManager);
6931 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6932 marineStatusPointer->behaviourState = MBS_Retreating;
6933
6934 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
6935
6936 marineStatusPointer->fearmodule=NULL;
6937 /* It'll get set on state execution. */
6938
6939 if ((FastRandom()&65535)<32767) {
6940 Marine_QueuePanicExpression(sbPtr);
6941 Marine_PanicScream(sbPtr);
6942 } else {
6943 Marine_QueueGrimaceExpression(sbPtr);
6944 }
6945
6946 #if 0
6947 if(marineStatusPointer->IAmCrouched) {
6948 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6949 } else {
6950 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
6951 }
6952 #endif
6953 /* Actually, sequence change is done in the function now. */
6954
6955 }
6956
6957 void Marine_Enter_Taunt_State(STRATEGYBLOCK *sbPtr) {
6958
6959 MARINE_STATUS_BLOCK *marineStatusPointer;
6960
6961 LOCALASSERT(sbPtr);
6962 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
6963 LOCALASSERT(marineStatusPointer);
6964
6965 {
6966 DELTA_CONTROLLER *delta;
6967 /* There should be NO head turn delta. */
6968 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
6969 if (delta) {
6970 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
6971 }
6972 }
6973
6974 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Taunt_One)) {
6975
6976 marineStatusPointer->gotapoint=0;
6977 marineStatusPointer->internalState=0;
6978 marineStatusPointer->volleySize = 0;
6979 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
6980 marineStatusPointer->behaviourState = MBS_Taunting;
6981 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
6982
6983 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Taunt_One,-1,(ONE_FIXED>>3));
6984 marineStatusPointer->HModelController.LoopAfterTweening=0;
6985 } else {
6986 /* Aw, forget it. */
6987 Marine_Enter_Wait_State(sbPtr);
6988 return;
6989 }
6990
6991 if ((FastRandom()&65535)<32767) {
6992 Marine_QueueWink1Expression(sbPtr);
6993 }
6994
6995 Marine_TauntShout(sbPtr);
6996
6997 }
6998
6999 void Marine_Enter_Reload_State(STRATEGYBLOCK *sbPtr) {
7000
7001 MARINE_STATUS_BLOCK *marineStatusPointer;
7002
7003 LOCALASSERT(sbPtr);
7004 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7005 LOCALASSERT(marineStatusPointer);
7006
7007 GLOBALASSERT(HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence));
7008
7009 marineStatusPointer->gotapoint=0;
7010 marineStatusPointer->internalState=0;
7011 marineStatusPointer->volleySize = 0;
7012 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7013 marineStatusPointer->behaviourState = MBS_Reloading;
7014 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
7015
7016 {
7017 DELTA_CONTROLLER *delta;
7018 /* There should be NO head turn delta. */
7019 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7020 if (delta) {
7021 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7022 }
7023 }
7024
7025 /* Dunno if this is right. */
7026 Marine_QueueGrimaceExpression(sbPtr);
7027
7028 /* Remove the gunflash */
7029 if(marineStatusPointer->myGunFlash)
7030 {
7031 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
7032 marineStatusPointer->myGunFlash = NULL;
7033 }
7034 /* .... and stop the sound */
7035 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
7036 Sound_Stop(marineStatusPointer->soundHandle);
7037 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
7038 }
7039
7040 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence,-1,(ONE_FIXED>>3));
7041 marineStatusPointer->HModelController.LoopAfterTweening=0;
7042
7043 }
7044
7045 void Marine_Enter_PanicReload_State(STRATEGYBLOCK *sbPtr) {
7046
7047 MARINE_STATUS_BLOCK *marineStatusPointer;
7048
7049 LOCALASSERT(sbPtr);
7050 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7051 LOCALASSERT(marineStatusPointer);
7052
7053 GLOBALASSERT(HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence));
7054
7055 marineStatusPointer->gotapoint=0;
7056 marineStatusPointer->internalState=0;
7057 marineStatusPointer->volleySize = 0;
7058 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7059 marineStatusPointer->behaviourState = MBS_PanicReloading;
7060 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
7061
7062 {
7063 DELTA_CONTROLLER *delta;
7064 /* There should be NO head turn delta. */
7065 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7066 if (delta) {
7067 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7068 }
7069 }
7070
7071 if ((FastRandom()&65535)<32767) {
7072 Marine_QueuePanicExpression(sbPtr);
7073 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
7074 Marine_PanicScream(sbPtr);
7075 } else {
7076 Marine_AngryScream(sbPtr);
7077 }
7078 } else {
7079 Marine_QueueGrimaceExpression(sbPtr);
7080 }
7081
7082 /* Remove the gunflash */
7083 if(marineStatusPointer->myGunFlash)
7084 {
7085 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
7086 marineStatusPointer->myGunFlash = NULL;
7087 }
7088 /* .... and stop the sound */
7089 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
7090 Sound_Stop(marineStatusPointer->soundHandle);
7091 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
7092 }
7093
7094 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,MSSS_Panic_Reload)) {
7095 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Panic_Reload,-1,(ONE_FIXED>>3));
7096 } else {
7097 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,marineStatusPointer->My_Weapon->Reload_Sequence,-1,(ONE_FIXED>>3));
7098 }
7099 marineStatusPointer->HModelController.LoopAfterTweening=0;
7100
7101 }
7102
7103 void Marine_Enter_PumpAction_State(STRATEGYBLOCK *sbPtr) {
7104
7105 MARINE_STATUS_BLOCK *marineStatusPointer;
7106
7107 LOCALASSERT(sbPtr);
7108 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7109 LOCALASSERT(marineStatusPointer);
7110
7111 GLOBALASSERT(HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,MSSS_PumpAction));
7112
7113 /* Maintain many things from fire. */
7114 marineStatusPointer->gotapoint=0;
7115 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7116 marineStatusPointer->behaviourState = MBS_PumpAction;
7117
7118 {
7119 DELTA_CONTROLLER *delta;
7120 /* There should be NO head turn delta. */
7121 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7122 if (delta) {
7123 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7124 }
7125 }
7126
7127 /* Dunno if this is right. */
7128 Marine_QueueGrimaceExpression(sbPtr);
7129
7130 /* Remove the gunflash */
7131 if(marineStatusPointer->myGunFlash)
7132 {
7133 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
7134 marineStatusPointer->myGunFlash = NULL;
7135 }
7136 /* .... and stop the sound */
7137 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
7138 Sound_Stop(marineStatusPointer->soundHandle);
7139 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
7140 }
7141
7142 if (marineStatusPointer->IAmCrouched) {
7143 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCrSS_PumpAction,-1,(ONE_FIXED>>5));
7144 marineStatusPointer->HModelController.LoopAfterTweening=0;
7145 } else {
7146 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_PumpAction,-1,(ONE_FIXED>>5));
7147 marineStatusPointer->HModelController.LoopAfterTweening=0;
7148 }
7149
7150 }
7151
7152 void Marine_Enter_PanicFire_State(STRATEGYBLOCK *sbPtr) {
7153
7154 MARINE_STATUS_BLOCK *marineStatusPointer;
7155
7156 LOCALASSERT(sbPtr);
7157 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7158 LOCALASSERT(marineStatusPointer);
7159
7160 marineStatusPointer->gotapoint=0;
7161
7162 {
7163 DELTA_CONTROLLER *delta;
7164 /* There should be NO head turn delta. */
7165 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7166 if (delta) {
7167 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7168 }
7169 }
7170
7171 if (marineStatusPointer->My_Weapon->id==MNPCW_SADAR) {
7172 #if 0
7173 if (marineStatusPointer->Target) {
7174 Marine_Enter_Firing_State(sbPtr);
7175 return;
7176 } else {
7177 Marine_Enter_Wait_State(sbPtr);
7178 return;
7179 }
7180 #else
7181 Marine_Enter_PullPistol_State(sbPtr);
7182 return;
7183 #endif
7184 } else if (marineStatusPointer->My_Weapon->id==MNPCW_Skeeter) {
7185 Marine_Enter_PullPistol_State(sbPtr);
7186 return;
7187 } else if (marineStatusPointer->My_Weapon->id==MNPCW_MMolotov) {
7188 if (marineStatusPointer->Target) {
7189 Marine_Enter_Firing_State(sbPtr);
7190 return;
7191 } else {
7192 Marine_Enter_Wait_State(sbPtr);
7193 return;
7194 }
7195 }
7196
7197 marineStatusPointer->internalState=0;
7198 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7199 marineStatusPointer->behaviourState = MBS_PanicFire;
7200 marineStatusPointer->volleySize = 0;
7201
7202 if (marineStatusPointer->My_Weapon->id!=MNPCW_MPistol) {
7203 marineStatusPointer->lastroundhit=0;
7204 }
7205 if ((marineStatusPointer->My_Weapon->id==MNPCW_Flamethrower)||
7206 (marineStatusPointer->My_Weapon->id==MNPCW_MFlamer)) {
7207 marineStatusPointer->weapon_variable=0;
7208 }
7209
7210 marineStatusPointer->lasthitsection=NULL;
7211 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
7212 if (marineStatusPointer->Target) {
7213 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
7214 }
7215
7216 if ((FastRandom()&65535)<32767) {
7217 Marine_QueuePanicExpression(sbPtr);
7218 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
7219 Marine_PanicScream(sbPtr);
7220 } else {
7221 Marine_AngryScream(sbPtr);
7222 }
7223 } else {
7224 Marine_QueueGrimaceExpression(sbPtr);
7225 }
7226
7227 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_WildFire_0)) {
7228 /* *can* enter wild fire... */
7229 #if 0
7230 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
7231 marineStatusPointer->HModelController.LoopAfterTweening=1;
7232 #endif
7233 /* Sequence will be set in the function. */
7234 } else {
7235 /* Aw, forget it. */
7236 Marine_Enter_Retreat_State(sbPtr);
7237 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
7238 }
7239
7240 }
7241
7242 void Marine_Enter_PullPistol_State(STRATEGYBLOCK *sbPtr) {
7243
7244 MARINE_STATUS_BLOCK *marineStatusPointer;
7245 SECTION *root;
7246 MARINE_WEAPON_DATA *pistol_data;
7247
7248 LOCALASSERT(sbPtr);
7249 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7250 LOCALASSERT(marineStatusPointer);
7251
7252 GLOBALASSERT(marineStatusPointer->My_Weapon->ARealMarine);
7253
7254 marineStatusPointer->gotapoint=0;
7255 marineStatusPointer->internalState=0;
7256 marineStatusPointer->volleySize = 0;
7257 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7258 marineStatusPointer->behaviourState = MBS_GetWeapon;
7259 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
7260
7261 {
7262 DELTA_CONTROLLER *delta;
7263 /* There should be NO head turn delta... */
7264 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7265 if (delta) {
7266 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7267 }
7268 /* ...and NO Minigun delta... */
7269 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
7270 if (delta) {
7271 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
7272 }
7273 /* ...and strip out HitDelta for now, too. */
7274 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
7275 if (delta) {
7276 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
7277 }
7278 }
7279
7280 /* Now, try to be clever... */
7281 /* Turn into a pistol guy! */
7282 pistol_data=GetThisNPCMarineWeapon(MNPCW_PistolMarine);
7283 GLOBALASSERT(pistol_data);
7284
7285 root=GetNamedHierarchyFromLibrary(pistol_data->Riffname,pistol_data->HierarchyName);
7286 GLOBALASSERT(root);
7287
7288 marineStatusPointer->HModelController.Sequence_Type=HMSQT_MarineStand;
7289 marineStatusPointer->HModelController.Sub_Sequence=MSSS_Get_Weapon;
7290 /* That's to put the pistol in the right place... */
7291 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 1,0);
7292 marineStatusPointer->My_Weapon=pistol_data;
7293 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName);
7294 marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection);
7295 /* Start loaded! */
7296 marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size;
7297
7298 /* Dunno if this is right. */
7299 Marine_QueueGrimaceExpression(sbPtr);
7300
7301 /* Remove the gunflash */
7302 if(marineStatusPointer->myGunFlash)
7303 {
7304 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
7305 marineStatusPointer->myGunFlash = NULL;
7306 }
7307 /* .... and stop the sound */
7308 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
7309 Sound_Stop(marineStatusPointer->soundHandle);
7310 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
7311 }
7312
7313 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Get_Weapon,-1,(ONE_FIXED>>3));
7314 marineStatusPointer->HModelController.LoopAfterTweening=0;
7315
7316 /* Attempt to put the hitdelta back? */
7317 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
7318 DELTA_CONTROLLER *delta;
7319 delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
7320 GLOBALASSERT(delta);
7321 delta->Playing=0;
7322 }
7323
7324 DeInitialise_HModel(&marineStatusPointer->HModelController);
7325 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
7326
7327 }
7328
7329 void Marine_Enter_OneArmShotgun_State(STRATEGYBLOCK *sbPtr) {
7330
7331 MARINE_STATUS_BLOCK *marineStatusPointer;
7332 SECTION *root;
7333 MARINE_WEAPON_DATA *pistol_data;
7334
7335 LOCALASSERT(sbPtr);
7336 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7337 LOCALASSERT(marineStatusPointer);
7338
7339 GLOBALASSERT(marineStatusPointer->Android);
7340
7341 marineStatusPointer->gotapoint=0;
7342 marineStatusPointer->internalState=0;
7343 marineStatusPointer->volleySize = 0;
7344 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7345 marineStatusPointer->behaviourState = MBS_Waiting;
7346 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
7347
7348 {
7349 DELTA_CONTROLLER *delta;
7350 /* There should be NO head turn delta... */
7351 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7352 if (delta) {
7353 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7354 }
7355 /* ...and NO Minigun delta... */
7356 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
7357 if (delta) {
7358 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
7359 }
7360 /* ...and strip out HitDelta for now, too. */
7361 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
7362 if (delta) {
7363 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
7364 }
7365 }
7366
7367 /* Now, try to be clever... */
7368 /* Turn into an Android Special! */
7369 pistol_data=GetThisNPCMarineWeapon(MNPCW_AndroidSpecial);
7370 GLOBALASSERT(pistol_data);
7371
7372 root=GetNamedHierarchyFromLibrary(pistol_data->Riffname,pistol_data->HierarchyName);
7373 GLOBALASSERT(root);
7374
7375 marineStatusPointer->HModelController.Sequence_Type=HMSQT_MarineStand;
7376 marineStatusPointer->HModelController.Sub_Sequence=MSSS_Standard;
7377 /* That's to put the pistol in the right place... */
7378 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 1,0);
7379 marineStatusPointer->My_Weapon=pistol_data;
7380 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName);
7381 marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection);
7382
7383 /* Retain clipammo from the old shotgun. */
7384
7385 /* Remove the gunflash */
7386 if(marineStatusPointer->myGunFlash)
7387 {
7388 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
7389 marineStatusPointer->myGunFlash = NULL;
7390 }
7391 /* .... and stop the sound */
7392 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
7393 Sound_Stop(marineStatusPointer->soundHandle);
7394 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
7395 }
7396
7397 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,-1,(ONE_FIXED>>3));
7398 marineStatusPointer->HModelController.LoopAfterTweening=0;
7399
7400 /* Attempt to put the hitdelta back? */
7401 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
7402 DELTA_CONTROLLER *delta;
7403 delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
7404 GLOBALASSERT(delta);
7405 delta->Playing=0;
7406 }
7407
7408 DeInitialise_HModel(&marineStatusPointer->HModelController);
7409 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
7410
7411 }
7412
7413 void Marine_Enter_OneArmPistol_State(STRATEGYBLOCK *sbPtr) {
7414
7415 MARINE_STATUS_BLOCK *marineStatusPointer;
7416 SECTION *root;
7417 MARINE_WEAPON_DATA *pistol_data;
7418
7419 LOCALASSERT(sbPtr);
7420 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7421 LOCALASSERT(marineStatusPointer);
7422
7423 GLOBALASSERT(marineStatusPointer->Android);
7424
7425 marineStatusPointer->gotapoint=0;
7426 marineStatusPointer->internalState=0;
7427 marineStatusPointer->volleySize = 0;
7428 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
7429 marineStatusPointer->behaviourState = MBS_GetWeapon;
7430 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
7431
7432 {
7433 DELTA_CONTROLLER *delta;
7434 /* There should be NO head turn delta... */
7435 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7436 if (delta) {
7437 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
7438 }
7439 /* ...and NO Minigun delta... */
7440 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
7441 if (delta) {
7442 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
7443 }
7444 /* ...and strip out HitDelta for now, too. */
7445 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
7446 if (delta) {
7447 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
7448 }
7449 }
7450
7451 /* Now, try to be clever... */
7452 /* Turn into an Android Special! */
7453 pistol_data=GetThisNPCMarineWeapon(MNPCW_Android_Pistol_Special);
7454 GLOBALASSERT(pistol_data);
7455
7456 root=GetNamedHierarchyFromLibrary(pistol_data->Riffname,pistol_data->HierarchyName);
7457 GLOBALASSERT(root);
7458
7459 marineStatusPointer->HModelController.Sequence_Type=HMSQT_MarineStand;
7460 marineStatusPointer->HModelController.Sub_Sequence=MSSS_Get_Weapon;
7461 /* That's to put the pistol in the right place... */
7462 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 1,0);
7463 marineStatusPointer->My_Weapon=pistol_data;
7464 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName);
7465 marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection);
7466 /* Start loaded! */
7467 marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size;
7468
7469 /* Remove the gunflash */
7470 if(marineStatusPointer->myGunFlash)
7471 {
7472 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
7473 marineStatusPointer->myGunFlash = NULL;
7474 }
7475 /* .... and stop the sound */
7476 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
7477 Sound_Stop(marineStatusPointer->soundHandle);
7478 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
7479 }
7480
7481 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Get_Weapon,-1,(ONE_FIXED>>3));
7482 marineStatusPointer->HModelController.LoopAfterTweening=0;
7483
7484 /* Attempt to put the hitdelta back? */
7485 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
7486 DELTA_CONTROLLER *delta;
7487 delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
7488 GLOBALASSERT(delta);
7489 delta->Playing=0;
7490 }
7491
7492 DeInitialise_HModel(&marineStatusPointer->HModelController);
7493 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
7494
7495 }
7496
7497 static STATE_RETURN_CONDITION Execute_MNS_Approach(STRATEGYBLOCK *sbPtr)
7498 {
7499 MARINE_STATUS_BLOCK *marineStatusPointer;
7500 VECTORCH velocityDirection = {0,0,0};
7501 VECTORCH targetPosition;
7502 int targetIsAirduct = 0;
7503 int range;
7504
7505 LOCALASSERT(sbPtr);
7506 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7507 LOCALASSERT(marineStatusPointer);
7508
7509 HandleMovingAnimations(sbPtr);
7510
7511 /* now check for state changes... firstly, if we can no longer attack the target, go
7512 to wander */
7513 if(!(MarineIsAwareOfTarget(sbPtr)))
7514 {
7515 if (marineStatusPointer->suspicious==0) {
7516 /* Return to wait. Nothing to worry about. */
7517 return(SRC_Request_Wait);
7518 }
7519
7520 } else {
7521
7522 /* We have a target that we are aware of. */
7523
7524 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
7525
7526 /* if we are close... go directly to firing */
7527 if(range < marineStatusPointer->My_Weapon->ForceFireRange)
7528 {
7529 /* switch directly to firing, at this distance */
7530
7531 return(SRC_Request_Fire);
7532 }
7533
7534 /* if our state timer has run out in approach state, see if we can fire*/
7535 if(marineStatusPointer->stateTimer > 0) marineStatusPointer->stateTimer -= NormalFrameTime;
7536 if(marineStatusPointer->stateTimer <= 0)
7537 {
7538 /* it is time to fire, if we can see the target */
7539 if((MarineCanSeeTarget(sbPtr))
7540 &&((marineStatusPointer->My_Weapon->MaxRange==-1)
7541 ||(range<marineStatusPointer->My_Weapon->MaxRange))) {
7542
7543 /* we are going to fire then */
7544
7545 return(SRC_Request_Fire);
7546 }
7547 else
7548 {
7549 /* renew approach state */
7550 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
7551
7552 }
7553 }
7554 }
7555
7556 /* Kick them out of the stupid state? */
7557
7558 /* See which way we want to go. */
7559 if ((marineStatusPointer->destinationmodule==sbPtr->containingModule->m_aimodule)
7560 ||(marineStatusPointer->destinationmodule==NULL)) {
7561
7562 AIMODULE *targetModule;
7563 MODULE *tcm;
7564 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
7565
7566 if (marineStatusPointer->Target==NULL) {
7567 /* Must be approaching a suspect point. */
7568 GLOBALASSERT(marineStatusPointer->suspicious);
7569 tcm=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule);
7570 } else {
7571 if (marineStatusPointer->Target->containingModule) {
7572 tcm=marineStatusPointer->Target->containingModule;
7573 } else {
7574 tcm=ModuleFromPosition(&marineStatusPointer->Target->DynPtr->Position,sbPtr->containingModule);
7575 }
7576 }
7577
7578 if (tcm) {
7579 targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,tcm->m_aimodule,7,0);
7580 } else {
7581 targetModule=NULL;
7582 }
7583
7584 if (targetModule==sbPtr->containingModule->m_aimodule) {
7585 /* Try going for it, we still can't see them. */
7586 if (marineStatusPointer->Target) {
7587 NPCGetMovementTarget(sbPtr, marineStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
7588 } else {
7589 int range2;
7590 VECTORCH relTargetPosition;
7591 /* Just use the target point? */
7592 targetPosition=marineStatusPointer->suspect_point;
7593
7594 #if 0
7595 range2=VectorDistance(&targetPosition,(&sbPtr->DynPtr->Position));
7596 #else
7597
7598 relTargetPosition=targetPosition;
7599
7600 relTargetPosition.vx-=sbPtr->DynPtr->Position.vx;
7601 relTargetPosition.vy-=sbPtr->DynPtr->Position.vy;
7602 relTargetPosition.vz-=sbPtr->DynPtr->Position.vz;
7603
7604 /* Let's try doing this. */
7605 relTargetPosition.vy>>=2;
7606
7607 range2=Approximate3dMagnitude(&relTargetPosition);
7608 #endif
7609
7610 if (range2<SUSPECT_SENSITIVITY) {
7611 /* That's probably close enough. */
7612 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
7613 /* Used to unset suspicion at that point. */
7614 if (marineStatusPointer->Mission==MM_Pathfinder) {
7615 /* Get back to business! */
7616 return(SRC_Request_Return);
7617 } else {
7618 return(SRC_Request_Wait);
7619 }
7620 }
7621
7622 }
7623 NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&marineStatusPointer->waypointManager);
7624 } else if (!targetModule) {
7625 /* Must be inaccessible. Time out suspicion. */
7626 marineStatusPointer->suspicious-=NormalFrameTime;
7627 /* To fix the next trap... */
7628 if (marineStatusPointer->suspicious==0) {
7629 marineStatusPointer->suspicious=-1;
7630 }
7631 if (marineStatusPointer->suspicious<0) {
7632 marineStatusPointer->suspicious=0;
7633 /* Set to zero on natural timeout, too. */
7634 marineStatusPointer->previous_suspicion=0;
7635 marineStatusPointer->using_squad_suspicion=0;
7636 if ((marineStatusPointer->behaviourState==MBS_Waiting)
7637 ||(marineStatusPointer->behaviourState==MBS_Sentry)) {
7638 /* We might concievably want to do this for all states. */
7639 marineStatusPointer->gotapoint=0;
7640 }
7641 }
7642
7643 if (ShowSquadState) {
7644 if (marineStatusPointer->Target) {
7645 if (marineStatusPointer->Target->containingModule) {
7646 PrintDebuggingText("I can see you, but I can't get there!\n");
7647 } else {
7648 PrintDebuggingText("Hey, you've got no Containing Module!\n");
7649 }
7650 } else {
7651 PrintDebuggingText("Can't get to the suspect point!\n");
7652 /* Yuck. Stop it. */
7653 #if 0
7654 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
7655 /* Used to unset suspicion at that point. */
7656 #else
7657 marineStatusPointer->suspicious=1;
7658 /* Just this once, let's unset it... We can't do anything about it. */
7659 #endif
7660 return(SRC_Request_Wait);
7661 }
7662 }
7663 return(SRC_No_Change);
7664 } else {
7665
7666 thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
7667 if (!thisEp) {
7668 LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",
7669 (*(targetModule->m_module_ptrs))->name,
7670 sbPtr->containingModule->name));
7671 //LOGDXFMT(("This assert is a busted adjacency!"));
7672 GLOBALASSERT(thisEp);
7673 }
7674 /* If that fired, there's a farped adjacency. */
7675 GLOBALASSERT(thisEp->alien_only==0);
7676 /* If that fired, GetNextModuleForLink went wrong. */
7677
7678 marineStatusPointer->wanderData.worldPosition=thisEp->position;
7679 marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
7680 marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
7681 marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
7682
7683 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
7684
7685 }
7686
7687 } else if (marineStatusPointer->destinationmodule!=NULL) {
7688 /* Go towards next module. */
7689 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
7690 } else {
7691 /* we are still in approach state: target the target, and move */
7692 if (marineStatusPointer->Target) {
7693 NPCGetMovementTarget(sbPtr, marineStatusPointer->Target, &targetPosition, &targetIsAirduct,0);
7694 } else {
7695 /* How did we get here, anyway? */
7696 targetPosition=marineStatusPointer->suspect_point;
7697 }
7698 NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&marineStatusPointer->waypointManager);
7699 }
7700
7701 /* Should have a velocity set now. */
7702
7703 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
7704
7705 /* test here for impeding collisions, and not being able to reach target... */
7706 #if ALL_NEW_AVOIDANCE
7707 {
7708 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
7709 /* Go to all new avoidance. */
7710 return(SRC_Request_Avoidance);
7711 }
7712 }
7713 #else
7714 {
7715 STRATEGYBLOCK *destructableObject = NULL;
7716
7717 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
7718 if(marineStatusPointer->obstruction.environment)
7719 {
7720 /* go to avoidance */
7721 return(SRC_Request_Avoidance);
7722 }
7723 if(marineStatusPointer->obstruction.destructableObject)
7724 {
7725 LOCALASSERT(destructableObject);
7726 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
7727 }
7728 }
7729
7730 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &targetPosition, &velocityDirection))
7731 {
7732
7733 marineStatusPointer->obstruction.environment=1;
7734 marineStatusPointer->obstruction.destructableObject=0;
7735 marineStatusPointer->obstruction.otherCharacter=0;
7736 marineStatusPointer->obstruction.anySingleObstruction=0;
7737
7738 return(SRC_Request_Avoidance);
7739 }
7740 #endif
7741
7742 return(SRC_No_Change);
7743 }
7744
7745
7746 /* this function is specifically for marines, and creates a gun flash
7747 pointing in the direction of the target point */
7748 static void MaintainMarineGunFlash(STRATEGYBLOCK *sbPtr)
7749 {
7750 VECTORCH firingDirn,firingPoint;
7751 MARINE_STATUS_BLOCK *marineStatusPointer;
7752 int firingOffsetUp;
7753 int firingOffsetInfront;
7754 int firingOffsetAcross;
7755
7756 LOCALASSERT(sbPtr);
7757 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7758 LOCALASSERT(marineStatusPointer);
7759
7760 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
7761
7762 /* get the firing point offsets:*/
7763 if(marineStatusPointer->IAmCrouched)
7764 {
7765 firingOffsetUp = MARINE_FIRINGPOINT_UP;
7766 firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT;
7767 firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS;
7768 }
7769 else
7770 {
7771 firingOffsetUp = MARINE_FIRINGPOINT_UP_CROUCHED;
7772 firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT_CROUCHED;
7773 firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS_CROUCHED;
7774 }
7775
7776 /* find the firing direction */
7777 firingDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
7778 firingDirn.vy = marineStatusPointer->weaponTarget.vy - sbPtr->DynPtr->Position.vy;
7779 firingDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
7780 Normalise(&firingDirn);
7781 {
7782 VECTORCH yNormal = {0,-65536,0};
7783 VECTORCH tempDirn;
7784 VECTORCH acrossDirn;
7785
7786 /* now find firing point (conceptually, the end of the weapon muzzle)... */
7787 firingPoint = sbPtr->DynPtr->Position;
7788 firingPoint.vx += MUL_FIXED(firingDirn.vx,firingOffsetInfront);
7789 firingPoint.vz += MUL_FIXED(firingDirn.vz,firingOffsetInfront);
7790
7791 tempDirn = firingDirn;
7792 tempDirn.vy = 0;
7793 Normalise(&tempDirn);
7794 CrossProduct(&tempDirn,&yNormal,&acrossDirn);
7795 Normalise(&acrossDirn);
7796 firingPoint.vx += MUL_FIXED(tempDirn.vx,firingOffsetAcross);
7797 firingPoint.vz += MUL_FIXED(tempDirn.vz,firingOffsetAcross);
7798 firingPoint.vy += MUL_FIXED(yNormal.vy,firingOffsetUp);
7799 }
7800 LOCALASSERT(marineStatusPointer->myGunFlash!=NULL);
7801
7802 MaintainNPCGunFlashEffect(marineStatusPointer->myGunFlash,&marineStatusPointer->My_Gunflash_Section->World_Offset,
7803 &marineStatusPointer->My_Gunflash_Section->SecMat);
7804 }
7805
7806 /* NB this shouldn't be called if :
7807 1. we are close to the target
7808 2. we are crouched */
7809 static void LobAGrenade(STRATEGYBLOCK *sbPtr)
7810 {
7811 MARINE_STATUS_BLOCK *marineStatusPointer;
7812 //VECTORCH firingPoint;
7813 //VECTORCH firingDirn;
7814
7815 LOCALASSERT(sbPtr);
7816 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7817 LOCALASSERT(marineStatusPointer);
7818
7819 /* first, find the firing direction */
7820 //firingDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
7821 //firingDirn.vy = marineStatusPointer->weaponTarget.vy - sbPtr->DynPtr->Position.vz;
7822 //firingDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
7823 //Normalise(&firingDirn);
7824
7825 if((sbPtr->DynPtr->Position.vy - marineStatusPointer->weaponTarget.vy) > 2500)
7826 {
7827 /* too high */
7828 return;
7829 }
7830
7831 #if 0
7832 {
7833 VECTORCH yNormal = {0,-65536,0};
7834 VECTORCH tempDirn;
7835 VECTORCH acrossDirn;
7836
7837 /* now find firing point (conceptually, the end of the weapon muzzle + a bit)... */
7838 firingPoint = sbPtr->DynPtr->Position;
7839 firingPoint.vx += MUL_FIXED(firingDirn.vx,(MARINE_FIRINGPOINT_INFRONT+400));
7840 firingPoint.vz += MUL_FIXED(firingDirn.vz,(MARINE_FIRINGPOINT_INFRONT+400));
7841
7842 tempDirn = firingDirn;
7843 tempDirn.vy = 0;
7844 Normalise(&tempDirn);
7845 CrossProduct(&tempDirn,&yNormal,&acrossDirn);
7846 Normalise(&acrossDirn);
7847 firingPoint.vx += MUL_FIXED(tempDirn.vx,MARINE_FIRINGPOINT_ACROSS);
7848 firingPoint.vz += MUL_FIXED(tempDirn.vz,MARINE_FIRINGPOINT_ACROSS);
7849 firingPoint.vy += MUL_FIXED(yNormal.vy,MARINE_FIRINGPOINT_UP);
7850 }
7851 #endif
7852
7853 /* this bit nicked from player grenade creation fn. in bh_weap.c :
7854 actually, it is now a pulse rifle grenade */
7855 {
7856 DISPLAYBLOCK *dispPtr;
7857 DYNAMICSBLOCK *dynPtr;
7858
7859 dispPtr = MakeObject(I_BehaviourPulseGrenade,&marineStatusPointer->My_Gunflash_Section->World_Offset);
7860 if(!dispPtr) return;
7861 LOCALASSERT(dispPtr->ObStrategyBlock);
7862 AddLightingEffectToObject(dispPtr,LFX_ROCKETJET);
7863 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
7864 if(!dynPtr)
7865 {
7866 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
7867 return;
7868 }
7869 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
7870 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK));
7871 if(!dispPtr->ObStrategyBlock->SBdataptr)
7872 {
7873 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
7874 return;
7875 }
7876 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
7877 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = 0;
7878
7879 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
7880
7881 #define PULSEGRENADE_SPEED 100000 // Was 30000
7882 dynPtr->Position = marineStatusPointer->My_Gunflash_Section->World_Offset;
7883 dynPtr->OrientMat = marineStatusPointer->My_Gunflash_Section->SecMat;
7884 dynPtr->PrevOrientMat = dynPtr->OrientMat; /* stops mis-alignment if dynamics problem */
7885
7886 dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31;
7887 dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32;
7888 dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33;
7889
7890 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, PULSEGRENADE_SPEED);
7891 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, PULSEGRENADE_SPEED);
7892 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, PULSEGRENADE_SPEED);
7893
7894 //dynPtr->LinImpulse.vx = MUL_FIXED(firingDirn.vx,PULSEGRENADE_SPEED);
7895 //dynPtr->LinImpulse.vy = MUL_FIXED(firingDirn.vy,PULSEGRENADE_SPEED);
7896 //dynPtr->LinImpulse.vz = MUL_FIXED(firingDirn.vz,PULSEGRENADE_SPEED);
7897 }
7898 }
7899
7900 /*NB avoidance state behaviour function probabaly doesn't need to check
7901 for crouching, or for target becoming cloaked. Only when we exit the state
7902 do we need to check these behaviour parameters to pick a new state and sequence*/
7903 static STATE_RETURN_CONDITION Execute_MNS_Avoidance(STRATEGYBLOCK *sbPtr)
7904 {
7905 MARINE_STATUS_BLOCK *marineStatusPointer;
7906 int terminateState = 0;
7907
7908 LOCALASSERT(sbPtr);
7909 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
7910 LOCALASSERT(marineStatusPointer);
7911
7912 #if 1
7913 HandleMovingAnimations(sbPtr);
7914 #endif
7915
7916 #if ALL_NEW_AVOIDANCE
7917 /* New avoidance kernel. */
7918
7919 NPCSetVelocity(sbPtr, &(marineStatusPointer->avoidanceManager.avoidanceDirection), (marineStatusPointer->nearSpeed));
7920 /* Velocity CANNOT be zero, unless deliberately so! */
7921 {
7922 AVOIDANCE_RETURN_CONDITION rc;
7923
7924 rc=AllNewAvoidanceKernel(sbPtr,&marineStatusPointer->avoidanceManager);
7925
7926 if (rc!=AvRC_Avoidance) {
7927 terminateState=1;
7928 }
7929 /* Should put in a test for AvRC_Failure here. */
7930 }
7931
7932 #if 0
7933 {
7934 VECTORCH point;
7935 /* Wacky test. */
7936 GetTargetingPointOfObject_Far(sbPtr,&point);
7937 MakeParticle(&point,&sbPtr->DynPtr->LinVelocity,PARTICLE_NONCOLLIDINGFLAME);
7938
7939 MakeParticle(&point,&(marineStatusPointer->avoidanceManager.avoidanceDirection),PARTICLE_PREDATOR_BLOOD);
7940 MakeParticle(&point,&(marineStatusPointer->avoidanceManager.aggregateNormal),PARTICLE_ALIEN_BLOOD);
7941
7942 }
7943 #endif
7944
7945 #else
7946 /* set velocity */
7947 LOCALASSERT((marineStatusPointer->moveData.avoidanceDirn.vx!=0)||
7948 (marineStatusPointer->moveData.avoidanceDirn.vy!=0)||
7949 (marineStatusPointer->moveData.avoidanceDirn.vz!=0));
7950 NPCSetVelocity(sbPtr, &(marineStatusPointer->moveData.avoidanceDirn), (marineStatusPointer->nearSpeed));
7951
7952 /* decrement state timer */
7953 marineStatusPointer->stateTimer -= NormalFrameTime;
7954 if(marineStatusPointer->stateTimer <= 0) terminateState = 1;
7955
7956 {
7957 STRATEGYBLOCK *destructableObject = NULL;
7958 NPC_OBSTRUCTIONREPORT obstruction;
7959 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&obstruction,&destructableObject);
7960 if(obstruction.anySingleObstruction)
7961 {
7962 terminateState = 1;
7963 }
7964 }
7965 #endif
7966
7967 if(terminateState)
7968 {
7969 /* switch to approach */
7970 if(MarineIsAwareOfTarget(sbPtr))
7971 {
7972 /* go to approach */
7973
7974 return(SRC_Request_Approach);
7975 /* Was fire! */
7976 }
7977 else
7978 {
7979 /* go to an appropriate state */
7980 switch (marineStatusPointer->lastState) {
7981 case MBS_Retreating:
7982 return(SRC_Request_Retreat);
7983 break;
7984 case MBS_Returning:
7985 return(SRC_Request_Return);
7986 break;
7987 case MBS_Responding:
7988 return(SRC_Request_Respond);
7989 break;
7990 case MBS_Approaching:
7991 /* Go directly to approach. Do not pass GO. Do not collect 200 zorkmids. */
7992 return(SRC_Request_Approach);
7993 break;
7994 case MBS_Sentry:
7995 /* Go back to sentry. */
7996 return(SRC_Request_Wait);
7997 break;
7998 default:
7999 return(SRC_Request_Wander);
8000 break;
8001 }
8002 /* Still here? */
8003 return(SRC_Request_Wander);
8004 }
8005 }
8006 return(SRC_No_Change);
8007 }
8008
8009 static STATE_RETURN_CONDITION Execute_MNS_Wander(STRATEGYBLOCK *sbPtr)
8010 {
8011 MARINE_STATUS_BLOCK *marineStatusPointer;
8012 DYNAMICSBLOCK *dynPtr;
8013 VECTORCH velocityDirection = {0,0,0};
8014
8015 LOCALASSERT(sbPtr);
8016 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
8017 dynPtr = sbPtr->DynPtr;
8018 LOCALASSERT(marineStatusPointer);
8019 LOCALASSERT(dynPtr);
8020
8021 HandleMovingAnimations(sbPtr);
8022
8023 /* should we change to approach state? */
8024 if ((MarineIsAwareOfTarget(sbPtr))||(marineStatusPointer->suspicious))
8025 {
8026 /* doesn't require a sequence change */
8027 return(SRC_Request_Approach);
8028 }
8029
8030 /* Is there a new alert? */
8031 if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard)
8032 &&(marineStatusPointer->Mission!=MM_NonCom)) {
8033 /* Are we already there? */
8034 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
8035 if (NpcSquad.responseLevel>0) {
8036 /* Picked up a target. Can we move to respond? */
8037 AIMODULE *targetModule=0;
8038 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
8039 if (targetModule) {
8040 return(SRC_Request_Respond);
8041 }
8042 }
8043 }
8044 }
8045
8046 /* Are we bored of wandering yet? */
8047
8048 marineStatusPointer->stateTimer-=NormalFrameTime;
8049
8050 if (marineStatusPointer->stateTimer<=0) {
8051 /* Time to make a decision. */
8052 marineStatusPointer->stateTimer = MARINE_NEARWAITTIME;
8053 if ((FastRandom()&65535)<8192)
8054 {
8055 /* This is too tiring... let's just wait around a while. */
8056 return(SRC_Request_Wait);
8057 }
8058 }
8059
8060 /* Are we using bimble rules? */
8061
8062 if (marineStatusPointer->wanderData.currentModule==NPC_BIMBLINGINMODULE) {
8063
8064 int range;
8065
8066 /* Range to target... */
8067
8068 range=VectorDistance((&marineStatusPointer->wanderData.worldPosition),(&sbPtr->DynPtr->Position));
8069
8070 if (range<2000) {
8071
8072 /* Reset system, try again. */
8073 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
8074 marineStatusPointer->moveData.lastModule=NULL;
8075
8076 }
8077
8078 } else {
8079
8080 /* wander target aquisition: if no target, or moved module */
8081 LOCALASSERT(sbPtr->containingModule);
8082 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8083 {
8084 NPC_InitMovementData(&(marineStatusPointer->moveData));
8085 marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule;
8086 NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0);
8087
8088 }
8089 else if(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)
8090 {
8091 NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0);
8092
8093 }
8094
8095 /* if we still haven't got one, bimble about in this one for a bit. */
8096 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8097 {
8098 NPC_GetBimbleTarget(sbPtr,&marineStatusPointer->wanderData.worldPosition);
8099 marineStatusPointer->wanderData.currentModule=NPC_BIMBLINGINMODULE;
8100
8101 }
8102
8103 }
8104
8105 /* ok: should have a current target at this stage... */
8106 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
8107 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
8108
8109 /* test here for impeding collisions, and not being able to reach target... */
8110 #if ALL_NEW_AVOIDANCE
8111 {
8112 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
8113 /* Go to all new avoidance. */
8114 return(SRC_Request_Avoidance);
8115 }
8116 }
8117 #else
8118 {
8119 STRATEGYBLOCK *destructableObject = NULL;
8120 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
8121 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
8122 {
8123 /* go to avoidance */
8124 return(SRC_Request_Avoidance);
8125 }
8126 if(marineStatusPointer->obstruction.destructableObject)
8127 {
8128 LOCALASSERT(destructableObject);
8129 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
8130 }
8131 }
8132
8133 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
8134 {
8135 /* go to avoidance */
8136 /* no sequence change required */
8137
8138 marineStatusPointer->obstruction.environment=1;
8139 marineStatusPointer->obstruction.destructableObject=0;
8140 marineStatusPointer->obstruction.otherCharacter=0;
8141 marineStatusPointer->obstruction.anySingleObstruction=0;
8142
8143 return(SRC_Request_Avoidance);
8144 }
8145 #endif
8146
8147 return(SRC_No_Change);
8148 }
8149
8150 static STATE_RETURN_CONDITION Execute_MNS_Return(STRATEGYBLOCK *sbPtr)
8151 {
8152 MARINE_STATUS_BLOCK *marineStatusPointer;
8153 DYNAMICSBLOCK *dynPtr;
8154 AIMODULE *targetModule;
8155 VECTORCH velocityDirection = {0,0,0};
8156
8157 LOCALASSERT(sbPtr);
8158 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
8159 dynPtr = sbPtr->DynPtr;
8160 LOCALASSERT(marineStatusPointer);
8161 LOCALASSERT(dynPtr);
8162
8163 HandleMovingAnimations(sbPtr);
8164
8165 /* should we change to approach state? */
8166 if(MarineIsAwareOfTarget(sbPtr))
8167 {
8168 /* doesn't require a sequence change */
8169 return(SRC_Request_Approach);
8170 }
8171
8172 #if 0
8173 /* Ignore alerts. */
8174 if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard)
8175 &&(marineStatusPointer->Mission!=MM_NonCom)) {
8176 /* Are we already there? */
8177 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
8178 if (NpcSquad.responseLevel>0) {
8179 /* Picked up a target. Can we move to respond? */
8180 AIMODULE *targetModule=0;
8181 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
8182 if (targetModule) {
8183 return(SRC_Request_Respond);
8184 }
8185 }
8186 }
8187 }
8188 #endif
8189
8190 marineStatusPointer->stateTimer-=NormalFrameTime;
8191
8192 /* Are we there yet? */
8193 if (sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule) {
8194 return(SRC_Request_Wait);
8195 }
8196
8197 /* Target module aquisition. */
8198
8199 LOCALASSERT(sbPtr->containingModule);
8200
8201 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8202 {
8203 NPC_InitMovementData(&(marineStatusPointer->moveData));
8204 }
8205 if ((marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8206 ||(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) {
8207
8208 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0);
8209
8210 if (targetModule) {
8211 FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
8212 if(thisEp) {
8213 /* aha. an ep!... */
8214 VECTORCH thisEpWorld = thisEp->position;
8215
8216 thisEpWorld.vx += targetModule->m_world.vx;
8217 thisEpWorld.vy += targetModule->m_world.vy;
8218 thisEpWorld.vz += targetModule->m_world.vz;
8219
8220 marineStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
8221 marineStatusPointer->wanderData.worldPosition = thisEpWorld;
8222
8223 GLOBALASSERT(thisEp->alien_only==0);
8224 /* If that fired, GetNextModuleForLink went wrong. */
8225 } else {
8226 /* Failure case. */
8227 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
8228 }
8229
8230 } else {
8231 /* Another failure case. */
8232 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
8233 }
8234 }
8235
8236 /* if we still haven't got one, bimble about in this one for a bit. */
8237 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8238 {
8239 NPC_InitMovementData(&(marineStatusPointer->moveData));
8240 marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule;
8241 NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0);
8242 }
8243
8244 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) {
8245 /* STILL broken! Okay, just... wander, then. */
8246 return(SRC_Request_Wander);
8247 }
8248
8249 /* ok: should have a current target at this stage... */
8250 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
8251 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
8252
8253 /* test here for impeding collisions, and not being able to reach target... */
8254 #if ALL_NEW_AVOIDANCE
8255 {
8256 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
8257 /* Go to all new avoidance. */
8258 return(SRC_Request_Avoidance);
8259 }
8260 }
8261 #else
8262 {
8263 STRATEGYBLOCK *destructableObject = NULL;
8264 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
8265 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
8266 {
8267 /* go to avoidance */
8268 return(SRC_Request_Avoidance);
8269 }
8270 if(marineStatusPointer->obstruction.destructableObject)
8271 {
8272 LOCALASSERT(destructableObject);
8273 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
8274 }
8275 }
8276
8277 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
8278 {
8279 /* go to avoidance */
8280 /* no sequence change required */
8281
8282 marineStatusPointer->obstruction.environment=1;
8283 marineStatusPointer->obstruction.destructableObject=0;
8284 marineStatusPointer->obstruction.otherCharacter=0;
8285 marineStatusPointer->obstruction.anySingleObstruction=0;
8286
8287 return(SRC_Request_Avoidance);
8288 }
8289 #endif
8290
8291 return(SRC_No_Change);
8292 }
8293
8294 static STATE_RETURN_CONDITION Execute_MNS_Pathfinder(STRATEGYBLOCK *sbPtr)
8295 {
8296 MARINE_STATUS_BLOCK *marineStatusPointer;
8297 DYNAMICSBLOCK *dynPtr;
8298 AIMODULE *targetModule;
8299 VECTORCH velocityDirection = {0,0,0};
8300
8301 LOCALASSERT(sbPtr);
8302 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
8303 dynPtr = sbPtr->DynPtr;
8304 LOCALASSERT(marineStatusPointer);
8305 LOCALASSERT(dynPtr);
8306
8307 #if 0
8308 /* check if we should be crouched or standing up */
8309 if(marineStatusPointer->IAmCrouched)
8310 {
8311 /* curently crouched */
8312 if(!(MarineShouldBeCrawling(sbPtr)))
8313 {
8314 /* should be running*/
8315 marineStatusPointer->IAmCrouched = 0;
8316 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
8317 }
8318 }
8319 else
8320 {
8321 /* currently standing */
8322 if(MarineShouldBeCrawling(sbPtr))
8323 {
8324 /* should be crawling */
8325 marineStatusPointer->IAmCrouched = 1;
8326 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
8327 }
8328 }
8329 #else
8330 HandleMovingAnimations(sbPtr);
8331 #endif
8332
8333 /* should we change to approach state? */
8334 if(MarineIsAwareOfTarget(sbPtr))
8335 {
8336 /* doesn't require a sequence change */
8337 return(SRC_Request_Approach);
8338 }
8339
8340 if (marineStatusPointer->suspicious) {
8341 MODULE *targetModule;
8342 /* Are we allowed to check it out? */
8343 targetModule=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule);
8344 if (targetModule) {
8345 if (IsModuleVisibleFromModule(targetModule,sbPtr->containingModule)) {
8346 /* I suppose we'd better go, then. */
8347 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
8348 return(SRC_Request_Wait);
8349 } else {
8350 return(SRC_Request_Approach);
8351 }
8352 }
8353 }
8354 }
8355
8356 /* Ignore alerts. */
8357
8358 marineStatusPointer->stateTimer-=NormalFrameTime;
8359
8360 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8361 {
8362 NPC_InitMovementData(&(marineStatusPointer->moveData));
8363 }
8364 if ((marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8365 ||(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) {
8366
8367 FARENTRYPOINT *thisEp;
8368 int nextModuleIndex;
8369 /* Okay, so where are we exactly? */
8370
8371 if ((marineStatusPointer->stepnumber<0)||(marineStatusPointer->path<0)) {
8372 /* Get OUT! */
8373 return(SRC_Request_Wander);
8374 }
8375
8376 targetModule = TranslatePathIndex(marineStatusPointer->stepnumber,marineStatusPointer->path);
8377
8378 if (targetModule==NULL) {
8379 /* Oh, to heck with this. Try to wander. */
8380 return(SRC_Request_Wander);
8381 }
8382
8383 /* Right, so there is a somewhere to get to. */
8384
8385 if (targetModule!=sbPtr->containingModule->m_aimodule) {
8386 /* But we're nowhere near it. Geeze... */
8387 marineStatusPointer->missionmodule=targetModule;
8388 return(SRC_Request_Return);
8389 }
8390
8391 /* Okay, so now we need to know where to go now. */
8392
8393 nextModuleIndex=GetNextModuleInPath(marineStatusPointer->stepnumber,marineStatusPointer->path);
8394 GLOBALASSERT(nextModuleIndex>=0);
8395 /* If that fires, it's Richard's fault. */
8396 targetModule=TranslatePathIndex(nextModuleIndex,marineStatusPointer->path);
8397 GLOBALASSERT(targetModule);
8398 /* Ditto. */
8399 marineStatusPointer->stepnumber=nextModuleIndex;
8400
8401 thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
8402 if(thisEp) {
8403 /* aha. an ep!... */
8404 VECTORCH thisEpWorld = thisEp->position;
8405
8406 thisEpWorld.vx += targetModule->m_world.vx;
8407 thisEpWorld.vy += targetModule->m_world.vy;
8408 thisEpWorld.vz += targetModule->m_world.vz;
8409
8410 marineStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
8411 marineStatusPointer->wanderData.worldPosition = thisEpWorld;
8412 GLOBALASSERT(thisEp->alien_only==0);
8413 /* If that fired, the path goes through an alien-only link. */
8414
8415 } else {
8416 /* Failure case. */
8417 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
8418 }
8419
8420 }
8421
8422 /* if we still haven't got one, wander for a bit. */
8423 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
8424 {
8425 NPC_InitMovementData(&(marineStatusPointer->moveData));
8426 marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule;
8427 NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0);
8428 }
8429
8430 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) {
8431 /* STILL broken! Okay, just... wander forever, then. */
8432 return(SRC_Request_Wander);
8433 }
8434
8435 /* ok: should have a current target at this stage... */
8436 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
8437 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
8438
8439 /* test here for impeding collisions, and not being able to reach target... */
8440 #if ALL_NEW_AVOIDANCE
8441 {
8442 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
8443 /* Go to all new avoidance. */
8444 return(SRC_Request_Avoidance);
8445 }
8446 }
8447 #else
8448 {
8449 STRATEGYBLOCK *destructableObject = NULL;
8450 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
8451 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
8452 {
8453 /* go to avoidance */
8454 return(SRC_Request_Avoidance);
8455 }
8456 if(marineStatusPointer->obstruction.destructableObject)
8457 {
8458 LOCALASSERT(destructableObject);
8459 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
8460 }
8461 }
8462
8463 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
8464 {
8465 /* go to avoidance */
8466 /* no sequence change required */
8467
8468 marineStatusPointer->obstruction.environment=1;
8469 marineStatusPointer->obstruction.destructableObject=0;
8470 marineStatusPointer->obstruction.otherCharacter=0;
8471 marineStatusPointer->obstruction.anySingleObstruction=0;
8472
8473 return(SRC_Request_Avoidance);
8474 }
8475 #endif
8476
8477 return(SRC_No_Change);
8478 }
8479
8480 void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output) {
8481
8482 MODULE *my_module;
8483 VECTORCH alternate;
8484 int success;
8485
8486 /* Get a random position in the same module. */
8487
8488 my_module=sbPtr->containingModule;
8489 success=0;
8490
8491 while (success==0) {
8492
8493 do {
8494 output->vx=FastRandom()&65535;
8495 output->vx+=my_module->m_minx;
8496 } while (!( (output->vx>my_module->m_minx)&&(output->vx<my_module->m_maxx) ));
8497
8498 do {
8499 output->vz=FastRandom()&65535;
8500 output->vz+=my_module->m_minz;
8501 } while (!( (output->vz>my_module->m_minz)&&(output->vz<my_module->m_maxz) ));
8502
8503 output->vy=sbPtr->DynPtr->Position.vy;
8504 output->vy-=my_module->m_world.vy;
8505
8506 if (!( (output->vy>my_module->m_miny)&&(output->vy<my_module->m_maxy) )) {
8507 do {
8508 output->vy=FastRandom()&65535;
8509 output->vy+=my_module->m_miny;
8510 } while (!( (output->vy>my_module->m_miny)&&(output->vy<my_module->m_maxy) ));
8511 }
8512
8513 GLOBALASSERT(PointIsInModule(my_module,output));
8514
8515 output->vx+=my_module->m_world.vx;
8516 output->vy+=my_module->m_world.vy;
8517 output->vz+=my_module->m_world.vz;
8518
8519 /* Check for waypoints? */
8520
8521 if (my_module->m_waypoints) {
8522 if (GetPositionValidity(my_module,output,&alternate)==NULL) {
8523 /* Failure! */
8524 success=0;
8525 } else {
8526 if ( (alternate.vx!=output->vx)
8527 || (alternate.vy!=output->vy)
8528 || (alternate.vz!=output->vz) ) {
8529 *output=alternate;
8530 /* Success! */
8531 success=1;
8532 } else {
8533 /* Success! */
8534 success=1;
8535 }
8536 }
8537 } else {
8538 /* Success! */
8539 success=1;
8540 }
8541
8542 }
8543
8544 }
8545
8546 static void HandleFidgetAnimations(STRATEGYBLOCK *sbPtr) {
8547
8548 MARINE_STATUS_BLOCK *marineStatusPointer;
8549
8550 LOCALASSERT(sbPtr);
8551 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
8552 LOCALASSERT(marineStatusPointer);
8553
8554 /* A sub function for simplicity. */
8555
8556 if(marineStatusPointer->IAmCrouched) {
8557 /* No crouch fidget yet. */
8558 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrouch)
8559 ||(marineStatusPointer->HModelController.Sub_Sequence!=MCrSS_Standard)) {
8560 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
8561 }
8562 } else {
8563 /* Are we in some sort of fidget anim? */
8564 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)||(
8565 (marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Stand_To_Fidget)
8566 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Fidget_A)
8567 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Fidget_B)
8568 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Fidget_C)
8569 )) {
8570
8571 if ((marineStatusPointer->HModelController.Sequence_Type==HMSQT_MarineRun)
8572 &&(marineStatusPointer->HModelController.Sub_Sequence==MRSS_Mooch_Bored)) {
8573 /* Mooch bored does not require Stand_To_Fidget - go directly to Fidget_A. */
8574 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A)) {
8575 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_A,ONE_FIXED<<3,(ONE_FIXED>>3));
8576 marineStatusPointer->internalState=0;
8577 } else {
8578 /* No fidgets at all! */
8579 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
8580 }
8581 } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Stand_To_Fidget)) {
8582 /* Not in any kind of fidget anim: run Stand_To_Fidget if poss. */
8583 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Stand_To_Fidget,((ONE_FIXED*3)/2),(ONE_FIXED>>3));
8584 marineStatusPointer->HModelController.LoopAfterTweening=0;
8585 } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A)) {
8586 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_A,ONE_FIXED<<3,(ONE_FIXED>>3));
8587 } else {
8588 /* No fidgets at all! */
8589 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
8590 }
8591
8592 } else {
8593 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Stand_To_Fidget)) {
8594 /* We must have gone through StandToFidget, or at least be in it. */
8595 if (((marineStatusPointer->HModelController.Tweening==Controller_NoTweening)
8596 &&(marineStatusPointer->HModelController.sequence_timer==(ONE_FIXED-1))
8597 &&(marineStatusPointer->HModelController.Looped==0))
8598 ||((marineStatusPointer->HModelController.keyframe_flags)&&(marineStatusPointer->internalState))) {
8599 /* End of old sequence. */
8600 /* Go back to normal. */
8601 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_A)) {
8602 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_A,ONE_FIXED<<3,(ONE_FIXED>>3));
8603 marineStatusPointer->internalState=0;
8604 }
8605 } else if (marineStatusPointer->HModelController.keyframe_flags) {
8606 if ((FastRandom()&65535)<21846) {
8607 if ((FastRandom()&65535)<32767) {
8608 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_B)) {
8609 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_B,-1,(ONE_FIXED>>3));
8610 marineStatusPointer->HModelController.LoopAfterTweening=0;
8611 marineStatusPointer->internalState=1;
8612 } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_C)) {
8613 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_C,-1,(ONE_FIXED>>3));
8614 marineStatusPointer->HModelController.LoopAfterTweening=0;
8615 marineStatusPointer->internalState=2;
8616 }
8617 } else {
8618 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_C)) {
8619 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_C,-1,(ONE_FIXED>>3));
8620 marineStatusPointer->HModelController.LoopAfterTweening=0;
8621 marineStatusPointer->internalState=2;
8622 } else if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_Fidget_B)) {
8623 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Fidget_B,-1,(ONE_FIXED>>3));
8624 marineStatusPointer->HModelController.LoopAfterTweening=0;
8625 marineStatusPointer->internalState=1;
8626 }
8627 }
8628 }
8629 /* Else do nothing, I guess. */
8630 }
8631 } else {
8632 /* No stand to fidget. */
8633 }
8634 }
8635 }
8636
8637 }
8638
8639 static void HandleWaitingAnimations(STRATEGYBLOCK *sbPtr) {
8640
8641 MARINE_STATUS_BLOCK *marineStatusPointer;
8642 int tweeningtime;
8643
8644 LOCALASSERT(sbPtr);
8645 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
8646 LOCALASSERT(marineStatusPointer);
8647
8648 #if 0
8649 /* If you get here, you look stationary, so BE stationary! */
8650 sbPtr->DynPtr->LinVelocity.vx = 0;
8651 sbPtr->DynPtr->LinVelocity.vy = 0;
8652 sbPtr->DynPtr->LinVelocity.vz = 0;
8653 #endif
8654
8655 {
8656 DELTA_CONTROLLER *delta;
8657 /* There should be NO head turn delta. */
8658 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
8659 if (delta) {
8660 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
8661 }
8662 }
8663
8664 /* First test to see if we're in midair. */
8665 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Jump)) {
8666 if (!sbPtr->DynPtr->IsInContactWithFloor) {
8667 VECTORCH offset;
8668
8669 offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx;
8670 offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy;
8671 offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz;
8672
8673 if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) {
8674 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
8675 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Jump)) {
8676 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Jump,-1,(ONE_FIXED>>4));
8677 }
8678 }
8679 }
8680 }
8681
8682 /* Get a random tweening time... */
8683
8684 tweeningtime=((FastRandom()&65535)+32767)>>3;
8685
8686 /* Figure out what we should be playing, and do it. */
8687
8688 if (MarineShouldBeCrawling(sbPtr)) {
8689 marineStatusPointer->IAmCrouched=1;
8690 } else {
8691 marineStatusPointer->IAmCrouched=0;
8692 }
8693
8694 if(marineStatusPointer->IAmCrouched) {
8695 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrouch)
8696 ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) {
8697 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrouch,MCSS_Standard,ONE_FIXED,tweeningtime);
8698 }
8699 } else {
8700 if (marineStatusPointer->suspicious) {
8701 /* Go directly to wait alert, if you can. */
8702 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Wait_Alert)) {
8703 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
8704 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Wait_Alert)) {
8705 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Wait_Alert,(MUL_FIXED((ONE_FIXED<<2),((FastRandom()&32767)+65536))),tweeningtime);
8706 }
8707 } else {
8708 HandleFidgetAnimations(sbPtr);
8709 }
8710 } else {
8711 HandleFidgetAnimations(sbPtr);
8712 }
8713 }
8714 }
8715
8716 static void HandleMovingAnimations(STRATEGYBLOCK *sbPtr) {
8717
8718 MARINE_STATUS_BLOCK *marineStatusPointer;
8719 MARINE_MOVEMENT_STYLE style;
8720 MARINE_BHSTATE baseState;
8721 const MOVEMENT_DATA *movementData;
8722 VECTORCH offset;
8723 int can_mooch_bored;
8724 int can_mooch_alert;
8725 int can_sprint;
8726 int speed,animfactor;
8727
8728 LOCALASSERT(sbPtr);
8729 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
8730 LOCALASSERT(marineStatusPointer);
8731
8732 style=-1;
8733
8734 /* First test to see if we're in midair. */
8735 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_Jump)) {
8736 if (!sbPtr->DynPtr->IsInContactWithFloor) {
8737 VECTORCH offset;
8738
8739 offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx;
8740 offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy;
8741 offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz;
8742
8743 if ((offset.vx!=0)||(offset.vy!=0)||(offset.vz!=0)) {
8744 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
8745 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Jump)) {
8746 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Jump,-1,(ONE_FIXED>>4));
8747 }
8748 }
8749 }
8750 }
8751
8752 can_mooch_bored=HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Bored);
8753 can_mooch_alert=HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Mooch_Alert);
8754 can_sprint=HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_Sprint);
8755
8756 /* Figure out what we should be playing... */
8757
8758 if (marineStatusPointer->behaviourState==MBS_Avoidance) {
8759 baseState=marineStatusPointer->lastState;
8760 } else {
8761 baseState=marineStatusPointer->behaviourState;
8762 }
8763
8764 switch (baseState) {
8765 case MBS_Waiting:
8766 /* Why am I here? */
8767 style=MMS_Alert;
8768 break;
8769 case MBS_Wandering:
8770 style=MMS_Bored;
8771 break;
8772 case MBS_Retreating:
8773 style=MMS_Sprint;
8774 break;
8775 case MBS_Sentry:
8776 case MBS_Returning:
8777 case MBS_Pathfinding:
8778 if (marineStatusPointer->Target==NULL) {
8779 if (marineStatusPointer->suspicious) {
8780 style=MMS_Alert;
8781 } else {
8782 style=MMS_Bored;
8783 }
8784 } else {
8785 style=MMS_Combat;
8786 }
8787 case MBS_Approaching:
8788 case MBS_Responding:
8789 if (marineStatusPointer->Target==NULL) {
8790 style=MMS_Alert;
8791 } else {
8792 style=MMS_Combat;
8793 }
8794 break;
8795 case MBS_Firing:
8796 /* Shouldn't really be here. */
8797 style=MMS_Combat;
8798 break;
8799 case MBS_Avoidance:
8800 case MBS_Dying:
8801 /* Definitely shouldn't be here! */
8802 GLOBALASSERT(0);
8803 break;
8804 default:
8805 /* Shouldn't really be here. */
8806 style=MMS_Combat;
8807 break;
8808 }
8809
8810 /* Finally... */
8811 offset.vx=sbPtr->DynPtr->Position.vx-sbPtr->DynPtr->PrevPosition.vx;
8812 offset.vy=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy;
8813 offset.vz=sbPtr->DynPtr->Position.vz-sbPtr->DynPtr->PrevPosition.vz;
8814 {
8815 #if 0
8816 int dist;
8817 /* ...compute speed factor... */
8818 speed=Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity);
8819 dist=Approximate3dMagnitude(&offset);
8820 if (dist<(MUL_FIXED(NormalFrameTime,100))) {
8821 /* Not moving much, are we? */
8822 style=MMS_Stationary;
8823 }
8824 #else
8825 /* ...compute speed factor... */
8826 speed=Magnitude(&offset);
8827 if (speed<(MUL_FIXED(NormalFrameTime,50))) {
8828 /* Not moving much, are we? */
8829 style=MMS_Stationary;
8830 }
8831 speed=DIV_FIXED(speed,NormalFrameTime);
8832 #endif
8833 }
8834
8835 /* Fix crouching. */
8836 if(marineStatusPointer->IAmCrouched)
8837 {
8838 /* currently crouched */
8839 if(!(MarineShouldBeCrawling(sbPtr))) {
8840 marineStatusPointer->IAmCrouched=0;
8841 }
8842 } else {
8843 /* currently standing */
8844 if(MarineShouldBeCrawling(sbPtr)) {
8845 marineStatusPointer->IAmCrouched=1;
8846 }
8847 }
8848
8849 /* Now, pre-emptive reject of unavailable cases. */
8850 if (style==MMS_Bored) {
8851 if (!can_mooch_bored) {
8852 style=MMS_Combat;
8853 }
8854 }
8855
8856 if (style==MMS_Alert) {
8857 if (!can_mooch_alert) {
8858 style=MMS_Combat;
8859 }
8860 }
8861
8862 if (style==MMS_Sprint) {
8863 #if 1
8864 if (!can_sprint) {
8865 #else
8866 if (1) {
8867 #endif
8868 style=MMS_Combat;
8869 }
8870 }
8871
8872 if (speed==0) {
8873 style=MMS_Stationary;
8874 animfactor=ONE_FIXED;
8875 } else {
8876 animfactor=DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down...
8877 }
8878 GLOBALASSERT(animfactor>0);
8879
8880 /* ...and do it. */
8881 switch (style) {
8882
8883 case -1:
8884 /* Whoops! */
8885 GLOBALASSERT(0);
8886 break;
8887 case MMS_Stationary:
8888 {
8889 /* Ouch. */
8890 HandleWaitingAnimations(sbPtr);
8891 }
8892 break;
8893 case MMS_Bored:
8894 {
8895 if(marineStatusPointer->IAmCrouched) {
8896 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl)
8897 ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) {
8898 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4));
8899 }
8900
8901 if (marineStatusPointer->My_Weapon->ARealMarine) {
8902 movementData=GetThisMovementData(MDI_Marine_Combat);
8903 } else {
8904 movementData=GetThisMovementData(MDI_Civilian_Combat);
8905 }
8906 GLOBALASSERT(movementData);
8907 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
8908 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
8909
8910 } else {
8911 /* If we're here, we must be able to mooch bored. */
8912 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun)
8913 ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Mooch_Bored)) {
8914 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Bored,((ONE_FIXED*7)/5),(ONE_FIXED>>4));
8915 }
8916
8917 if (marineStatusPointer->My_Weapon->ARealMarine) {
8918 movementData=GetThisMovementData(MDI_Marine_Mooch_Bored);
8919 } else {
8920 movementData=GetThisMovementData(MDI_Civilian_Mooch_Bored);
8921 }
8922 GLOBALASSERT(movementData);
8923 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
8924 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
8925
8926 //marineStatusPointer->nearSpeed=MARINE_NEAR_SPEED>>2;
8927 }
8928 }
8929 break;
8930 case MMS_Alert:
8931 {
8932 if(marineStatusPointer->IAmCrouched) {
8933 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl)
8934 ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) {
8935 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4));
8936 }
8937
8938 if (marineStatusPointer->My_Weapon->ARealMarine) {
8939 movementData=GetThisMovementData(MDI_Marine_Combat);
8940 } else {
8941 movementData=GetThisMovementData(MDI_Civilian_Combat);
8942 }
8943 GLOBALASSERT(movementData);
8944 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
8945 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
8946 } else {
8947 /* If we're here, we must be able to mooch alert. */
8948 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun)
8949 ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Mooch_Alert)) {
8950 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Mooch_Alert,((ONE_FIXED*23)/10),(ONE_FIXED>>4));
8951 }
8952 if (marineStatusPointer->My_Weapon->ARealMarine) {
8953 movementData=GetThisMovementData(MDI_Marine_Mooch_Alert);
8954 } else {
8955 movementData=GetThisMovementData(MDI_Civilian_Mooch_Alert);
8956 }
8957 GLOBALASSERT(movementData);
8958 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
8959 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
8960 }
8961 }
8962 break;
8963 case MMS_Sprint:
8964 {
8965 if(marineStatusPointer->IAmCrouched) {
8966 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl)
8967 ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) {
8968 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4));
8969 }
8970 if (marineStatusPointer->My_Weapon->ARealMarine) {
8971 movementData=GetThisMovementData(MDI_Marine_Combat);
8972 } else {
8973 movementData=GetThisMovementData(MDI_Civilian_Combat);
8974 }
8975 GLOBALASSERT(movementData);
8976 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
8977 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
8978 } else {
8979 /* If we're here, we must be able to sprint. */
8980 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun)
8981 ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Sprint)) {
8982 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Sprint,((ONE_FIXED*7)/10),(ONE_FIXED>>4));
8983 }
8984 if (marineStatusPointer->My_Weapon->ARealMarine) {
8985 movementData=GetThisMovementData(MDI_Marine_Sprint);
8986 } else {
8987 movementData=GetThisMovementData(MDI_Civilian_Sprint);
8988 }
8989 GLOBALASSERT(movementData);
8990 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
8991 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
8992 }
8993 }
8994 break;
8995 case MMS_Combat:
8996 default:
8997 {
8998 if(marineStatusPointer->IAmCrouched) {
8999 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineCrawl)
9000 ||(marineStatusPointer->HModelController.Sub_Sequence!=MCSS_Standard)) {
9001 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCSS_Standard,ONE_FIXED,(ONE_FIXED>>4));
9002 }
9003 if (marineStatusPointer->My_Weapon->ARealMarine) {
9004 movementData=GetThisMovementData(MDI_Marine_Combat);
9005 } else {
9006 movementData=GetThisMovementData(MDI_Civilian_Combat);
9007 }
9008 GLOBALASSERT(movementData);
9009 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
9010 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
9011 } else {
9012 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineRun)
9013 ||(marineStatusPointer->HModelController.Sub_Sequence!=MRSS_Standard)) {
9014 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>4));
9015 }
9016 if (marineStatusPointer->My_Weapon->ARealMarine) {
9017 movementData=GetThisMovementData(MDI_Marine_Combat);
9018 } else {
9019 movementData=GetThisMovementData(MDI_Civilian_Combat);
9020 }
9021 GLOBALASSERT(movementData);
9022 marineStatusPointer->nearSpeed = MUL_FIXED(movementData->maxSpeed,marineStatusPointer->speedConstant);
9023 marineStatusPointer->acceleration = MUL_FIXED(movementData->acceleration,marineStatusPointer->accelerationConstant);
9024 }
9025 }
9026 break;
9027
9028 }
9029 if (marineStatusPointer->HModelController.Tweening==0) {
9030 HModel_SetToolsRelativeSpeed(&marineStatusPointer->HModelController,animfactor);
9031 }
9032
9033 /* Finally, civilians sprinting away look over their shoulders... */
9034 {
9035 int crs;
9036 DELTA_CONTROLLER *delta;
9037
9038 crs=0;
9039
9040 if (marineStatusPointer->My_Weapon->ARealMarine==0) {
9041 if (style==MMS_Sprint) {
9042 if (marineStatusPointer->IAmCrouched==0) {
9043 if (marineStatusPointer->behaviourState==MBS_Retreating) {
9044 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineRun,MRSS_SprintHeadDelta)) {
9045 crs=1;
9046 }
9047 }
9048 }
9049 }
9050 }
9051
9052 if (crs) {
9053 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
9054 if (!delta) {
9055 /* Add it. */
9056 delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta",(int)HMSQT_MarineRun,(int)MRSS_SprintHeadDelta,-1);
9057 GLOBALASSERT(delta);
9058 delta->Playing=0;
9059 delta->Looped=0;
9060 }
9061 /* Now we must have it... */
9062 if (delta->Playing==0) {
9063 if (marineStatusPointer->incidentFlag) {
9064 /* Start it. */
9065 Start_Delta_Sequence(delta,(int)HMSQT_MarineRun,(int)MRSS_SprintHeadDelta,-1);
9066 delta->Playing=1;
9067 }
9068 } else {
9069 if (DeltaAnimation_IsFinished(delta)) {
9070 delta->Playing=0;
9071 }
9072 }
9073 } else {
9074 /* There should be NO such delta. */
9075 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
9076 if (delta) {
9077 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
9078 }
9079 }
9080 }
9081 }
9082
9083 static STATE_RETURN_CONDITION Execute_MNS_SentryMode(STRATEGYBLOCK *sbPtr) {
9084
9085 MARINE_STATUS_BLOCK *marineStatusPointer;
9086 VECTORCH orientationDirn,offset,velocityDirection;
9087 int correctlyOrientated,range;
9088 int dist;
9089
9090 LOCALASSERT(sbPtr);
9091 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9092 LOCALASSERT(marineStatusPointer);
9093
9094 offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->my_spot.vx;
9095 offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->my_spot.vy;
9096 offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->my_spot.vz;
9097 /* Fix for midair start points, grrrr. */
9098 offset.vy>>=2;
9099
9100 /* Find distance off spot. */
9101 dist=Approximate3dMagnitude(&offset);
9102
9103 if ((dist<SENTRY_SENSITIVITY)&&(sbPtr->containingModule->m_aimodule==marineStatusPointer->missionmodule)) {
9104
9105 /* On the spot. */
9106
9107 /* zero velocity */
9108 LOCALASSERT(sbPtr->DynPtr);
9109 sbPtr->DynPtr->LinVelocity.vx = 0;
9110 sbPtr->DynPtr->LinVelocity.vy = 0;
9111 sbPtr->DynPtr->LinVelocity.vz = 0;
9112
9113 HandleWaitingAnimations(sbPtr);
9114
9115 correctlyOrientated=0;
9116
9117 if(MarineIsAwareOfTarget(sbPtr)) {
9118
9119 GLOBALASSERT(marineStatusPointer->Target);
9120 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
9121
9122 /* orientate to firing point first */
9123 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
9124 orientationDirn.vy = 0;
9125 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
9126 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
9127
9128 } else if (marineStatusPointer->suspicious) {
9129 /* Orientate to suspect point? */
9130 orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx;
9131 orientationDirn.vy = 0;
9132 orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz;
9133 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
9134
9135 if (correctlyOrientated) {
9136 /* Please don't be staring at a wall... */
9137 SECTION_DATA *head_sec;
9138 VECTORCH sight_vec;
9139
9140 head_sec=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head");
9141 GLOBALASSERT(head_sec);
9142
9143 sight_vec.vx=sbPtr->DynPtr->OrientMat.mat31;
9144 sight_vec.vy=sbPtr->DynPtr->OrientMat.mat32;
9145 sight_vec.vz=sbPtr->DynPtr->OrientMat.mat33;
9146
9147 FindPolygonInLineOfSight(&sight_vec,&head_sec->World_Offset,0,sbPtr->SBdptr);
9148 if (LOS_ObjectHitPtr) {
9149 if (SBIsEnvironment(LOS_ObjectHitPtr->ObStrategyBlock)) {
9150 if (LOS_Lambda<2000) {
9151 Marine_MirrorSuspectPoint(sbPtr);
9152 }
9153 }
9154 }
9155 }
9156 marineStatusPointer->gotapoint=0;
9157 } else {
9158 if (marineStatusPointer->gotapoint) {
9159 VECTORCH orientationDirn;
9160 int correctlyOrientated;
9161
9162 orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx;
9163 orientationDirn.vy = 0;
9164 orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz;
9165 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
9166 } else {
9167 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
9168 }
9169 }
9170
9171 if(!correctlyOrientated) {
9172
9173 return(SRC_No_Change);
9174
9175 }
9176
9177 if (marineStatusPointer->Target==NULL) {
9178 /* Must be suspicious? */
9179 if (marineStatusPointer->suspicious) {
9180 return(SRC_No_Change);
9181 }
9182 /* Else drop through? */
9183 } else {
9184 /* We have a target, and should be correctly orientated. */
9185
9186 if (MarineCanSeeTarget(sbPtr)) {
9187 /* I can see! */
9188 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
9189
9190 if ((marineStatusPointer->My_Weapon->MaxRange==-1) ||
9191 (range<marineStatusPointer->My_Weapon->MaxRange)) {
9192
9193 return(SRC_Request_Fire);
9194
9195 }
9196 } else {
9197 /* Eh? */
9198 if (marineStatusPointer->suspicious) {
9199 return(SRC_No_Change);
9200 }
9201 }
9202 }
9203
9204 /* Well, we're stuck with sentrymode. */
9205 if (marineStatusPointer->gotapoint) {
9206
9207 VECTORCH orientationDirn;
9208 int correctlyOrientated;
9209
9210 orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx;
9211 orientationDirn.vy = 0;
9212 orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz;
9213
9214 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
9215
9216 } else {
9217 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
9218 }
9219
9220 return(SRC_No_Change);
9221
9222 }
9223
9224 /* If you got here, you're lost. */
9225
9226 if (marineStatusPointer->missionmodule==NULL) {
9227 /* Fused! */
9228 return(SRC_No_Change);
9229 }
9230
9231 HandleMovingAnimations(sbPtr);
9232
9233 if (sbPtr->containingModule->m_aimodule!=marineStatusPointer->missionmodule) {
9234
9235 AIMODULE *targetModule;
9236 /* Not even in the same module! */
9237
9238 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
9239 {
9240 NPC_InitMovementData(&(marineStatusPointer->moveData));
9241 }
9242 if ((marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
9243 ||(marineStatusPointer->wanderData.currentModule!=sbPtr->containingModule->m_aimodule->m_index)) {
9244
9245 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->missionmodule,7,0);
9246
9247 if (targetModule) {
9248 FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
9249 if(thisEp) {
9250 /* aha. an ep!... */
9251 VECTORCH thisEpWorld = thisEp->position;
9252
9253 thisEpWorld.vx += targetModule->m_world.vx;
9254 thisEpWorld.vy += targetModule->m_world.vy;
9255 thisEpWorld.vz += targetModule->m_world.vz;
9256
9257 marineStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index;
9258 marineStatusPointer->wanderData.worldPosition = thisEpWorld;
9259
9260 GLOBALASSERT(thisEp->alien_only==0);
9261 /* If that fired, GetNextModuleForLink went wrong. */
9262
9263 } else {
9264 /* Failure case. */
9265 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
9266 }
9267
9268 } else {
9269 /* Another failure case. */
9270 marineStatusPointer->wanderData.currentModule=NPC_NOWANDERMODULE;
9271 }
9272 }
9273
9274 /* if we still haven't got one, bimble about in this one for a bit. */
9275 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE)
9276 {
9277 NPC_InitMovementData(&(marineStatusPointer->moveData));
9278 marineStatusPointer->moveData.lastModule=marineStatusPointer->lastmodule;
9279 NPC_FindAIWanderTarget(sbPtr,&(marineStatusPointer->wanderData),&(marineStatusPointer->moveData),0);
9280 }
9281
9282 if(marineStatusPointer->wanderData.currentModule==NPC_NOWANDERMODULE) {
9283 /* STILL broken! We're in a lot of trouble. */
9284 return(SRC_No_Change);
9285 }
9286
9287 /* Should have a legal target. */
9288 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
9289
9290 } else {
9291 /* Same module, wrong place. Just go for it. */
9292 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->my_spot),&marineStatusPointer->waypointManager);
9293
9294 }
9295
9296 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
9297
9298 /* test here for impeding collisions, and not being able to reach target... */
9299 #if ALL_NEW_AVOIDANCE
9300 {
9301 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
9302 /* Go to all new avoidance. */
9303 return(SRC_Request_Avoidance);
9304 }
9305 }
9306 #else
9307 {
9308 STRATEGYBLOCK *destructableObject = NULL;
9309 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
9310 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
9311 {
9312 /* go to avoidance */
9313 return(SRC_Request_Avoidance);
9314 }
9315 if(marineStatusPointer->obstruction.destructableObject)
9316 {
9317 LOCALASSERT(destructableObject);
9318 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
9319 }
9320 }
9321
9322 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
9323 {
9324 /* go to avoidance */
9325 /* no sequence change required */
9326
9327 marineStatusPointer->obstruction.environment=1;
9328 marineStatusPointer->obstruction.destructableObject=0;
9329 marineStatusPointer->obstruction.otherCharacter=0;
9330 marineStatusPointer->obstruction.anySingleObstruction=0;
9331
9332 return(SRC_Request_Avoidance);
9333 }
9334 #endif
9335
9336 return(SRC_No_Change);
9337
9338
9339 }
9340
9341 static STATE_RETURN_CONDITION Execute_MNS_Wait(STRATEGYBLOCK *sbPtr)
9342 {
9343 /* wait until near state timer runs out, then wander:
9344 alternatively, if we can attack the target, go straight to approach */
9345 MARINE_STATUS_BLOCK *marineStatusPointer;
9346 DYNAMICSBLOCK *dynPtr;
9347
9348 LOCALASSERT(sbPtr);
9349 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9350 dynPtr = sbPtr->DynPtr;
9351 LOCALASSERT(marineStatusPointer);
9352 LOCALASSERT(dynPtr);
9353
9354 /* zero velocity */
9355 LOCALASSERT(sbPtr->DynPtr);
9356 sbPtr->DynPtr->LinVelocity.vx = 0;
9357 sbPtr->DynPtr->LinVelocity.vy = 0;
9358 sbPtr->DynPtr->LinVelocity.vz = 0;
9359
9360 /* test for attack */
9361 if (MarineIsAwareOfTarget(sbPtr))
9362 {
9363 if ((FastRandom()&65535)<32767) {
9364 return(SRC_Request_Approach);
9365 } else {
9366 return(SRC_Request_Fire);
9367 }
9368 }
9369
9370 if (marineStatusPointer->suspicious) {
9371 int range;
9372
9373 #if 0
9374 range=VectorDistance(&marineStatusPointer->suspect_point,(&sbPtr->DynPtr->Position));
9375 #else
9376 VECTORCH targetPosition;
9377
9378 targetPosition=marineStatusPointer->suspect_point;
9379
9380 targetPosition.vx-=sbPtr->DynPtr->Position.vx;
9381 targetPosition.vy-=sbPtr->DynPtr->Position.vy;
9382 targetPosition.vz-=sbPtr->DynPtr->Position.vz;
9383
9384 /* Let's try doing this. */
9385 targetPosition.vy>>=2;
9386
9387 range=Approximate3dMagnitude(&targetPosition);
9388 #endif
9389
9390 if (range>SUSPECT_SENSITIVITY) {
9391 /* Too far away! */
9392 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
9393 /* Used to unset suspicion at that point. */
9394 return(SRC_Request_Approach);
9395 } else {
9396 /* We could at least turn to face it. */
9397 VECTORCH orientationDirn;
9398 int correctlyOrientated;
9399
9400 orientationDirn.vx = marineStatusPointer->suspect_point.vx - sbPtr->DynPtr->Position.vx;
9401 orientationDirn.vy = 0;
9402 orientationDirn.vz = marineStatusPointer->suspect_point.vz - sbPtr->DynPtr->Position.vz;
9403
9404 if (sbPtr->SBDamageBlock.IsOnFire) {
9405 /* Can't handle 'suspect points' stuck to them! */
9406 correctlyOrientated = 1;
9407 } else {
9408 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
9409 }
9410
9411 /* For when suspicion times out. */
9412 marineStatusPointer->gotapoint=0;
9413
9414 if (correctlyOrientated) {
9415 /* Please don't be staring at a wall... */
9416 SECTION_DATA *head_sec;
9417 VECTORCH sight_vec;
9418
9419 head_sec=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head");
9420 GLOBALASSERT(head_sec);
9421
9422 sight_vec.vx=sbPtr->DynPtr->OrientMat.mat31;
9423 sight_vec.vy=sbPtr->DynPtr->OrientMat.mat32;
9424 sight_vec.vz=sbPtr->DynPtr->OrientMat.mat33;
9425
9426 FindPolygonInLineOfSight(&sight_vec,&head_sec->World_Offset,0,sbPtr->SBdptr);
9427 if (LOS_ObjectHitPtr) {
9428 if (SBIsEnvironment(LOS_ObjectHitPtr->ObStrategyBlock)) {
9429 if (LOS_Lambda<2000) {
9430 Marine_MirrorSuspectPoint(sbPtr);
9431 }
9432 }
9433 }
9434 }
9435
9436 }
9437
9438 }
9439
9440 /* Think Sequences. */
9441
9442 HandleWaitingAnimations(sbPtr);
9443
9444 if ((NpcSquad.alertZone)&&(marineStatusPointer->Mission!=MM_LocalGuard)
9445 &&(marineStatusPointer->Mission!=MM_NonCom)) {
9446 /* Are we already there? */
9447 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
9448 if (NpcSquad.responseLevel>0) {
9449 /* Picked up a target. Can we move to respond? */
9450 AIMODULE *targetModule=0;
9451 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
9452 if (targetModule) {
9453 return(SRC_Request_Respond);
9454 }
9455 }
9456 }
9457 }
9458
9459 /* still waiting: decrement timer */
9460 marineStatusPointer->stateTimer-=NormalFrameTime;
9461
9462 if(marineStatusPointer->stateTimer<=0)
9463 {
9464
9465 /* Might want to wander. */
9466
9467 if ((FastRandom()&65535)<2048)
9468 {
9469 /* we should be wandering... we're bored of waiting. */
9470 return(SRC_Request_Wander);
9471 }
9472
9473 /* No, I'm happy waiting. */
9474 marineStatusPointer->stateTimer=MARINE_NEARWAITTIME;
9475 return(SRC_No_Change);
9476 }
9477
9478 /* Well, we're stuck with waiting. */
9479
9480 if (marineStatusPointer->suspicious) {
9481 /* Stay facing the suspect point. */
9482 return(SRC_No_Change);
9483 }
9484
9485 if (marineStatusPointer->gotapoint) {
9486
9487 VECTORCH orientationDirn;
9488 int correctlyOrientated;
9489
9490 orientationDirn.vx = marineStatusPointer->wanderData.worldPosition.vx - sbPtr->DynPtr->Position.vx;
9491 orientationDirn.vy = 0;
9492 orientationDirn.vz = marineStatusPointer->wanderData.worldPosition.vz - sbPtr->DynPtr->Position.vz;
9493
9494 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
9495
9496 } else {
9497 GetPointToFaceMarineTowards(sbPtr,&marineStatusPointer->wanderData.worldPosition);
9498 }
9499
9500 return(SRC_No_Change);
9501 }
9502
9503 /*----------------------- Patrick 16/6/97 ------------------------
9504 Special state for dying:
9505 NB once we have entered this state, we are locked into it until
9506 we are dead.
9507 ----------------------------------------------------------------*/
9508 static void Execute_Dying(STRATEGYBLOCK *sbPtr)
9509 {
9510 MARINE_STATUS_BLOCK *marineStatusPointer;
9511
9512 LOCALASSERT(sbPtr);
9513 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9514 LOCALASSERT(marineStatusPointer);
9515
9516 #if 0
9517 sbPtr->DynPtr->LinVelocity.vx = 0;
9518 sbPtr->DynPtr->LinVelocity.vy = 0;
9519 sbPtr->DynPtr->LinVelocity.vz = 0;
9520
9521 sbPtr->DynPtr->LinImpulse.vx = 0;
9522 sbPtr->DynPtr->LinImpulse.vy = 0;
9523 sbPtr->DynPtr->LinImpulse.vz = 0;
9524 #endif
9525
9526 {
9527 DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
9528 /* do we have a displayblock? */
9529 if (dispPtr)
9530 {
9531 dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
9532 dispPtr->ObFlags2 = marineStatusPointer->stateTimer/2;
9533
9534 }
9535 }
9536
9537 marineStatusPointer->stateTimer -= NormalFrameTime;
9538
9539 #if 0
9540 if ( (sbPtr->DynPtr->Position.vx=sbPtr->DynPtr->PrevPosition.vx)
9541 || (sbPtr->DynPtr->Position.vx=sbPtr->DynPtr->PrevPosition.vy)
9542 || (sbPtr->DynPtr->Position.vx=sbPtr->DynPtr->PrevPosition.vz)) {
9543
9544 /* Now, turn off collisions? */
9545 if(sbPtr->DynPtr)
9546 {
9547 sbPtr->DynPtr->IsStatic = 1;
9548 sbPtr->DynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS;
9549 sbPtr->DynPtr->GravityOn = 0;
9550 }
9551
9552 }
9553 #endif
9554
9555
9556 /* Did marine die with the trigger held down? */
9557 if (marineStatusPointer->lastroundhit==-2) {
9558 /* Is there a gunflash? */
9559 if(marineStatusPointer->My_Gunflash_Section) {
9560 /* But is it still attached? */
9561 if (marineStatusPointer->My_Gunflash_Section->my_controller==&(marineStatusPointer->HModelController)) {
9562 /* Keep firing! */
9563 LOCALASSERT(marineStatusPointer->My_Weapon->WeaponMisfireFunction);
9564 /* Shouldn't be doing this without knowing why. */
9565 (*marineStatusPointer->My_Weapon->WeaponMisfireFunction)(marineStatusPointer->My_Gunflash_Section,&marineStatusPointer->weapon_variable);
9566 }
9567 }
9568 }
9569
9570 /* Do we want to trim off the weapons? */
9571
9572 if (marineStatusPointer->HModelController.keyframe_flags) {
9573 SECTION *root;
9574
9575 root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName);
9576
9577 TrimToTemplate(sbPtr,&marineStatusPointer->HModelController,
9578 root, 1);
9579 }
9580
9581 }
9582
9583 static void MarineFireFlameThrower(STRATEGYBLOCK *sbPtr) {
9584
9585 VECTORCH null_vec;
9586 MARINE_STATUS_BLOCK *marineStatusPointer;
9587
9588 LOCALASSERT(sbPtr);
9589 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9590 LOCALASSERT(marineStatusPointer);
9591
9592 null_vec.vx=0;
9593 null_vec.vy=0;
9594 null_vec.vz=0;
9595
9596 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
9597
9598 FireFlameThrower(&marineStatusPointer->My_Gunflash_Section->World_Offset,&null_vec,
9599 &marineStatusPointer->My_Gunflash_Section->SecMat,0,&marineStatusPointer->weapon_variable);
9600
9601 }
9602
9603 void MarineMisfireFlameThrower(SECTION_DATA *muzzle, int *timer) {
9604
9605 VECTORCH null_vec;
9606
9607 null_vec.vx=0;
9608 null_vec.vy=0;
9609 null_vec.vz=0;
9610
9611 FireFlameThrower(&muzzle->World_Offset,&null_vec,&muzzle->SecMat,0,timer);
9612
9613 }
9614
9615 /*----------------------- Patrick 18/4/97 ------------------------
9616 Support for gunflash objects. These are for use by AI marines
9617 and also network ghosted players
9618 ----------------------------------------------------------------*/
9619
9620 /* this function is specifically for marines, and creates a gun flash
9621 pointing in the direction of the target point */
9622 static void CreateMarineGunFlash(STRATEGYBLOCK *sbPtr)
9623 {
9624 VECTORCH firingDirn,firingPoint;
9625 MARINE_STATUS_BLOCK *marineStatusPointer;
9626 int firingOffsetUp,firingOffsetInfront,firingOffsetAcross;
9627
9628 LOCALASSERT(sbPtr);
9629 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9630 LOCALASSERT(marineStatusPointer);
9631
9632 /* get the firing point offsets:*/
9633 if(marineStatusPointer->IAmCrouched)
9634 {
9635 firingOffsetUp = MARINE_FIRINGPOINT_UP;
9636 firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT;
9637 firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS;
9638 }
9639 else
9640 {
9641 firingOffsetUp = MARINE_FIRINGPOINT_UP_CROUCHED;
9642 firingOffsetInfront = MARINE_FIRINGPOINT_INFRONT_CROUCHED;
9643 firingOffsetAcross = MARINE_FIRINGPOINT_ACROSS_CROUCHED;
9644 }
9645
9646 /* find the firing direction */
9647 firingDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
9648 firingDirn.vy = marineStatusPointer->weaponTarget.vy - sbPtr->DynPtr->Position.vy;
9649 firingDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
9650 Normalise(&firingDirn);
9651 {
9652 VECTORCH yNormal = {0,-65536,0};
9653 VECTORCH tempDirn;
9654 VECTORCH acrossDirn;
9655
9656 /* now find firing point (conceptually, the end of the weapon muzzle)... */
9657 firingPoint = sbPtr->DynPtr->Position;
9658 firingPoint.vx += MUL_FIXED(firingDirn.vx,firingOffsetInfront);
9659 firingPoint.vz += MUL_FIXED(firingDirn.vz,firingOffsetInfront);
9660
9661 tempDirn = firingDirn;
9662 tempDirn.vy = 0;
9663 Normalise(&tempDirn);
9664 CrossProduct(&tempDirn,&yNormal,&acrossDirn);
9665 Normalise(&acrossDirn);
9666 firingPoint.vx += MUL_FIXED(tempDirn.vx,firingOffsetAcross);
9667 firingPoint.vz += MUL_FIXED(tempDirn.vz,firingOffsetAcross);
9668 firingPoint.vy += MUL_FIXED(yNormal.vy,firingOffsetUp);
9669 }
9670
9671
9672 LOCALASSERT(marineStatusPointer->myGunFlash==NULL);
9673 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
9674 marineStatusPointer->myGunFlash = AddNPCGunFlashEffect
9675 (
9676 &marineStatusPointer->My_Gunflash_Section->World_Offset,
9677 &marineStatusPointer->My_Gunflash_Section->SecMat,
9678 marineStatusPointer->My_Weapon->SfxID
9679 );
9680 }
9681
9682 /* Add a gun flash at the given position & orientation */
9683 DISPLAYBLOCK* AddNPCGunFlashEffect(VECTORCH *position, MATRIXCH* orientation, enum SFX_ID sfxID)
9684 {
9685 DISPLAYBLOCK *dPtr;
9686
9687 dPtr = CreateSFXObject(sfxID);
9688
9689 if(dPtr)
9690 {
9691 dPtr->ObMyModule = NULL;
9692 dPtr->ObWorld = *position;
9693 dPtr->ObMat = *orientation;
9694 //CreateEulerMatrix(orientation, &dPtr->ObMat);
9695 //TransposeMatrixCH(&dPtr->ObMat);
9696 AddLightingEffectToObject(dPtr,LFX_MUZZLEFLASH);
9697 GLOBALASSERT(dPtr->SfxPtr);
9698 dPtr->SfxPtr->EffectDrawnLastFrame=0;
9699 }
9700 return dPtr;
9701 }
9702
9703 /* Remove the gunflash */
9704 void RemoveNPCGunFlashEffect(DISPLAYBLOCK* dPtr)
9705 {
9706 DestroyActiveObject(dPtr);
9707 }
9708
9709 /* Update the gunflash effect given a new position and orientation */
9710 void MaintainNPCGunFlashEffect(DISPLAYBLOCK* dPtr, VECTORCH *position, MATRIXCH* orientation)
9711 {
9712 dPtr->ObWorld = *position;
9713 dPtr->ObMat = *orientation;
9714
9715 /* oh, oh, and re-add the lighting effect */
9716 AddLightingEffectToObject(dPtr,LFX_MUZZLEFLASH);
9717 }
9718
9719
9720
9721 /* Patrick: 2/7/97 --------------------------------------------------------
9722 Some marine support functions
9723 -------------------------------------------------------------------------*/
9724 static void SetMarineAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening)
9725 {
9726
9727 MARINE_STATUS_BLOCK *marineStatusPointer;
9728
9729 LOCALASSERT(sbPtr);
9730 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9731 LOCALASSERT(marineStatusPointer);
9732
9733 GLOBALASSERT(length!=0);
9734
9735 if (tweening<=0) {
9736 InitHModelSequence(&marineStatusPointer->HModelController,(int)type,subtype,length);
9737 } else {
9738 InitHModelTweening(&marineStatusPointer->HModelController, tweening, (int)type,subtype,length, 1);
9739 }
9740
9741 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
9742 }
9743
9744 static void SetMarineAnimationSequence_Null(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening) {
9745 /* Ha! */
9746 #if (NEW_ANIM_SYSTEM==0)
9747 SetMarineAnimationSequence(sbPtr,type,subtype,length,tweening);
9748 #endif
9749
9750 }
9751
9752 static int MarineCanSeeTarget(STRATEGYBLOCK *sbPtr)
9753 {
9754 MARINE_STATUS_BLOCK *marineStatusPointer;
9755 int targetIsCloaked,targetTaunted;
9756 VECTORCH offset;
9757 int dist;
9758 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9759
9760 LOCALASSERT(sbPtr);
9761 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9762 LOCALASSERT(marineStatusPointer);
9763
9764 if (marineStatusPointer->Target==NULL) {
9765 /* You can't see nothin. */
9766 return(0);
9767 }
9768
9769 targetIsCloaked=0;
9770 targetTaunted=0;
9771
9772 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
9773 /* test for player being cloaked */
9774 LOCALASSERT(playerStatusPtr);
9775 if (AvP.PlayerType==I_Predator) {
9776
9777 if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) {
9778 targetIsCloaked=1;
9779 }
9780 }
9781 if (playerStatusPtr->tauntTimer) {
9782 /* Idiot. */
9783 targetIsCloaked=0;
9784 /* On the other hand, */
9785 targetTaunted=1;
9786 }
9787
9788 } else {
9789 /* Test for NPC predators being cloaked, or aliens hiding? */
9790 if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) {
9791 PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr;
9792 GLOBALASSERT(predStatus);
9793 if (predStatus->CloakStatus==PCLOAK_On) {
9794 targetIsCloaked=1;
9795 }
9796 }
9797 }
9798
9799 offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->Position.vx;
9800 offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->Position.vy;
9801 offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->Position.vz;
9802 dist=Approximate3dMagnitude(&offset);
9803
9804 /* If a marine is suspicious, and the target is within 2m of the suspect_point... */
9805 if (marineStatusPointer->suspicious) {
9806 /* Detect on the incidentFlag? */
9807 if (marineStatusPointer->incidentFlag) {
9808 int dice,targetnum;
9809
9810 dice=(FastRandom()&65535);
9811 targetnum=(marineStatusPointer->Skill);
9812
9813 targetnum=MakeModifiedTargetNum(targetnum,dist);
9814
9815 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
9816 if (AvP.PlayerType==I_Predator) {
9817 if (playerStatusPtr->cloakOn==1) {
9818 dice=MUL_FIXED(dice,playerStatusPtr->CloakingEffectiveness);
9819 }
9820 }
9821 } else if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) {
9822 PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr;
9823 GLOBALASSERT(predStatus);
9824 if (predStatus->CloakStatus==PCLOAK_On) {
9825 dice=MUL_FIXED(dice,predStatus->CloakingEffectiveness);
9826 }
9827 }
9828
9829 if (dice<targetnum) {
9830 targetIsCloaked=0;
9831 }
9832 }
9833 if (dist<MARINE_AUTODETECT_RANGE) {
9834 /* Too close to fool anyone. */
9835 targetIsCloaked=0;
9836 }
9837 }
9838
9839 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
9840 /* Alien test is now here, since it uses probability differently. */
9841 if (AvP.PlayerType==I_Alien) {
9842 if (!AlienPCIsCurrentlyVisible(marineStatusPointer->incidentFlag,sbPtr)) {
9843 if (playerStatusPtr->tauntTimer) {
9844 /* Idiot. */
9845 targetIsCloaked=0;
9846 /* Taunted flag should already be set. */
9847 } else {
9848 targetIsCloaked=1;
9849 }
9850 }
9851 }
9852 }
9853
9854 if (marineStatusPointer->sawlastframe) {
9855 if (marineStatusPointer->incidentFlag) {
9856 /* Chance of losing target. */
9857 VECTORCH offset;
9858 int speed;
9859
9860 offset.vx=marineStatusPointer->Target->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->PrevPosition.vx;
9861 offset.vy=marineStatusPointer->Target->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->PrevPosition.vy;
9862 offset.vz=marineStatusPointer->Target->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->PrevPosition.vz;
9863
9864 /* ...compute speed factor... */
9865 speed=Magnitude(&offset);
9866 speed=DIV_FIXED(speed,NormalFrameTime);
9867
9868 if (speed>50) {
9869 /* The faster you move, the more likely to be lost. */
9870 speed<<=1;
9871 if ((FastRandom()&65535)>speed) {
9872 /* Retain target! */
9873 targetIsCloaked=0;
9874 }
9875 } else {
9876 /* Can't lose them if they're still. */
9877 targetIsCloaked=0;
9878 }
9879 } else {
9880 targetIsCloaked=0;
9881 }
9882 }
9883
9884 if (marineStatusPointer->Target->SBDamageBlock.IsOnFire) {
9885 /* Oh come ON. */
9886 targetIsCloaked=0;
9887 }
9888
9889 if(!(NPCCanSeeTarget(sbPtr,marineStatusPointer->Target, MARINE_NEAR_VIEW_WIDTH))) {
9890 if (marineStatusPointer->sawlastframe) {
9891 marineStatusPointer->sawlastframe=2;
9892 /* I'm suspicious now. */
9893 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
9894 marineStatusPointer->suspect_point=marineStatusPointer->Target->DynPtr->Position;
9895 /* And unset previous_suspicion. */
9896 marineStatusPointer->previous_suspicion=0;
9897 marineStatusPointer->using_squad_suspicion=0;
9898 }
9899 return(0);
9900 }
9901
9902 if (targetIsCloaked) {
9903 return(0);
9904 }
9905 marineStatusPointer->sawlastframe=1;
9906
9907 if ((targetTaunted)&&(marineStatusPointer->Target)&&(marineStatusPointer->Android==0)) {
9908
9909 if (dist<16834) {
9910 dist=16384-dist;
9911 dist<<=2;
9912 marineStatusPointer->Courage-=MUL_FIXED((NormalFrameTime<<1),dist);
9913 }
9914 }
9915 return(1);
9916 }
9917
9918 static int MarineCanSeeObject(STRATEGYBLOCK *sbPtr,STRATEGYBLOCK *target)
9919 {
9920 MARINE_STATUS_BLOCK *marineStatusPointer;
9921 int targetIsCloaked, targetTaunted, targetWasCloaked;
9922 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
9923 VECTORCH offset;
9924 int dist;
9925
9926 LOCALASSERT(sbPtr);
9927 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
9928 LOCALASSERT(marineStatusPointer);
9929
9930 if (target==NULL) {
9931 /* You can't see nothin. */
9932 return(0);
9933 }
9934
9935 targetIsCloaked=0;
9936 targetTaunted=0;
9937 targetWasCloaked=0;
9938
9939 if (target==Player->ObStrategyBlock) {
9940 /* test for player being cloaked */
9941 LOCALASSERT(playerStatusPtr);
9942 if (AvP.PlayerType==I_Predator) {
9943
9944 if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) {
9945 targetIsCloaked=1;
9946 targetWasCloaked=1;
9947 }
9948 }
9949 if (playerStatusPtr->tauntTimer) {
9950 /* Idiot. */
9951 targetIsCloaked=0;
9952 /* On the other hand, */
9953 targetTaunted=1;
9954 }
9955
9956 } else {
9957 /* Test for NPC predators being cloaked, or aliens hiding? */
9958 if (target->I_SBtype==I_BehaviourPredator) {
9959 PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)target->SBdataptr;
9960 GLOBALASSERT(predStatus);
9961 if (predStatus->CloakStatus==PCLOAK_On) {
9962 targetIsCloaked=1;
9963 targetWasCloaked=1;
9964 }
9965 }
9966 }
9967
9968 offset.vx=sbPtr->DynPtr->Position.vx-target->DynPtr->Position.vx;
9969 offset.vy=sbPtr->DynPtr->Position.vy-target->DynPtr->Position.vy;
9970 offset.vz=sbPtr->DynPtr->Position.vz-target->DynPtr->Position.vz;
9971 dist=Approximate3dMagnitude(&offset);
9972
9973 /* If a marine is suspicious, and the target is within 2m of the suspect_point... */
9974 if (marineStatusPointer->suspicious) {
9975 /* Detect on the incidentFlag? */
9976 if (marineStatusPointer->incidentFlag) {
9977 int dice,targetnum;
9978
9979 dice=(FastRandom()&65535);
9980 targetnum=(marineStatusPointer->Skill);
9981
9982 targetnum=MakeModifiedTargetNum(targetnum,dist);
9983
9984 if (target==Player->ObStrategyBlock) {
9985 if (AvP.PlayerType==I_Predator) {
9986 if (playerStatusPtr->cloakOn==1) {
9987 dice=MUL_FIXED(dice,playerStatusPtr->CloakingEffectiveness);
9988 }
9989 }
9990 } else if (target->I_SBtype==I_BehaviourPredator) {
9991 PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)target->SBdataptr;
9992 GLOBALASSERT(predStatus);
9993 if (predStatus->CloakStatus==PCLOAK_On) {
9994 dice=MUL_FIXED(dice,predStatus->CloakingEffectiveness);
9995 }
9996 }
9997
9998 if (dice<targetnum) {
9999 targetIsCloaked=0;
10000 }
10001 }
10002 if (dist<MARINE_AUTODETECT_RANGE) {
10003 /* Too close to fool anyone. */
10004 targetIsCloaked=0;
10005 }
10006 }
10007
10008 if (target==Player->ObStrategyBlock) {
10009 /* Alien test is now here, since it uses probability differently. */
10010 if (AvP.PlayerType==I_Alien) {
10011 if (!AlienPCIsCurrentlyVisible(marineStatusPointer->incidentFlag,sbPtr)) {
10012 if (playerStatusPtr->tauntTimer) {
10013 /* Idiot. */
10014 targetIsCloaked=0;
10015 /* Taunted flag should already be set. */
10016 } else {
10017 targetIsCloaked=1;
10018 targetWasCloaked=1;
10019 }
10020 }
10021 }
10022 }
10023
10024 if (marineStatusPointer->sawlastframe) {
10025 if (marineStatusPointer->incidentFlag) {
10026 /* Chance of losing target. */
10027 VECTORCH offset;
10028 int speed;
10029
10030 offset.vx=target->DynPtr->Position.vx-target->DynPtr->PrevPosition.vx;
10031 offset.vy=target->DynPtr->Position.vy-target->DynPtr->PrevPosition.vy;
10032 offset.vz=target->DynPtr->Position.vz-target->DynPtr->PrevPosition.vz;
10033
10034 /* ...compute speed factor... */
10035 speed=Magnitude(&offset);
10036 speed=DIV_FIXED(speed,NormalFrameTime);
10037
10038 if (speed>50) {
10039 /* The faster you move, the more likely to be lost. */
10040 speed<<=1;
10041 if ((FastRandom()&65535)>speed) {
10042 /* Retain target! */
10043 targetIsCloaked=0;
10044 }
10045 } else {
10046 /* Can't lose them if they're still. */
10047 targetIsCloaked=0;
10048 }
10049 } else {
10050 targetIsCloaked=0;
10051 }
10052 }
10053
10054 if (target->SBDamageBlock.IsOnFire) {
10055 /* Oh come ON. */
10056 targetIsCloaked=0;
10057 }
10058
10059 /* NO saw last frame usage! */
10060
10061 if (targetIsCloaked) {
10062 return(0);
10063 }
10064
10065 if(!(NPCCanSeeTarget(sbPtr,target, MARINE_NEAR_VIEW_WIDTH))) {
10066 return(0);
10067 }
10068
10069 if ((targetWasCloaked)&&(marineStatusPointer->Target==NULL)) {
10070 /* Exhibit suprise? */
10071 if ((FastRandom()&65535)<16384) {
10072 Marine_SurpriseSound(sbPtr);
10073 }
10074 }
10075
10076 if ((targetTaunted)&&(marineStatusPointer->Target)&&(marineStatusPointer->Android==0)) {
10077 /* It must be the player. */
10078 if (dist<16834) {
10079 dist=16384-dist;
10080 dist<<=2;
10081 marineStatusPointer->Courage-=MUL_FIXED((NormalFrameTime<<1),dist);
10082 }
10083 }
10084 return(1);
10085 }
10086
10087 void WarnMarineOfAttack(STRATEGYBLOCK *marine,STRATEGYBLOCK *attacker) {
10088
10089 MARINE_STATUS_BLOCK *marineStatusPointer;
10090
10091 GLOBALASSERT(marine);
10092
10093 GLOBALASSERT(marine->I_SBtype==I_BehaviourMarine);
10094
10095 marineStatusPointer = (MARINE_STATUS_BLOCK *)(marine->SBdataptr);
10096 GLOBALASSERT(marineStatusPointer);
10097
10098 GLOBALASSERT(attacker);
10099
10100 /* Test? */
10101
10102 if(MarineCanSeeObject(marine,attacker)) {
10103
10104 /* Remember your suspicion! */
10105 marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious;
10106 marineStatusPointer->suspicious=1; /* It's right there! */
10107 marineStatusPointer->Target=attacker;
10108
10109 COPY_NAME(marineStatusPointer->Target_SBname,marineStatusPointer->Target->SBname);
10110
10111 PointAlert(2,&attacker->DynPtr->Position);
10112 }
10113
10114 }
10115
10116 static int MarineIsAwareOfTarget(STRATEGYBLOCK *sbPtr)
10117 {
10118 MARINE_STATUS_BLOCK *marineStatusPointer;
10119 int targetIsCloaked;
10120 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
10121 VECTORCH offset;
10122 int dist;
10123
10124 /* Like MarineCanSeeTarget, but the 'Far' version: should it hunt? */
10125
10126 LOCALASSERT(sbPtr);
10127 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
10128 LOCALASSERT(marineStatusPointer);
10129
10130 if (marineStatusPointer->Target!=NULL) {
10131
10132 /* Okay, let's try this sense malarky. */
10133
10134 /* Motion tracker, only when scanning. */
10135
10136 if (marineStatusPointer->mtracker_timer==0) {
10137 if (marineStatusPointer->Target->DynPtr) {
10138 DYNAMICSBLOCK *tDynPtr;
10139 MATRIXCH WtoL;
10140 VECTORCH offset;
10141 /* Arc reject. */
10142
10143 tDynPtr=marineStatusPointer->Target->DynPtr;
10144
10145 offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->Position.vx;
10146 offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->Position.vy;
10147 offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->Position.vz;
10148
10149 WtoL=sbPtr->DynPtr->OrientMat;
10150 TransposeMatrixCH(&WtoL);
10151 RotateVector(&offset,&WtoL);
10152
10153 if (offset.vz<=0) {
10154 #if 0
10155 if (
10156 (tDynPtr->Position.vx!=tDynPtr->PrevPosition.vx)
10157 ||(tDynPtr->Position.vx!=tDynPtr->PrevPosition.vx)
10158 ||(tDynPtr->Position.vx!=tDynPtr->PrevPosition.vx)
10159 ) {
10160 #else
10161 if (ObjectShouldAppearOnMotionTracker(marineStatusPointer->Target)) {
10162 #endif
10163 int range;
10164
10165 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
10166
10167 if (range<=MOTIONTRACKER_RANGE) {
10168 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME; /* It might be there. */
10169 marineStatusPointer->suspect_point=marineStatusPointer->Target->DynPtr->Position;
10170 /* Set this to zero when you get a *new* suspicion. */
10171 marineStatusPointer->previous_suspicion=0;
10172 marineStatusPointer->using_squad_suspicion=0;
10173 tracker_noise=2; /* Wheep! */
10174 return(1);
10175 }
10176 }
10177 }
10178 }
10179 }
10180
10181 /* So, there's nothing on the scanner. */
10182
10183 targetIsCloaked=0;
10184
10185 /* Far visibility. */
10186
10187 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
10188 /* test for player being cloaked */
10189 LOCALASSERT(playerStatusPtr);
10190 if (AvP.PlayerType==I_Predator) {
10191
10192 if((playerStatusPtr->cloakOn==1)&&(playerStatusPtr->cloakPositionGivenAway==0)) {
10193 targetIsCloaked=1;
10194 }
10195 }
10196 if (playerStatusPtr->tauntTimer) {
10197 /* Idiot. */
10198 targetIsCloaked=0;
10199 }
10200
10201 } else {
10202 /* Test for NPC predators being cloaked, or aliens hiding? */
10203 if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) {
10204 PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr;
10205 GLOBALASSERT(predStatus);
10206 if (predStatus->CloakStatus==PCLOAK_On) {
10207 targetIsCloaked=1;
10208 }
10209 }
10210 }
10211
10212 offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->Position.vx;
10213 offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->Position.vy;
10214 offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->Position.vz;
10215 dist=Approximate3dMagnitude(&offset);
10216
10217 /* If a marine is suspicious, and the target is within 2m of the suspect_point... */
10218 if (marineStatusPointer->suspicious) {
10219 /* Detect on the incidentFlag? */
10220 if (marineStatusPointer->incidentFlag) {
10221 int dice,targetnum;
10222
10223 dice=(FastRandom()&65535);
10224 targetnum=(marineStatusPointer->Skill);
10225
10226 targetnum=MakeModifiedTargetNum(targetnum,dist);
10227
10228 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
10229 if (AvP.PlayerType==I_Predator) {
10230 if (playerStatusPtr->cloakOn==1) {
10231 dice=MUL_FIXED(dice,playerStatusPtr->CloakingEffectiveness);
10232 }
10233 }
10234 } else if (marineStatusPointer->Target->I_SBtype==I_BehaviourPredator) {
10235 PREDATOR_STATUS_BLOCK *predStatus=(PREDATOR_STATUS_BLOCK *)marineStatusPointer->Target->SBdataptr;
10236 GLOBALASSERT(predStatus);
10237 if (predStatus->CloakStatus==PCLOAK_On) {
10238 dice=MUL_FIXED(dice,predStatus->CloakingEffectiveness);
10239 }
10240 }
10241
10242 if (dice<targetnum) {
10243 targetIsCloaked=0;
10244 }
10245 }
10246 if (dist<MARINE_AUTODETECT_RANGE) {
10247 /* Too close to fool anyone. */
10248 targetIsCloaked=0;
10249 }
10250 }
10251
10252 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
10253 /* Alien test is now here, since it uses probability differently. */
10254 if (AvP.PlayerType==I_Alien) {
10255 if (!AlienPCIsCurrentlyVisible(marineStatusPointer->incidentFlag,sbPtr)) {
10256 if (playerStatusPtr->tauntTimer) {
10257 /* Idiot. */
10258 targetIsCloaked=0;
10259 } else {
10260 targetIsCloaked=1;
10261 }
10262 }
10263 }
10264 }
10265
10266 if (marineStatusPointer->sawlastframe) {
10267 if (marineStatusPointer->incidentFlag) {
10268 /* Chance of losing target. */
10269 VECTORCH offset;
10270 int speed;
10271
10272 offset.vx=marineStatusPointer->Target->DynPtr->Position.vx-marineStatusPointer->Target->DynPtr->PrevPosition.vx;
10273 offset.vy=marineStatusPointer->Target->DynPtr->Position.vy-marineStatusPointer->Target->DynPtr->PrevPosition.vy;
10274 offset.vz=marineStatusPointer->Target->DynPtr->Position.vz-marineStatusPointer->Target->DynPtr->PrevPosition.vz;
10275
10276 /* ...compute speed factor... */
10277 speed=Magnitude(&offset);
10278 speed=DIV_FIXED(speed,NormalFrameTime);
10279
10280 if (speed>50) {
10281 /* The faster you move, the more likely to be lost. */
10282 speed<<=1;
10283 if ((FastRandom()&65535)>speed) {
10284 /* Retain target! */
10285 targetIsCloaked=0;
10286 }
10287 } else {
10288 /* Can't lose them if they're still. */
10289 targetIsCloaked=0;
10290 }
10291 } else {
10292 targetIsCloaked=0;
10293 }
10294 }
10295
10296 if (marineStatusPointer->Target->SBDamageBlock.IsOnFire) {
10297 /* Oh come ON. */
10298 targetIsCloaked=0;
10299 }
10300
10301 if (targetIsCloaked==0) {
10302 if (!sbPtr->SBdptr) {
10303 if (marineStatusPointer->Target->containingModule) {
10304 if (IsModuleVisibleFromModule(marineStatusPointer->Target->containingModule,sbPtr->containingModule)) {
10305 /* Remember your suspicion! */
10306 marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious;
10307 /* Seen, unset suspicion. */
10308 marineStatusPointer->suspicious=1;
10309 return(1);
10310 }
10311 }
10312 } else {
10313 if (MarineCanSeeTarget(sbPtr)) {
10314 /* Remember your suspicion! */
10315 marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious;
10316 /* Near visibility - seen target, unset suspicion. */
10317 marineStatusPointer->suspicious=1;
10318 return(1);
10319 }
10320 }
10321 }
10322 }
10323
10324 /* Lastly, is there something we want to investigate? */
10325
10326 if (marineStatusPointer->suspicious) {
10327 if (!sbPtr->SBdptr) {
10328 MODULE *targetModule;
10329 /* Far case. */
10330 targetModule=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule);
10331 /* Target isn't guaranteed, is it? */
10332 if (targetModule) {
10333 if (IsModuleVisibleFromModule(targetModule,sbPtr->containingModule)) {
10334 /* Seen the point, unset suspicion? Maybe not. */
10335 #if 0
10336 /* Remember your suspicion! */
10337 marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious;
10338 marineStatusPointer->suspicious=1;
10339 /* Just let it time out instead. */
10340 #endif
10341 /* Shouldn't have a target now. */
10342 marineStatusPointer->Target=NULL;
10343 return(0);
10344 /* If there was something there, we should have picked it up by now. */
10345 }
10346 }
10347 /* Still suspicious. */
10348 } else {
10349 /* Near case. */
10350 VECTORCH offset;
10351 MATRIXCH WtoL;
10352 /* Arc reject. */
10353
10354 offset.vx=sbPtr->DynPtr->Position.vx-marineStatusPointer->suspect_point.vx;
10355 offset.vy=sbPtr->DynPtr->Position.vy-marineStatusPointer->suspect_point.vy;
10356 offset.vz=sbPtr->DynPtr->Position.vz-marineStatusPointer->suspect_point.vz;
10357
10358 WtoL=sbPtr->DynPtr->OrientMat;
10359 TransposeMatrixCH(&WtoL);
10360 RotateVector(&offset,&WtoL);
10361 /* Do reject. */
10362 if (MarineSight_FrustrumReject(sbPtr,&offset,NULL)) {
10363 if (IsThisObjectVisibleFromThisPosition(sbPtr->SBdptr,&marineStatusPointer->suspect_point,NPC_MAX_VIEWRANGE)) {
10364 /* I know what you're going to say. That's backwards. */
10365 #if 0
10366 /* Remember your suspicion! */
10367 marineStatusPointer->previous_suspicion=marineStatusPointer->suspicious;
10368 marineStatusPointer->suspicious=1; /* Flag for unsetting nicely. */
10369 /* Now, let's try just timing it out. */
10370 #endif
10371 /* By this point I would have thought there's no valid target. */
10372 marineStatusPointer->Target=NULL;
10373 return(0);
10374 /* Well, show me 'IsThisPositionVisibleFromThisObject' and I'll be happy to change it. */
10375 }
10376 }
10377 }
10378 }
10379
10380 return(0);
10381 }
10382
10383 static int MarineShouldBeCrawling(STRATEGYBLOCK *sbPtr)
10384 {
10385 if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) return 1;
10386 return 0;
10387 }
10388
10389 static STATE_RETURN_CONDITION Execute_MNS_DischargeFlamethrower(STRATEGYBLOCK *sbPtr)
10390 {
10391 MARINE_STATUS_BLOCK *marineStatusPointer;
10392 VECTORCH orientationDirn;
10393 int correctlyOrientated;
10394
10395 LOCALASSERT(sbPtr);
10396 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
10397 LOCALASSERT(marineStatusPointer);
10398
10399 marineStatusPointer->HModelController.Playing=1;
10400
10401 /* zero velocity */
10402 LOCALASSERT(sbPtr->DynPtr);
10403 sbPtr->DynPtr->LinVelocity.vx = 0;
10404 sbPtr->DynPtr->LinVelocity.vy = 0;
10405 sbPtr->DynPtr->LinVelocity.vz = 0;
10406
10407 /* look after the gun flash */
10408 if(marineStatusPointer->myGunFlash) {
10409 /* No gunflash, neither. */
10410 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
10411 }
10412
10413 /* first of all, validate this state: if the target suddenly becomes cloaked, then
10414 we should switch immediately to wait state*/
10415 if(!MarineCanSeeTarget(sbPtr))
10416 {
10417
10418 /* .... and stop the sound */
10419 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10420 Sound_Stop(marineStatusPointer->soundHandle);
10421 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10422 }
10423 return(SRC_Request_Wait);
10424 }
10425
10426 GLOBALASSERT(marineStatusPointer->Target);
10427 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
10428 /* Fix weapon target! */
10429 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
10430 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
10431 marineStatusPointer->My_Weapon->TargetCallibrationShift);
10432 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
10433 marineStatusPointer->My_Weapon->TargetCallibrationShift);
10434 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
10435 marineStatusPointer->My_Weapon->TargetCallibrationShift);
10436 }
10437
10438 /* Here we must have a target. Renew suspicion for new arrivals. */
10439 if (NpcSquad.Squad_Suspicion==0) {
10440 PointAlert(2,&marineStatusPointer->weaponTarget);
10441 }
10442
10443 /* Are we out of range? */
10444 {
10445 int range;
10446
10447 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
10448
10449 if ((marineStatusPointer->My_Weapon->MaxRange!=-1) &&
10450 (range>=marineStatusPointer->My_Weapon->MaxRange)) {
10451
10452 /* .... and stop the sound */
10453 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10454 Sound_Stop(marineStatusPointer->soundHandle);
10455 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10456 }
10457 return(SRC_Request_Approach);
10458
10459 }
10460 }
10461
10462 /* orientate to firing point first */
10463 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
10464 orientationDirn.vy = 0;
10465 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
10466 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
10467
10468 /* I have a cunning plan... */
10469 {
10470 DELTA_CONTROLLER *delta;
10471
10472 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
10473 if (delta) {
10474 if (!(DeltaAnimation_IsFinished(delta))) {
10475 correctlyOrientated=0;
10476 }
10477 }
10478 }
10479
10480 /* we are not correctly orientated to the target: this could happen because we have
10481 just entered this state, or the target has moved during firing*/
10482
10483 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
10484
10485 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10486 Sound_Stop(marineStatusPointer->soundHandle);
10487 }
10488 return(SRC_No_Change);
10489 }
10490
10491 if (marineStatusPointer->clipammo==0) {
10492 return(SRC_Request_Reload);
10493 }
10494
10495 /* at this point we are correctly orientated: if we have no gunflash yet,
10496 and our state timer is set to marine_near_firetime then we have either
10497 just started firing, or have become dis-orienated between bursts. This is a good
10498 time to consider firing a grenade... */
10499
10500 /* No grenades with FT. */
10501
10502 /* look after the sound */
10503 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
10504 else
10505 {
10506 /* SID_INCIN_LOOP? */
10507 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
10508 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
10509 }
10510
10511 marineStatusPointer->stateTimer -= NormalFrameTime;
10512
10513 MarineFireFlameThrower(sbPtr);
10514
10515 /* Lighting? */
10516 if (sbPtr->SBdptr) {
10517 AddLightingEffectToObject(sbPtr->SBdptr,LFX_MUZZLEFLASH);
10518 }
10519
10520 if (marineStatusPointer->clipammo>0) {
10521 marineStatusPointer->clipammo-=NormalFrameTime;
10522 if (marineStatusPointer->clipammo<0) {
10523 marineStatusPointer->clipammo=0;
10524 }
10525 }
10526
10527 if(marineStatusPointer->stateTimer > 0) return(SRC_No_Change);
10528
10529
10530 {
10531 /* we are far enough away, so return to approach */
10532
10533 /* ... and remove the gunflash */
10534 if(marineStatusPointer->myGunFlash)
10535 {
10536 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
10537 marineStatusPointer->myGunFlash = NULL;
10538 }
10539
10540 /* .... and stop the sound */
10541 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10542 Sound_Stop(marineStatusPointer->soundHandle);
10543 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10544 }
10545 return(SRC_Request_Approach);
10546 }
10547 }
10548
10549 static void DischargeLOSWeapon_Core(STRATEGYBLOCK *sbPtr)
10550 {
10551 MARINE_STATUS_BLOCK *marineStatusPointer;
10552 VECTORCH relPos,relPos2;
10553 int mod,hitroll,range,volleytime,volleyrounds;
10554
10555 LOCALASSERT(sbPtr);
10556 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
10557 LOCALASSERT(marineStatusPointer);
10558
10559 /* Snipped from DischargeLOSWeapon. */
10560
10561 if (marineStatusPointer->Target) {
10562 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
10563 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
10564 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
10565
10566 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
10567 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
10568 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
10569
10570 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
10571 } else {
10572 /* Just a number. */
10573 range=10000;
10574 }
10575
10576 /* look after the gun flash */
10577 if(marineStatusPointer->myGunFlash) {
10578 MaintainMarineGunFlash(sbPtr);
10579 } else {
10580 CreateMarineGunFlash(sbPtr);
10581 }
10582
10583 /* look after the sound */
10584 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
10585 else
10586 {
10587 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
10588 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
10589 }
10590
10591 marineStatusPointer->stateTimer -= NormalFrameTime;
10592
10593 /* Volleysize is now rounds fired this state. */
10594
10595 volleytime=marineStatusPointer->My_Weapon->FiringTime-marineStatusPointer->stateTimer;
10596 /* It was that or reverse the state timer for this state. */
10597 volleyrounds=MUL_FIXED(volleytime,marineStatusPointer->My_Weapon->FiringRate);
10598 volleyrounds>>=ONE_FIXED_SHIFT;
10599
10600 volleyrounds-=marineStatusPointer->volleySize;
10601 marineStatusPointer->volleySize+=volleyrounds;
10602
10603 LOCALASSERT(volleyrounds>=0);
10604
10605 if (marineStatusPointer->clipammo!=-1) {
10606 /* We're counting ammo. */
10607 if (volleyrounds>marineStatusPointer->clipammo) {
10608 volleyrounds=marineStatusPointer->clipammo;
10609 }
10610 marineStatusPointer->clipammo-=volleyrounds;
10611 LOCALASSERT(marineStatusPointer->clipammo>=0);
10612 }
10613
10614 marineStatusPointer->roundsForThisTarget+=volleyrounds;
10615
10616 /* Now hit the target with volleyrounds bullets. */
10617
10618 mod=SpeedRangeMods(&relPos,&relPos2);
10619
10620 hitroll=marineStatusPointer->Skill; /* Marine skill... */
10621 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
10622 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
10623 LOCALASSERT(playerStatusPtr);
10624 if ( (AvP.PlayerType==I_Alien)
10625 ||((AvP.PlayerType==I_Predator)&&(playerStatusPtr->cloakOn==1))) {
10626 /* Vs the player, lighting effects on aliens and cloaked preds. */
10627 hitroll=MUL_FIXED(hitroll,((CurrentLightAtPlayer>>1)+32767));
10628 }
10629 }
10630 hitroll-=mod;
10631 hitroll+=marineStatusPointer->My_Weapon->Accuracy;
10632
10633 /* Here we go... */
10634 {
10635 #define SUSTAINMOD (ONE_FIXED>>3)
10636 int a,hits;
10637
10638 hits=0;
10639
10640 for (a=0; a<volleyrounds; a++) {
10641
10642 int realhitroll;
10643
10644 if (marineStatusPointer->lastroundhit) {
10645 realhitroll=hitroll+SUSTAINMOD;
10646 } else {
10647 realhitroll=hitroll;
10648 }
10649
10650 if (marineStatusPointer->Target) {
10651 if (marineStatusPointer->lasthitsection) {
10652 /* Verify this section is valid? */
10653 HMODELCONTROLLER *tctrl=NULL;
10654
10655 if (marineStatusPointer->Target->SBdptr) {
10656 tctrl=marineStatusPointer->Target->SBdptr->HModelControlBlock;
10657 }
10658
10659 if ((marineStatusPointer->lasthitsection->flags§ion_data_notreal)
10660 || (marineStatusPointer->lasthitsection->flags§ion_data_terminate_here)
10661 || ( (tctrl!=NULL)&&(tctrl!=marineStatusPointer->lasthitsection->my_controller)) ) {
10662 /* Invalid. */
10663 marineStatusPointer->lasthitsection=NULL;
10664 }
10665 }
10666
10667 if ( (marineStatusPointer->lastroundhit==0)||(marineStatusPointer->lasthitsection==NULL)) {
10668 marineStatusPointer->lasthitsection=HitLocationRoll(marineStatusPointer->Target,sbPtr);
10669 }
10670 }
10671
10672 if ((FastRandom()&65535)<realhitroll) {
10673 hits++;
10674 marineStatusPointer->lastroundhit=1;
10675 } else {
10676 marineStatusPointer->lastroundhit=0;
10677 }
10678
10679 if (marineStatusPointer->Target==NULL) {
10680 hits=0;
10681 }
10682 }
10683
10684 /* Handle Damage. */
10685 {
10686 VECTORCH attack_dir,rel_pos;
10687 VECTORCH shotvector;
10688
10689 shotvector.vx=0;
10690 shotvector.vy=0;
10691 shotvector.vz=65535;
10692 RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat);
10693
10694 /* DO DAMAGE TO TARGET HERE */
10695 #if MARINE_STATE_PRINT
10696 textprint("Hits = %d\n",hits);
10697 #endif
10698
10699 if (hits!=0) {
10700
10701 int range2;
10702
10703 GLOBALASSERT(marineStatusPointer->Target);
10704
10705 rel_pos.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
10706 rel_pos.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
10707 rel_pos.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
10708 range2=Approximate3dMagnitude(&rel_pos);
10709
10710 if (VerifyHitShot(sbPtr,marineStatusPointer->Target,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, hits,range2)) {
10711 /* If 0, hits have been dealt with. */
10712 GetDirectionOfAttack(marineStatusPointer->Target,&rel_pos,&attack_dir);
10713
10714 if (marineStatusPointer->lasthitsection) {
10715 CauseDamageToHModel(marineStatusPointer->lasthitsection->my_controller, marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED*hits, marineStatusPointer->lasthitsection,&attack_dir,NULL,0);
10716 } else {
10717 CauseDamageToObject(marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED*hits,&attack_dir);
10718 }
10719 }
10720
10721 }
10722
10723 if ((volleyrounds-hits)>0) {
10724 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
10725
10726 if (marineStatusPointer->Target) {
10727 ProjectNPCShot(sbPtr, marineStatusPointer->Target, &marineStatusPointer->My_Gunflash_Section->World_Offset,&marineStatusPointer->My_Gunflash_Section->SecMat, marineStatusPointer->My_Weapon->Ammo_Type, (volleyrounds-hits));
10728 } else {
10729 /* Like a miss, so it's inaccurate. */
10730 CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, volleyrounds,1);
10731 }
10732 }
10733
10734 }
10735
10736 }
10737
10738 }
10739
10740 static STATE_RETURN_CONDITION Execute_MNS_DischargeLOSWeapon(STRATEGYBLOCK *sbPtr)
10741 {
10742 MARINE_STATUS_BLOCK *marineStatusPointer;
10743 VECTORCH orientationDirn,relPos,relPos2;
10744 int correctlyOrientated,range;
10745
10746 LOCALASSERT(sbPtr);
10747 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
10748 LOCALASSERT(marineStatusPointer);
10749
10750 marineStatusPointer->HModelController.Playing=1;
10751
10752 #if MARINE_STATE_PRINT
10753 textprint("Marine firing... ");
10754 #endif
10755
10756 /* zero velocity */
10757 LOCALASSERT(sbPtr->DynPtr);
10758 sbPtr->DynPtr->LinVelocity.vx = 0;
10759 sbPtr->DynPtr->LinVelocity.vy = 0;
10760 sbPtr->DynPtr->LinVelocity.vz = 0;
10761
10762 /* first of all, validate this state: if the target suddenly becomes cloaked, then
10763 we should switch immediately to wait state*/
10764 if (marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize) {
10765 /* Keep firing! */
10766 } else {
10767 if(!MarineCanSeeTarget(sbPtr))
10768 {
10769 #if 1
10770 EndMarineMuzzleFlash(sbPtr);
10771 #else
10772 /* ... and remove the gunflash */
10773 if(marineStatusPointer->myGunFlash)
10774 {
10775 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
10776 marineStatusPointer->myGunFlash = NULL;
10777 }
10778
10779 /* .... and stop the sound */
10780 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10781 Sound_Stop(marineStatusPointer->soundHandle);
10782 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10783 }
10784 #endif
10785
10786 #if MARINE_STATE_PRINT
10787 textprint("Returning no target.\n");
10788 #endif
10789 marineStatusPointer->lastroundhit=0;
10790 marineStatusPointer->lasthitsection=NULL;
10791 return(SRC_Request_Wait);
10792 }
10793 }
10794
10795 if (marineStatusPointer->clipammo==0) {
10796 /* Reload here. */
10797 EndMarineMuzzleFlash(sbPtr);
10798 return(SRC_Request_Reload);
10799 }
10800
10801
10802 if (marineStatusPointer->Target) {
10803 GLOBALASSERT(marineStatusPointer->Target);
10804 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
10805 /* Fix weapon target! */
10806 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
10807 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
10808 marineStatusPointer->My_Weapon->TargetCallibrationShift);
10809 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
10810 marineStatusPointer->My_Weapon->TargetCallibrationShift);
10811 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
10812 marineStatusPointer->My_Weapon->TargetCallibrationShift);
10813 }
10814
10815 /* Here we must have a target. Renew suspicion for new arrivals. */
10816 if (NpcSquad.Squad_Suspicion==0) {
10817 PointAlert(2,&marineStatusPointer->weaponTarget);
10818 }
10819 }
10820 /* Otherwise, stay facing the same way. */
10821
10822 /* orientate to firing point first */
10823 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
10824 orientationDirn.vy = 0;
10825 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
10826 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
10827
10828 /* I have a cunning plan... */
10829 {
10830 DELTA_CONTROLLER *delta;
10831
10832 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
10833 if (delta) {
10834 if (!(DeltaAnimation_IsFinished(delta))) {
10835 correctlyOrientated=0;
10836 }
10837 }
10838 }
10839 /* I have another cunning plan... */
10840 if ((marineStatusPointer->volleySize>0)&&
10841 (marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize)) {
10842 correctlyOrientated=1;
10843 }
10844
10845
10846 /* we are not correctly orientated to the target: this could happen because we have
10847 just entered this state, or the target has moved during firing*/
10848 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
10849
10850 /* stop visual and audio cues: technically, we're not firing at this moment */
10851 #if 1
10852 EndMarineMuzzleFlash(sbPtr);
10853 #else
10854 if(marineStatusPointer->myGunFlash)
10855 {
10856 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
10857 marineStatusPointer->myGunFlash = NULL;
10858 }
10859
10860 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10861 Sound_Stop(marineStatusPointer->soundHandle);
10862 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10863 }
10864 #endif
10865
10866 #if MARINE_STATE_PRINT
10867 textprint("Turning to face.\n");
10868 #endif
10869 marineStatusPointer->lastroundhit=0;
10870 marineStatusPointer->lasthitsection=NULL;
10871 return(SRC_No_Change);
10872 }
10873
10874 if (marineStatusPointer->Target) {
10875 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
10876 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
10877 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
10878
10879 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
10880 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
10881 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
10882
10883 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
10884 }
10885
10886 /* Test for grenading! */
10887 if ((marineStatusPointer->myGunFlash==NULL)&&(marineStatusPointer->stateTimer == MARINE_NEAR_FIRE_TIME)
10888 &&(marineStatusPointer->Target))
10889 {
10890
10891 /* NB don't fire grenades in air ducts */
10892 if ((FastRandom()&MARINE_CHANCEOFGRENADE) == 0) {
10893 if (!(marineStatusPointer->IAmCrouched)) {
10894 if (range > MARINE_TOO_CLOSE_TO_GRENADE_FOOL) {
10895 if (marineStatusPointer->My_Weapon->EnableGrenades) {
10896
10897 GLOBALASSERT(marineStatusPointer->Target);
10898 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
10899 LobAGrenade(sbPtr);
10900 marineStatusPointer->stateTimer = MARINE_NEAR_TIMEBETWEENFIRING;
10901 marineStatusPointer->volleySize = 0;
10902
10903
10904 #if MARINE_STATE_PRINT
10905 textprint("fired a grenade.\n");
10906 #endif
10907
10908 return(SRC_Request_Approach);
10909 }
10910 }
10911 }
10912 }
10913 }
10914
10915 DischargeLOSWeapon_Core(sbPtr);
10916
10917 if (marineStatusPointer->Target==NULL) {
10918 /* Getting out of here! */
10919 return(SRC_No_Change);
10920 }
10921
10922 /* Did we get him? */
10923 if ((NPC_IsDead(marineStatusPointer->Target))
10924 &&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) {
10925 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
10926 if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) {
10927 /* Huzzah! */
10928 #if 1
10929 EndMarineMuzzleFlash(sbPtr);
10930 #else
10931 if(marineStatusPointer->myGunFlash)
10932 {
10933 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
10934 marineStatusPointer->myGunFlash = NULL;
10935 }
10936 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10937 Sound_Stop(marineStatusPointer->soundHandle);
10938 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10939 }
10940 #endif
10941 marineStatusPointer->lastroundhit=0;
10942 marineStatusPointer->lasthitsection=NULL;
10943 return(SRC_Request_Taunt);
10944 }
10945 }
10946 }
10947
10948 if(marineStatusPointer->stateTimer > 0) {
10949 #if MARINE_STATE_PRINT
10950 textprint("Returning continue at range %d.\n",range);
10951 #endif
10952 return(SRC_No_Change);
10953 }
10954
10955 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
10956 {
10957 /* renew firing, as we are still too close to approach */
10958 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
10959 marineStatusPointer->volleySize = 0;
10960 GLOBALASSERT(marineStatusPointer->Target);
10961 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
10962 #if MARINE_STATE_PRINT
10963 textprint("Returning too close renewal at range %d.\n",range);
10964 #endif
10965 #if 1
10966 /* stop visual and audio cues: technically, we're not firing at this moment */
10967 #if 1
10968 EndMarineMuzzleFlash(sbPtr);
10969 #else
10970 if(marineStatusPointer->myGunFlash)
10971 {
10972 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
10973 marineStatusPointer->myGunFlash = NULL;
10974 }
10975
10976 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
10977 Sound_Stop(marineStatusPointer->soundHandle);
10978 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
10979 }
10980 #endif
10981 #endif
10982
10983 if (marineStatusPointer->Android==0) {
10984 marineStatusPointer->Courage-=(ONE_FIXED>>3);
10985 }
10986 return(SRC_Request_Fire);
10987 }
10988 else
10989 {
10990 /* we are far enough away, so return to approach */
10991
10992 #if 1
10993 /* ... and remove the gunflash */
10994 #if 1
10995 EndMarineMuzzleFlash(sbPtr);
10996 #else
10997 if(marineStatusPointer->myGunFlash)
10998 {
10999 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
11000 marineStatusPointer->myGunFlash = NULL;
11001 }
11002 /* .... and stop the sound */
11003 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
11004 Sound_Stop(marineStatusPointer->soundHandle);
11005 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
11006 }
11007 #endif
11008 #endif
11009
11010 #if MARINE_STATE_PRINT
11011 textprint("Returning too far termination at range %d.\n",range);
11012 #endif
11013 return(SRC_Request_Approach);
11014 }
11015 return(SRC_No_Change);
11016 }
11017
11018 int SpeedRangeMods(VECTORCH *range,VECTORCH *speed) {
11019
11020 int dot,theta,sinthet,rmod;
11021 int magrange,magspeed;
11022
11023 /* Should return between 0 and ONE_FIXED... */
11024
11025 magrange=Approximate3dMagnitude(range);
11026 rmod=magrange>>2;
11027
11028 magspeed=Approximate3dMagnitude(speed);
11029 dot=DotProduct(range,speed);
11030 if (dot<0) dot=-dot;
11031 {
11032 int ab=MUL_FIXED(magrange,magspeed);
11033 ab<<=1;
11034
11035 if (ab==0) dot=0; else dot=DIV_FIXED(dot,ab);
11036
11037 if (dot>ONE_FIXED) {
11038 dot=ONE_FIXED;
11039 /* Well, I suppose it could happen. */
11040 /* Accuracy errors... */
11041 LOCALASSERT(dot<=ONE_FIXED);
11042 }
11043
11044 theta=ArcCos(dot);
11045 sinthet=GetSin(theta);
11046
11047 dot=WideMulNarrowDiv(sinthet,magspeed,magrange);
11048
11049 }
11050 dot<<=3;
11051
11052 return(dot+rmod);
11053
11054 }
11055
11056 int Validate_Target(STRATEGYBLOCK *target,char *SBname) {
11057 /* General purpose function. */
11058
11059 if (target==NULL) return(0);
11060
11061 if (target==Player->ObStrategyBlock) {
11062 if (Observer) {
11063 return(0);
11064 }
11065 }
11066
11067 if (!NAME_ISEQUAL(target->SBname,SBname)) {
11068 return(0);
11069 } else {
11070 if (NPC_IsDead(target)) {
11071 return(0);
11072 } else {
11073 return(1);
11074 }
11075 }
11076 }
11077
11078 int Validate_Strategy(STRATEGYBLOCK *target,char *SBname) {
11079 /* General purpose function Too. */
11080
11081 if (target==NULL) return(0);
11082
11083 if (target==Player->ObStrategyBlock) {
11084 if (Observer) {
11085 return(0);
11086 }
11087 }
11088
11089 if (!NAME_ISEQUAL(target->SBname,SBname)) {
11090 return(0);
11091 } else {
11092 return(1);
11093 }
11094 }
11095
11096 int Marine_TargetFilter(STRATEGYBLOCK *candidate) {
11097
11098 switch (candidate->I_SBtype) {
11099 case I_BehaviourMarinePlayer:
11100 case I_BehaviourAlienPlayer:
11101 case I_BehaviourPredatorPlayer:
11102 {
11103 if (Observer) {
11104 return(0);
11105 }
11106
11107 switch(AvP.PlayerType)
11108 {
11109 case I_Alien:
11110 case I_Predator:
11111 return(1);
11112 break;
11113 case I_Marine:
11114 return(0);
11115 break;
11116 default:
11117 GLOBALASSERT(0);
11118 return(0);
11119 break;
11120 }
11121 break;
11122 }
11123 case I_BehaviourDummy:
11124 {
11125 DUMMY_STATUS_BLOCK *dummyStatusPointer;
11126 dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr);
11127 LOCALASSERT(dummyStatusPointer);
11128 switch (dummyStatusPointer->PlayerType) {
11129 case I_Alien:
11130 case I_Predator:
11131 return(1);
11132 break;
11133 case I_Marine:
11134 return(0);
11135 break;
11136 default:
11137 GLOBALASSERT(0);
11138 return(0);
11139 break;
11140 }
11141 break;
11142 }
11143 case I_BehaviourAlien:
11144 {
11145 ALIEN_STATUS_BLOCK *alienStatusPointer;
11146 LOCALASSERT(candidate);
11147 LOCALASSERT(candidate->DynPtr);
11148
11149 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr);
11150
11151 if (NPC_IsDead(candidate)) {
11152 return(0);
11153 } else {
11154 if ((alienStatusPointer->BehaviourState==ABS_Dormant)||
11155 (alienStatusPointer->BehaviourState==ABS_Awakening)) {
11156 return(0);
11157 } else {
11158 return(1);
11159 }
11160 }
11161 break;
11162 }
11163 case I_BehaviourQueenAlien:
11164 case I_BehaviourFaceHugger:
11165 case I_BehaviourPredator:
11166 case I_BehaviourXenoborg:
11167 case I_BehaviourSeal:
11168 case I_BehaviourPredatorAlien:
11169 /* Valid. */
11170 return(1);
11171 break;
11172 case I_BehaviourMarine:
11173 #if ANARCHY
11174 return(1);
11175 #else
11176 return(0);
11177 #endif
11178 break;
11179 case I_BehaviourNetGhost:
11180 {
11181 NETGHOSTDATABLOCK *dataptr;
11182 dataptr=candidate->SBdataptr;
11183 switch (dataptr->type) {
11184 case I_BehaviourMarinePlayer:
11185 case I_BehaviourAlienPlayer:
11186 case I_BehaviourPredatorPlayer:
11187 //return(1);
11188 return(0);
11189 break;
11190 default:
11191 return(0);
11192 break;
11193 }
11194 }
11195 break;
11196 default:
11197 return(0);
11198 break;
11199 }
11200
11201 }
11202
11203
11204 STRATEGYBLOCK *Marine_GetNewTarget(VECTORCH *marinepos, STRATEGYBLOCK *me) {
11205
11206 int neardist, newblip;
11207 STRATEGYBLOCK *nearest;
11208 #if 1
11209 int a;
11210 STRATEGYBLOCK *candidate;
11211 #endif
11212 MODULE *dmod;
11213 MARINE_STATUS_BLOCK *marineStatusPointer;
11214 int dist;
11215 VECTORCH offset;
11216
11217 LOCALASSERT(me);
11218 marineStatusPointer = (MARINE_STATUS_BLOCK *)(me->SBdataptr);
11219 LOCALASSERT(marineStatusPointer);
11220
11221 dmod=ModuleFromPosition(marinepos,playerPherModule);
11222
11223 LOCALASSERT(dmod);
11224
11225 nearest=NULL;
11226 neardist=ONE_FIXED;
11227 newblip=0;
11228
11229 //#if ANARCHY
11230 #if 1
11231 for (a=0; a<NumActiveStBlocks; a++) {
11232 candidate=ActiveStBlockList[a];
11233
11234 if (candidate!=me) {
11235 if (candidate->DynPtr) {
11236 /* Arc reject. */
11237 MATRIXCH WtoL;
11238
11239 offset.vx=marinepos->vx-candidate->DynPtr->Position.vx;
11240 offset.vy=marinepos->vy-candidate->DynPtr->Position.vy;
11241 offset.vz=marinepos->vz-candidate->DynPtr->Position.vz;
11242
11243 WtoL=me->DynPtr->OrientMat;
11244 TransposeMatrixCH(&WtoL);
11245 RotateVector(&offset,&WtoL);
11246
11247 if (offset.vz<=0) {
11248
11249 /* It'll wheep, anyway. */
11250 if (marineStatusPointer->mtracker_timer==0) {
11251 #if 0
11252 if (
11253 (candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11254 ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11255 ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11256 ) {
11257 #else
11258 if (ObjectShouldAppearOnMotionTracker(candidate)) {
11259 #endif
11260
11261 dist=Approximate3dMagnitude(&offset);
11262 if (dist<MOTIONTRACKER_RANGE) {
11263 tracker_noise=2;
11264 }
11265 }
11266 }
11267
11268 if (Marine_TargetFilter(candidate)) {
11269
11270 dist=Approximate3dMagnitude(&offset);
11271
11272 if (dist<neardist) {
11273 /* Check visibility? */
11274 if ((candidate->SBdptr)&&(me->SBdptr)) {
11275 /* Near case. */
11276 if ((!NPC_IsDead(candidate))
11277 ||(candidate->I_SBtype==I_BehaviourMarinePlayer)
11278 ||(candidate->I_SBtype==I_BehaviourDummy)) {
11279 if ((MarineCanSeeObject(me,candidate))) {
11280 nearest=candidate;
11281 neardist=dist;
11282 }
11283 }
11284 } else {
11285 if ((!NPC_IsDead(candidate))
11286 ||(candidate->I_SBtype==I_BehaviourMarinePlayer)
11287 ||(candidate->I_SBtype==I_BehaviourDummy)) {
11288 if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) {
11289 nearest=candidate;
11290 neardist=dist;
11291 }
11292 }
11293 }
11294
11295 if (marineStatusPointer->mtracker_timer==0) {
11296 /* Hey, the tracker's on. */
11297 if (dist<MOTIONTRACKER_RANGE) {
11298 #if 0
11299 if (
11300 (candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11301 ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11302 ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11303 ) {
11304 #else
11305 if (ObjectShouldAppearOnMotionTracker(candidate)) {
11306 #endif
11307 newblip=1;
11308 marineStatusPointer->suspect_point=candidate->DynPtr->Position;
11309 /* Set this to zero when you get a *new* suspicion. */
11310 marineStatusPointer->previous_suspicion=0;
11311 marineStatusPointer->using_squad_suspicion=0;
11312 }
11313 }
11314 }
11315 }
11316 }
11317 }
11318 }
11319 }
11320 }
11321 #endif
11322
11323 if (nearest==NULL) {
11324 if (newblip) {
11325 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
11326 tracker_noise=2;
11327 PointAlert(1,&marineStatusPointer->suspect_point);
11328 }
11329 } else {
11330 PointAlert(2,&nearest->DynPtr->Position);
11331 }
11332
11333 if (nearest) {
11334 /* Must have seen them. */
11335 marineStatusPointer->roundsForThisTarget=0;
11336 marineStatusPointer->sawlastframe=1;
11337
11338 if (((marineStatusPointer->suspicious==0)&&((FastRandom()&65535)<16384))
11339 ||(neardist<((FastRandom()&4095)+1000))) {
11340 /* Exhibit suprise? */
11341 Marine_SurpriseSound(me);
11342 }
11343 }
11344
11345 return(nearest);
11346
11347 }
11348
11349 void FakeTrackerWheepGenerator(VECTORCH *marinepos, STRATEGYBLOCK *me) {
11350
11351 int a,dist;
11352 STRATEGYBLOCK *candidate;
11353 MARINE_STATUS_BLOCK *marineStatusPointer;
11354 VECTORCH offset;
11355
11356 LOCALASSERT(me);
11357 marineStatusPointer = (MARINE_STATUS_BLOCK *)(me->SBdataptr);
11358 LOCALASSERT(marineStatusPointer);
11359
11360 if (marineStatusPointer->mtracker_timer==0) {
11361 for (a=0; a<NumActiveStBlocks; a++) {
11362 candidate=ActiveStBlockList[a];
11363 if (candidate!=me) {
11364 if (candidate->DynPtr) {
11365 /* Arc reject. */
11366 MATRIXCH WtoL;
11367
11368 offset.vx=marinepos->vx-candidate->DynPtr->Position.vx;
11369 offset.vy=marinepos->vy-candidate->DynPtr->Position.vy;
11370 offset.vz=marinepos->vz-candidate->DynPtr->Position.vz;
11371
11372 WtoL=me->DynPtr->OrientMat;
11373 TransposeMatrixCH(&WtoL);
11374 RotateVector(&offset,&WtoL);
11375
11376 if (offset.vz<=0) {
11377 /* It'll wheep, anyway. */
11378 #if 0
11379 if (
11380 (candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11381 ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11382 ||(candidate->DynPtr->Position.vx!=candidate->DynPtr->PrevPosition.vx)
11383 ) {
11384 #else
11385 if (ObjectShouldAppearOnMotionTracker(candidate)) {
11386 #endif
11387 dist=Approximate3dMagnitude(&offset);
11388 if (dist<MOTIONTRACKER_RANGE) {
11389 tracker_noise=2;
11390 }
11391 }
11392 }
11393 }
11394 }
11395 }
11396 }
11397 }
11398
11399 #if 0
11400 static STATE_RETURN_CONDITION Execute_MNS_Hunt(STRATEGYBLOCK *sbPtr)
11401 {
11402 MARINE_STATUS_BLOCK *marineStatusPointer;
11403 DYNAMICSBLOCK *dynPtr;
11404 VECTORCH velocityDirection = {0,0,0};
11405
11406 /* Your mission: to advance into the players module, even if near. */
11407
11408 LOCALASSERT(sbPtr);
11409 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
11410 dynPtr = sbPtr->DynPtr;
11411 LOCALASSERT(marineStatusPointer);
11412 LOCALASSERT(dynPtr);
11413
11414 /* check if we should be crouched or standing up */
11415 if(marineStatusPointer->IAmCrouched)
11416 {
11417 /* curently crouched */
11418 if(!(MarineShouldBeCrawling(sbPtr)))
11419 {
11420 /* should be running*/
11421 marineStatusPointer->IAmCrouched = 0;
11422 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
11423 }
11424 }
11425 else
11426 {
11427 /* currently standing */
11428 if(MarineShouldBeCrawling(sbPtr))
11429 {
11430 /* should be crawling */
11431 marineStatusPointer->IAmCrouched = 1;
11432 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
11433 }
11434 }
11435
11436 /* should we change to approach state? */
11437 if(MarineCanSeeTarget(sbPtr))
11438 {
11439 return(SRC_Request_Approach);
11440 } else if(!(MarineIsAwareOfTarget(sbPtr))) {
11441 return(SRC_Request_Wait);
11442 }
11443
11444 {
11445 AIMODULE *targetModule;
11446 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
11447
11448 targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr,0);
11449
11450 if (targetModule) {
11451 // textprint("Target module is %s\n",targetModule->name);
11452 #if MARINE_STATE_PRINT
11453 textprint("Target module is... an AI module...\n");
11454 #endif
11455 } else {
11456 #if MARINE_STATE_PRINT
11457 textprint("Target module is NULL!\n");
11458 #endif
11459 }
11460
11461 if (targetModule==sbPtr->containingModule->m_aimodule) {
11462 /* Hey, it'll drop through. */
11463 return(SRC_Request_Approach);
11464 }
11465
11466 if (!targetModule) {
11467 #if 1
11468 /* Must be sealed off. */
11469 return(SRC_Request_Wait);
11470 #else
11471 extern MODULE *playerPherModule;
11472
11473 LOGDXFMT(("Jules's bug: marine is in %s, player is in %s",sbPtr->containingModule->name,playerPherModule->name));
11474 GLOBALASSERT(targetModule);
11475 #endif
11476 }
11477
11478 thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
11479 if (!thisEp) {
11480 //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name));
11481 LOGDXFMT(("This assert is a busted adjacency!"));
11482 GLOBALASSERT(thisEp);
11483 }
11484 /* If that fired, there's a farped adjacency. */
11485 GLOBALASSERT(thisEp->alien_only==0);
11486 /* If that fired, Get...ModuleForHunt went wrong. */
11487
11488 marineStatusPointer->wanderData.worldPosition=thisEp->position;
11489 marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
11490 marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
11491 marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
11492
11493 }
11494
11495 /* ok: should have a current target at this stage... */
11496 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
11497 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
11498
11499 /* test here for impeding collisions, and not being able to reach target... */
11500 #if ALL_NEW_AVOIDANCE
11501 {
11502 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
11503 /* Go to all new avoidance. */
11504 return(SRC_Request_Avoidance);
11505 }
11506 }
11507 #else
11508 {
11509 STRATEGYBLOCK *destructableObject = NULL;
11510
11511 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
11512 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
11513 {
11514 return(SRC_Request_Avoidance);
11515 }
11516 if(marineStatusPointer->obstruction.destructableObject)
11517 {
11518 LOCALASSERT(destructableObject);
11519 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
11520 }
11521 }
11522
11523 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
11524 {
11525 /* go to avoidance */
11526 /* no sequence change required */
11527
11528 marineStatusPointer->obstruction.environment=1;
11529 marineStatusPointer->obstruction.destructableObject=0;
11530 marineStatusPointer->obstruction.otherCharacter=0;
11531 marineStatusPointer->obstruction.anySingleObstruction=0;
11532
11533 return(SRC_Request_Avoidance);
11534 }
11535 #endif
11536
11537 return(SRC_No_Change);
11538 }
11539 #endif
11540
11541 static STATE_RETURN_CONDITION Execute_MNS_Respond(STRATEGYBLOCK *sbPtr)
11542 {
11543 MARINE_STATUS_BLOCK *marineStatusPointer;
11544 DYNAMICSBLOCK *dynPtr;
11545 VECTORCH velocityDirection = {0,0,0};
11546
11547 /* Your mission: to advance into the alert zone, even if near. */
11548
11549 LOCALASSERT(sbPtr);
11550 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
11551 dynPtr = sbPtr->DynPtr;
11552 LOCALASSERT(marineStatusPointer);
11553 LOCALASSERT(dynPtr);
11554
11555 #if 0
11556 /* check if we should be crouched or standing up */
11557 if(marineStatusPointer->IAmCrouched)
11558 {
11559 /* curently crouched */
11560 if(!(MarineShouldBeCrawling(sbPtr)))
11561 {
11562 /* should be running*/
11563 marineStatusPointer->IAmCrouched = 0;
11564 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineRun,MRSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
11565 }
11566 }
11567 else
11568 {
11569 /* currently standing */
11570 if(MarineShouldBeCrawling(sbPtr))
11571 {
11572 /* should be crawling */
11573 marineStatusPointer->IAmCrouched = 1;
11574 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
11575 }
11576 }
11577 #else
11578 HandleMovingAnimations(sbPtr);
11579 #endif
11580
11581 /* should we change to approach state? */
11582 if((MarineIsAwareOfTarget(sbPtr))) {
11583 return(SRC_Request_Approach);
11584 }
11585 /* If we've picked up a new target, go for it. */
11586
11587 if (sbPtr->containingModule->m_aimodule==NpcSquad.alertZone) {
11588 /* We're here! */
11589 DeprioritiseAlert(sbPtr->containingModule->m_aimodule);
11590 /* Hey, if it's real, there'll be a new one soon enough. */
11591 return(SRC_Request_Approach);
11592 }
11593
11594 {
11595 AIMODULE *targetModule;
11596 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
11597
11598 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
11599
11600 if (targetModule) {
11601 // textprint("Target module is %s\n",targetModule->name);
11602 #if MARINE_STATE_PRINT
11603 textprint("Target module is... an AI module...\n");
11604 #endif
11605 } else {
11606 #if MARINE_STATE_PRINT
11607 textprint("Target module is NULL!\n");
11608 #endif
11609 }
11610
11611 if (targetModule==sbPtr->containingModule->m_aimodule) {
11612 /* Looks like we've arrived. */
11613 /* Hey, it'll drop through. */
11614 return(SRC_Request_Approach);
11615 }
11616
11617 if (!targetModule) {
11618 #if 1
11619 /* Must be sealed off. */
11620 return(SRC_Request_Wait);
11621 #else
11622 extern MODULE *playerPherModule;
11623
11624 LOGDXFMT(("Jules's bug: marine is in %s, player is in %s",sbPtr->containingModule->name,playerPherModule->name));
11625 GLOBALASSERT(targetModule);
11626 #endif
11627 }
11628
11629 thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
11630 if (!thisEp) {
11631 //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name));
11632 LOGDXFMT(("This assert is a busted adjacency!"));
11633 GLOBALASSERT(thisEp);
11634 }
11635 /* If that fired, there's a farped adjacency. */
11636 GLOBALASSERT(thisEp->alien_only==0);
11637 /* If that fired, GetNextModuleForLink went wrong. */
11638
11639 marineStatusPointer->wanderData.worldPosition=thisEp->position;
11640 marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
11641 marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
11642 marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
11643
11644 }
11645
11646 /* ok: should have a current target at this stage... */
11647 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
11648 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
11649
11650 /* test here for impeding collisions, and not being able to reach target... */
11651 #if ALL_NEW_AVOIDANCE
11652 {
11653 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
11654 /* Go to all new avoidance. */
11655 return(SRC_Request_Avoidance);
11656 }
11657 }
11658 #else
11659 {
11660 STRATEGYBLOCK *destructableObject = NULL;
11661
11662 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
11663 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
11664 {
11665 return(SRC_Request_Avoidance);
11666 }
11667 if(marineStatusPointer->obstruction.destructableObject)
11668 {
11669 LOCALASSERT(destructableObject);
11670 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
11671 }
11672 }
11673
11674 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
11675 {
11676 /* go to avoidance */
11677 /* no sequence change required */
11678
11679 marineStatusPointer->obstruction.environment=1;
11680 marineStatusPointer->obstruction.destructableObject=0;
11681 marineStatusPointer->obstruction.otherCharacter=0;
11682 marineStatusPointer->obstruction.anySingleObstruction=0;
11683
11684 return(SRC_Request_Avoidance);
11685 }
11686 #endif
11687
11688 return(SRC_No_Change);
11689 }
11690
11691 static int MarineRetreatsInTheFaceOfDanger(STRATEGYBLOCK *sbPtr)
11692 {
11693 MARINE_STATUS_BLOCK *marineStatusPointer;
11694
11695 LOCALASSERT(sbPtr);
11696 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
11697 LOCALASSERT(marineStatusPointer);
11698
11699 /* This depends on mission, armament, and whether he's cornered. */
11700
11701 if (marineStatusPointer->Android) {
11702 return(0);
11703 }
11704
11705 switch (marineStatusPointer->Mission) {
11706 case MM_NonCom:
11707 #if 0
11708 /* Err... runferrit! */
11709 return(1);
11710 break;
11711 #endif
11712 case MM_Guard:
11713 case MM_Wander:
11714 case MM_Wait_Then_Wander:
11715 case MM_LocalGuard:
11716 case MM_Pathfinder:
11717 {
11718 if ((FastRandom()&65535)>marineStatusPointer->Courage) {
11719 return(1);
11720 } else {
11721 return(0);
11722 }
11723 break;
11724 }
11725 default:
11726 return(0);
11727 break;
11728 }
11729
11730 return(0);
11731 }
11732
11733 static STATE_RETURN_CONDITION Execute_MNS_Retreat(STRATEGYBLOCK *sbPtr)
11734 {
11735 MARINE_STATUS_BLOCK *marineStatusPointer;
11736 DYNAMICSBLOCK *dynPtr;
11737 VECTORCH velocityDirection = {0,0,0};
11738 AIMODULE *old_fearmod;
11739
11740 /* Your mission: to advance out of trouble, even if near. */
11741
11742 LOCALASSERT(sbPtr);
11743 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
11744 dynPtr = sbPtr->DynPtr;
11745 LOCALASSERT(marineStatusPointer);
11746 LOCALASSERT(dynPtr);
11747
11748 old_fearmod=marineStatusPointer->fearmodule;
11749
11750 /* From where am I running? */
11751 if(MarineIsAwareOfTarget(sbPtr)) {
11752 marineStatusPointer->fearmodule=marineStatusPointer->Target->containingModule->m_aimodule;
11753 } else if (marineStatusPointer->fearmodule==NULL) {
11754 marineStatusPointer->fearmodule=sbPtr->containingModule->m_aimodule;
11755
11756 if (TERROR_MODE) {
11757 /* Better correct... */
11758 marineStatusPointer->fearmodule=Player->ObStrategyBlock->containingModule->m_aimodule;
11759 }
11760 }
11761
11762 if (marineStatusPointer->fearmodule!=old_fearmod) {
11763 marineStatusPointer->destinationmodule = General_GetAIModuleForRetreat(sbPtr,marineStatusPointer->fearmodule,5);
11764 }
11765
11766 {
11767 AIMODULE *targetModule;
11768 FARENTRYPOINT *thisEp = (FARENTRYPOINT *)0;
11769
11770 targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,marineStatusPointer->destinationmodule,6,0);
11771
11772 #if 0
11773 if (targetModule) {
11774 //textprint("Target module is %s\n",targetModule->name);
11775 #if MARINE_STATE_PRINT
11776 textprint("Target AI module found.\n");
11777 #endif
11778 } else {
11779 #if MARINE_STATE_PRINT
11780 textprint("Target module is NULL!\n");
11781 #endif
11782 return(SRC_Request_Wait);
11783 }
11784 #endif
11785
11786 if ((targetModule==sbPtr->containingModule->m_aimodule)
11787 || (targetModule==NULL)) {
11788 /* There's no-where to run! */
11789 if (marineStatusPointer->Target) {
11790 return(SRC_Request_PanicFire);
11791 } else {
11792 return(SRC_Request_Wait);
11793 }
11794 }
11795
11796 GLOBALASSERT(targetModule);
11797
11798 thisEp=GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule);
11799 if (!thisEp) {
11800 //LOGDXFMT(("This assert is a busted adjacency!\nNo EP between %s and %s.",targetModule->name,sbPtr->containingModule->name));
11801 LOGDXFMT(("This assert is a busted adjacency!"));
11802 GLOBALASSERT(thisEp);
11803 }
11804 /* If that fired, there's a farped adjacency. */
11805 GLOBALASSERT(thisEp->alien_only==0);
11806 /* If that fired, GetNextModuleForLink went wrong. */
11807
11808 marineStatusPointer->wanderData.worldPosition=thisEp->position;
11809 marineStatusPointer->wanderData.worldPosition.vx+=targetModule->m_world.vx;
11810 marineStatusPointer->wanderData.worldPosition.vy+=targetModule->m_world.vy;
11811 marineStatusPointer->wanderData.worldPosition.vz+=targetModule->m_world.vz;
11812
11813 }
11814
11815 /* Ok: should have a current target at this stage... */
11816 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
11817 if (marineStatusPointer->Target) {
11818 int dp;
11819 VECTORCH vectotarget;
11820 /* Are we running in a stupid direction? */
11821 vectotarget.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
11822 vectotarget.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
11823 vectotarget.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
11824 Normalise(&vectotarget);
11825
11826 dp=DotProduct(&vectotarget,&velocityDirection);
11827
11828 if (dp>55000) {
11829 /* Argh! He's in the way! */
11830 return(SRC_Request_PanicFire);
11831 }
11832 }
11833 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
11834
11835 HandleMovingAnimations(sbPtr);
11836 /* ...so we must be here for the duration. */
11837
11838 /* Scream handling. */
11839 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
11840 if (marineStatusPointer->incidentFlag) {
11841 if (Marine_HasHisMouthOpen(sbPtr)) {
11842 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
11843 Marine_PanicScream(sbPtr);
11844 }
11845 }
11846 }
11847 }
11848
11849 /* test here for impeding collisions, and not being able to reach target... */
11850 #if ALL_NEW_AVOIDANCE
11851 {
11852 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
11853 /* Go to all new avoidance. */
11854 return(SRC_Request_Avoidance);
11855 }
11856 }
11857 #else
11858 {
11859 STRATEGYBLOCK *destructableObject = NULL;
11860
11861 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
11862 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
11863 {
11864 return(SRC_Request_Avoidance);
11865 }
11866 if(marineStatusPointer->obstruction.destructableObject)
11867 {
11868 LOCALASSERT(destructableObject);
11869 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
11870 }
11871 }
11872
11873 #if 1
11874 if(NPC_CannotReachTarget(&(marineStatusPointer->moveData), &(marineStatusPointer->wanderData.worldPosition), &velocityDirection))
11875 {
11876 /* go to avoidance */
11877 /* no sequence change required */
11878
11879 marineStatusPointer->obstruction.environment=1;
11880 marineStatusPointer->obstruction.destructableObject=0;
11881 marineStatusPointer->obstruction.otherCharacter=0;
11882 marineStatusPointer->obstruction.anySingleObstruction=0;
11883
11884 return(SRC_Request_Avoidance);
11885 }
11886 #endif
11887 #endif
11888
11889 return(SRC_No_Change);
11890 }
11891
11892 static STATE_RETURN_CONDITION Execute_MNS_DischargeShotgun(STRATEGYBLOCK *sbPtr)
11893 {
11894 MARINE_STATUS_BLOCK *marineStatusPointer;
11895 VECTORCH orientationDirn,relPos,relPos2;
11896 int correctlyOrientated,range;
11897 int hitroll;
11898
11899 LOCALASSERT(sbPtr);
11900 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
11901 LOCALASSERT(marineStatusPointer);
11902
11903 /* zero velocity */
11904 LOCALASSERT(sbPtr->DynPtr);
11905 sbPtr->DynPtr->LinVelocity.vx = 0;
11906 sbPtr->DynPtr->LinVelocity.vy = 0;
11907 sbPtr->DynPtr->LinVelocity.vz = 0;
11908
11909 #if MARINE_STATE_PRINT
11910 textprint("Firing shotgun... ");
11911 #endif
11912
11913 /* first of all, validate this state: if the target suddenly becomes cloaked, then
11914 we should switch immediately to wait state.*/
11915
11916 if(!MarineCanSeeTarget(sbPtr))
11917 {
11918
11919 /* Remove the gunflash */
11920 if(marineStatusPointer->myGunFlash)
11921 {
11922 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
11923 marineStatusPointer->myGunFlash = NULL;
11924 }
11925 /* .... and stop the sound */
11926 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
11927 Sound_Stop(marineStatusPointer->soundHandle);
11928 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
11929 }
11930 return(SRC_Request_Wait);
11931 }
11932
11933 if (marineStatusPointer->clipammo==0) {
11934 return(SRC_Request_Reload);
11935 }
11936
11937 /* Here we must have a target. Renew suspicion for new arrivals. */
11938 if (NpcSquad.Squad_Suspicion==0) {
11939 PointAlert(2,&marineStatusPointer->weaponTarget);
11940 }
11941
11942 /* Deal with tweening part. */
11943 if (marineStatusPointer->internalState) {
11944 if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) {
11945 marineStatusPointer->HModelController.Playing=0;
11946 marineStatusPointer->HModelController.sequence_timer=0;
11947 marineStatusPointer->internalState=0;
11948 }
11949 return(SRC_No_Change);
11950 }
11951
11952 #if 0
11953 if ((marineStatusPointer->HModelController.keyframe_flags)
11954 ||(marineStatusPointer->HModelController.Playing==0)) {
11955
11956 marineStatusPointer->HModelController.Playing=0;
11957 #else
11958 if (marineStatusPointer->HModelController.Playing==0) {
11959 #endif
11960
11961 /* Only terminate if you haven't fired yet... */
11962 if(!MarineCanSeeTarget(sbPtr))
11963 {
11964
11965 /* ... and remove the gunflash */
11966 if(marineStatusPointer->myGunFlash)
11967 {
11968 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
11969 marineStatusPointer->myGunFlash = NULL;
11970 }
11971
11972 /* .... and stop the sound */
11973 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
11974 Sound_Stop(marineStatusPointer->soundHandle);
11975 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
11976 }
11977
11978 #if MARINE_STATE_PRINT
11979 textprint("Returning no target.\n");
11980 #endif
11981 return(SRC_Request_Wait);
11982 }
11983
11984 GLOBALASSERT(marineStatusPointer->Target);
11985 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
11986 /* Fix weapon target! */
11987 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
11988 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
11989 marineStatusPointer->My_Weapon->TargetCallibrationShift);
11990 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
11991 marineStatusPointer->My_Weapon->TargetCallibrationShift);
11992 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
11993 marineStatusPointer->My_Weapon->TargetCallibrationShift);
11994 }
11995
11996 /* orientate to firing point first */
11997 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
11998 orientationDirn.vy = 0;
11999 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
12000 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
12001
12002 /* we are not correctly orientated to the target: this could happen because we have
12003 just entered this state, or the target has moved during firing*/
12004 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
12005
12006 /* stop visual and audio cues: technically, we're not firing at this moment */
12007 if(marineStatusPointer->myGunFlash)
12008 {
12009 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12010 marineStatusPointer->myGunFlash = NULL;
12011 }
12012
12013 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12014 Sound_Stop(marineStatusPointer->soundHandle);
12015 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12016 }
12017 #if MARINE_STATE_PRINT
12018 textprint("Turning to face.\n");
12019 #endif
12020 return(SRC_No_Change);
12021 }
12022
12023 /* If you are correctly oriented, you can now fire! */
12024
12025 marineStatusPointer->HModelController.Playing=1;
12026 marineStatusPointer->HModelController.sequence_timer=0;
12027
12028 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
12029 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
12030 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
12031
12032 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
12033 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
12034 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
12035
12036 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
12037
12038 /* at this point we are correctly orientated: if we have no gunflash yet,
12039 and our state timer is set to marine_near_firetime then we have either
12040 just started firing, or have become dis-orienated between bursts. This is a good
12041 time to consider firing a grenade... */
12042
12043 /* look after the gun flash */
12044 if(marineStatusPointer->myGunFlash) {
12045 MaintainMarineGunFlash(sbPtr);
12046 } else {
12047 CreateMarineGunFlash(sbPtr);
12048 }
12049
12050 /* look after the sound */
12051 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
12052 else
12053 {
12054 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
12055 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
12056 }
12057
12058 /* Now hit the target with a shotgun blast. */
12059
12060 hitroll=0;
12061
12062 while (ShotgunBlast[hitroll].vz>0) {
12063 VECTORCH world_vec;
12064
12065 RotateAndCopyVector(&ShotgunBlast[hitroll],&world_vec,&marineStatusPointer->My_Gunflash_Section->SecMat);
12066 CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&world_vec, marineStatusPointer->My_Weapon->Ammo_Type, 1,0);
12067
12068 hitroll++;
12069 }
12070 if (marineStatusPointer->clipammo>0) {
12071 marineStatusPointer->clipammo--;
12072 }
12073
12074 } else {
12075
12076 /* Remove the gunflash */
12077 if(marineStatusPointer->myGunFlash)
12078 {
12079 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12080 marineStatusPointer->myGunFlash = NULL;
12081 }
12082 /* .... and stop the sound */
12083 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12084 Sound_Stop(marineStatusPointer->soundHandle);
12085 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12086 }
12087 }
12088
12089 marineStatusPointer->stateTimer -= NormalFrameTime;
12090
12091 /* You must have fired already. */
12092 #if 1
12093 GLOBALASSERT(marineStatusPointer->HModelController.Looped==0);
12094 if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) {
12095 return(SRC_Request_PumpAction);
12096 }
12097 return(SRC_No_Change);
12098 #else
12099 if(marineStatusPointer->stateTimer > 0) {
12100 #if MARINE_STATE_PRINT
12101 textprint("Returning continue at range %d.\n",range);
12102 #endif
12103 return(SRC_No_Change);
12104 }
12105
12106 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
12107 {
12108 /* renew firing, as we are still too close to approach */
12109 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
12110 marineStatusPointer->volleySize = 0;
12111 GLOBALASSERT(marineStatusPointer->Target);
12112 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12113 #if MARINE_STATE_PRINT
12114 textprint("Returning too close renewal at range %d.\n",range);
12115 #endif
12116 if (marineStatusPointer->Android==0) {
12117 marineStatusPointer->Courage-=(ONE_FIXED>>3);
12118 }
12119 return(SRC_No_Change);
12120 }
12121 else
12122 {
12123 /* we are far enough away, so return to approach */
12124
12125 #if MARINE_STATE_PRINT
12126 textprint("Returning too far termination at range %d.\n",range);
12127 #endif
12128 return(SRC_Request_Approach);
12129 }
12130 return(SRC_No_Change);
12131 #endif
12132 }
12133
12134 #define PISTOL_RELOAD_TIME 65536
12135
12136 static STATE_RETURN_CONDITION Execute_MNS_DischargePistol(STRATEGYBLOCK *sbPtr)
12137 {
12138 MARINE_STATUS_BLOCK *marineStatusPointer;
12139 VECTORCH orientationDirn,relPos,relPos2;
12140 int correctlyOrientated,range;
12141 int mod,hitroll;
12142
12143 LOCALASSERT(sbPtr);
12144 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
12145 LOCALASSERT(marineStatusPointer);
12146
12147 LOCALASSERT((marineStatusPointer->My_Weapon->id==MNPCW_MPistol)
12148 ||(marineStatusPointer->My_Weapon->id==MNPCW_PistolMarine)
12149 ||(marineStatusPointer->My_Weapon->id==MNPCW_Android_Pistol_Special));
12150
12151 /* zero velocity */
12152 LOCALASSERT(sbPtr->DynPtr);
12153 sbPtr->DynPtr->LinVelocity.vx = 0;
12154 sbPtr->DynPtr->LinVelocity.vy = 0;
12155 sbPtr->DynPtr->LinVelocity.vz = 0;
12156
12157 if(!MarineCanSeeTarget(sbPtr))
12158 {
12159 /* Remove the gunflash */
12160 if(marineStatusPointer->myGunFlash)
12161 {
12162 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12163 marineStatusPointer->myGunFlash = NULL;
12164 }
12165 /* .... and stop the sound */
12166 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12167 Sound_Stop(marineStatusPointer->soundHandle);
12168 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12169 }
12170 return(SRC_Request_Wait);
12171 }
12172
12173 if (marineStatusPointer->clipammo==0) {
12174 /* Remove the gunflash */
12175 if(marineStatusPointer->myGunFlash)
12176 {
12177 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12178 marineStatusPointer->myGunFlash = NULL;
12179 }
12180 return(SRC_Request_Reload);
12181 }
12182
12183 #if MARINE_STATE_PRINT
12184 textprint("Firing pistol... ");
12185 #endif
12186
12187 /* Here we must have a target. Renew suspicion for new arrivals. */
12188 if (NpcSquad.Squad_Suspicion==0) {
12189 PointAlert(2,&marineStatusPointer->weaponTarget);
12190 }
12191
12192 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
12193 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
12194 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
12195
12196 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
12197 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
12198 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
12199
12200 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
12201
12202 /* first of all, validate this state: if the target suddenly becomes cloaked, then
12203 we should switch immediately to wait state.*/
12204
12205 if ((marineStatusPointer->HModelController.keyframe_flags)
12206 ||(marineStatusPointer->HModelController.Playing==0)) {
12207
12208 marineStatusPointer->HModelController.Playing=0;
12209 marineStatusPointer->HModelController.sequence_timer=0;
12210
12211 /* Only terminate if you haven't fired yet... */
12212 if(!MarineCanSeeTarget(sbPtr))
12213 {
12214 #if 1
12215 /* ... and remove the gunflash */
12216 if(marineStatusPointer->myGunFlash)
12217 {
12218 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12219 marineStatusPointer->myGunFlash = NULL;
12220 }
12221 #endif
12222
12223 /* .... and stop the sound */
12224 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12225 Sound_Stop(marineStatusPointer->soundHandle);
12226 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12227 }
12228
12229 #if MARINE_STATE_PRINT
12230 textprint("Returning no target.\n");
12231 #endif
12232 return(SRC_Request_Wait);
12233 }
12234
12235 GLOBALASSERT(marineStatusPointer->Target);
12236 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12237 /* Fix weapon target! */
12238 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
12239 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
12240 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12241 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
12242 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12243 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
12244 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12245 }
12246
12247 /* orientate to firing point first */
12248 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
12249 orientationDirn.vy = 0;
12250 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
12251 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
12252
12253 /* we are not correctly orientated to the target: this could happen because we have
12254 just entered this state, or the target has moved during firing*/
12255 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening==Controller_Tweening)) {
12256
12257 #if 1
12258 /* stop visual and audio cues: technically, we're not firing at this moment */
12259 if(marineStatusPointer->myGunFlash)
12260 {
12261 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12262 marineStatusPointer->myGunFlash = NULL;
12263 }
12264 #endif
12265 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12266 Sound_Stop(marineStatusPointer->soundHandle);
12267 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12268 }
12269 #if MARINE_STATE_PRINT
12270 textprint("Turning to face.\n");
12271 #endif
12272 return(SRC_No_Change);
12273 }
12274
12275 /* If you are correctly oriented, you can now fire! */
12276
12277 marineStatusPointer->HModelController.Playing=1;
12278 if (marineStatusPointer->clipammo>0) {
12279 marineStatusPointer->clipammo--;
12280 }
12281 marineStatusPointer->roundsForThisTarget++;
12282
12283 /* at this point we are correctly orientated: if we have no gunflash yet,
12284 and our state timer is set to marine_near_firetime then we have either
12285 just started firing, or have become dis-orienated between bursts. This is a good
12286 time to consider firing a grenade... */
12287
12288 #if 1
12289 /* look after the gun flash */
12290 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
12291 else CreateMarineGunFlash(sbPtr);
12292 #else
12293 /* KJL 15:50:48 05/01/98 - draw muzzleflash */
12294 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
12295 {
12296 VECTORCH direction;
12297
12298 direction.vx = marineStatusPointer->My_Gunflash_Section->SecMat.mat31;
12299 direction.vy = marineStatusPointer->My_Gunflash_Section->SecMat.mat32;
12300 direction.vz = marineStatusPointer->My_Gunflash_Section->SecMat.mat33;
12301
12302 DrawMuzzleFlash(&marineStatusPointer->My_Gunflash_Section->World_Offset,&direction,MUZZLE_FLASH_AMORPHOUS);
12303 }
12304 #endif
12305
12306 /* look after the sound */
12307 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
12308 else
12309 {
12310 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
12311 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
12312 }
12313
12314 /* Now hit the target with one bullet. */
12315
12316 mod=SpeedRangeMods(&relPos,&relPos2);
12317
12318 hitroll=marineStatusPointer->Skill; /* Marine skill... */
12319 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
12320 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
12321 LOCALASSERT(playerStatusPtr);
12322 if ( (AvP.PlayerType==I_Alien)
12323 ||((AvP.PlayerType==I_Predator)&&(playerStatusPtr->cloakOn==1))) {
12324 /* Vs the player, lighting effects on aliens and cloaked preds. */
12325 hitroll=MUL_FIXED(hitroll,((CurrentLightAtPlayer>>1)+32767));
12326 }
12327 }
12328 hitroll-=mod;
12329 hitroll+=marineStatusPointer->My_Weapon->Accuracy;
12330
12331 {
12332
12333 /* Handle Damage. */
12334 if ((FastRandom()&65535)<hitroll) {
12335 /* DO DAMAGE TO TARGET HERE */
12336
12337 VECTORCH rel_pos,attack_dir;
12338 int dist;
12339 VECTORCH shotvector;
12340
12341 shotvector.vx=0;
12342 shotvector.vy=0;
12343 shotvector.vz=65535;
12344 RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat);
12345
12346 rel_pos.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
12347 rel_pos.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
12348 rel_pos.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
12349
12350 dist=Approximate3dMagnitude(&rel_pos);
12351
12352 if (VerifyHitShot(sbPtr,marineStatusPointer->Target,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, 1,dist)) {
12353
12354 GetDirectionOfAttack(marineStatusPointer->Target,&rel_pos,&attack_dir);
12355 /* Get hit location? */
12356
12357 marineStatusPointer->lasthitsection=HitLocationRoll(marineStatusPointer->Target,sbPtr);
12358
12359 if (marineStatusPointer->lasthitsection) {
12360 CauseDamageToHModel(marineStatusPointer->lasthitsection->my_controller, marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED, marineStatusPointer->lasthitsection,&attack_dir,NULL,0);
12361 } else {
12362 CauseDamageToObject(marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
12363 }
12364 }
12365 } else {
12366 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
12367 ProjectNPCShot(sbPtr, marineStatusPointer->Target, &marineStatusPointer->My_Gunflash_Section->World_Offset,&marineStatusPointer->My_Gunflash_Section->SecMat, marineStatusPointer->My_Weapon->Ammo_Type, 1);
12368 }
12369
12370 /* Did we get him? */
12371 if ((NPC_IsDead(marineStatusPointer->Target))&&(marineStatusPointer->My_Weapon->ARealMarine)) {
12372 /* Only real marines taunt. */
12373 if ((marineStatusPointer->roundsForThisTarget==1)||(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
12374 if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) {
12375 /* Huzzah! */
12376 if(marineStatusPointer->myGunFlash)
12377 {
12378 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12379 marineStatusPointer->myGunFlash = NULL;
12380 }
12381 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12382 Sound_Stop(marineStatusPointer->soundHandle);
12383 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12384 }
12385 marineStatusPointer->lastroundhit=0;
12386 marineStatusPointer->lasthitsection=NULL;
12387 return(SRC_Request_Taunt);
12388 }
12389 }
12390 }
12391 }
12392 } else {
12393 /* Remove the gunflash */
12394 if(marineStatusPointer->myGunFlash)
12395 {
12396 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12397 marineStatusPointer->myGunFlash = NULL;
12398 }
12399 /* .... and stop the sound */
12400 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12401 Sound_Stop(marineStatusPointer->soundHandle);
12402 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12403 }
12404 }
12405
12406 marineStatusPointer->stateTimer -= NormalFrameTime;
12407
12408 /* You must have fired already. */
12409
12410 if(marineStatusPointer->stateTimer > 0) {
12411 #if MARINE_STATE_PRINT
12412 textprint("Returning continue at range %d.\n",range);
12413 #endif
12414 return(SRC_No_Change);
12415 }
12416
12417 if ((range < MARINE_CLOSE_APPROACH_DISTANCE)||(marineStatusPointer->Android))
12418 {
12419 /* renew firing, as we are still too close to approach */
12420 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
12421 marineStatusPointer->volleySize = 0;
12422 GLOBALASSERT(marineStatusPointer->Target);
12423 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12424 #if MARINE_STATE_PRINT
12425 textprint("Returning too close renewal at range %d.\n",range);
12426 #endif
12427 if (marineStatusPointer->Android==0) {
12428 marineStatusPointer->Courage-=(ONE_FIXED>>3);
12429 }
12430 return(SRC_No_Change);
12431 }
12432 else
12433 {
12434 /* we are far enough away, so return to approach */
12435
12436 #if MARINE_STATE_PRINT
12437 textprint("Returning too far termination at range %d.\n",range);
12438 #endif
12439 /* Remove the gunflash */
12440 if(marineStatusPointer->myGunFlash)
12441 {
12442 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12443 marineStatusPointer->myGunFlash = NULL;
12444 }
12445 return(SRC_Request_Approach);
12446 }
12447 return(SRC_No_Change);
12448 }
12449
12450 static STATE_RETURN_CONDITION Execute_MNS_ThrowMolotov(STRATEGYBLOCK *sbPtr)
12451 {
12452 MARINE_STATUS_BLOCK *marineStatusPointer;
12453 VECTORCH orientationDirn;
12454 int correctlyOrientated;
12455
12456 LOCALASSERT(sbPtr);
12457 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
12458 LOCALASSERT(marineStatusPointer);
12459
12460 /* zero velocity */
12461 LOCALASSERT(sbPtr->DynPtr);
12462 sbPtr->DynPtr->LinVelocity.vx = 0;
12463 sbPtr->DynPtr->LinVelocity.vy = 0;
12464 sbPtr->DynPtr->LinVelocity.vz = 0;
12465
12466 /* first of all, validate this state: if the target suddenly becomes cloaked, then
12467 we should switch immediately to wait state.*/
12468
12469 if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) {
12470 marineStatusPointer->HModelController.Playing=0;
12471 marineStatusPointer->HModelController.sequence_timer=0;
12472 marineStatusPointer->stateTimer--;
12473 }
12474
12475 {
12476 if (marineStatusPointer->Target) {
12477 /* Only terminate if you haven't fired yet... */
12478 if(!MarineCanSeeTarget(sbPtr))
12479 {
12480
12481 /* .... and stop the sound */
12482 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12483 Sound_Stop(marineStatusPointer->soundHandle);
12484 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12485 }
12486
12487 #if MARINE_STATE_PRINT
12488 textprint("Returning no target.\n");
12489 #endif
12490 return(SRC_Request_Wait);
12491 }
12492
12493 GLOBALASSERT(marineStatusPointer->Target);
12494 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12495 /* Fix weapon target! */
12496 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
12497 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
12498 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12499 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
12500 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12501 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
12502 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12503 }
12504
12505 /* Here we must have a target. Renew suspicion for new arrivals. */
12506 if (NpcSquad.Squad_Suspicion==0) {
12507 PointAlert(2,&marineStatusPointer->weaponTarget);
12508 }
12509
12510 }
12511
12512 /* orientate to firing point first */
12513 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
12514 orientationDirn.vy = 0;
12515 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
12516 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
12517
12518 /* we are not correctly orientated to the target: this could happen because we have
12519 just entered this state, or the target has moved during firing*/
12520 if(!correctlyOrientated)
12521 {
12522 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12523 Sound_Stop(marineStatusPointer->soundHandle);
12524 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12525 }
12526 #if MARINE_STATE_PRINT
12527 textprint("Turning to face.\n");
12528 #endif
12529 return(SRC_No_Change);
12530 }
12531
12532 /* If you are correctly oriented, you can now fire! */
12533
12534 marineStatusPointer->HModelController.Playing=1;
12535
12536 /* at this point we are correctly orientated: if we have no gunflash yet,
12537 and our state timer is set to marine_near_firetime then we have either
12538 just started firing, or have become dis-orienated between bursts. This is a good
12539 time to consider firing a grenade... */
12540
12541 /* No muzzle flash. */
12542
12543 /* look after the sound */
12544 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
12545 else
12546 {
12547 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
12548 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
12549 }
12550
12551 if(marineStatusPointer->My_Gunflash_Section) {
12552
12553 if (marineStatusPointer->HModelController.keyframe_flags) {
12554
12555 SECTION *root;
12556 MARINE_WEAPON_DATA *noncom;
12557
12558 /* Throw! */
12559 SpawnMolotovCocktail(marineStatusPointer->My_Gunflash_Section, &sbPtr->DynPtr->OrientMat);
12560 marineStatusPointer->My_Gunflash_Section=NULL;
12561 marineStatusPointer->Mission=MM_NonCom;
12562 /* Turn into a noncom! */
12563
12564 {
12565 /* Remove hitdelta, if there is one. */
12566 DELTA_CONTROLLER *delta;
12567 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
12568 if (delta) {
12569 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
12570 }
12571 }
12572
12573 noncom=GetThisNPCMarineWeapon(MNPCW_MUnarmed);
12574
12575 root=GetNamedHierarchyFromLibrary(noncom->Riffname,noncom->HierarchyName);
12576 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root, 1, 0,0);
12577 marineStatusPointer->My_Weapon=noncom;
12578
12579 /* Attempt to put the hitdelta back? */
12580 if (HModelSequence_Exists(&marineStatusPointer->HModelController,(int)HMSQT_MarineStand,(int)MSSS_HitChestFront)) {
12581 DELTA_CONTROLLER *delta;
12582 delta=Add_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta",(int)HMSQT_MarineStand,(int)MSSS_HitChestFront,(ONE_FIXED>>2));
12583 GLOBALASSERT(delta);
12584 delta->Playing=0;
12585 }
12586
12587 return(SRC_Request_Retreat);
12588 }
12589 }
12590 }
12591
12592 return(SRC_No_Change);
12593 }
12594
12595 #if 0
12596 static STATE_RETURN_CONDITION Execute_MNS_DischargeGL(STRATEGYBLOCK *sbPtr)
12597 {
12598 MARINE_STATUS_BLOCK *marineStatusPointer;
12599 VECTORCH orientationDirn,relPos,relPos2;
12600 int correctlyOrientated,range;
12601
12602 LOCALASSERT(sbPtr);
12603 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
12604 LOCALASSERT(marineStatusPointer);
12605
12606 #if MARINE_STATE_PRINT
12607 textprint("Firing grenade launcher... ");
12608 #endif
12609
12610 /* zero velocity */
12611 LOCALASSERT(sbPtr->DynPtr);
12612 sbPtr->DynPtr->LinVelocity.vx = 0;
12613 sbPtr->DynPtr->LinVelocity.vy = 0;
12614 sbPtr->DynPtr->LinVelocity.vz = 0;
12615
12616 /* first of all, validate this state: if the target suddenly becomes cloaked, then
12617 we should switch immediately to wait state.*/
12618
12619 if (marineStatusPointer->HModelController.keyframe_flags&2) {
12620 marineStatusPointer->internalState=1;
12621 }
12622 if (marineStatusPointer->HModelController.keyframe_flags&1) {
12623 marineStatusPointer->internalState=0;
12624 }
12625
12626 if(!MarineCanSeeTarget(sbPtr))
12627 {
12628 /* Remove the gunflash */
12629 if(marineStatusPointer->myGunFlash)
12630 {
12631 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12632 marineStatusPointer->myGunFlash = NULL;
12633 }
12634 /* .... and stop the sound */
12635 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12636 Sound_Stop(marineStatusPointer->soundHandle);
12637 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12638 }
12639 return(SRC_Request_Wait);
12640 }
12641
12642 if (marineStatusPointer->clipammo==0) {
12643 /* Reload here. */
12644 return(SRC_Request_Reload);
12645 }
12646
12647 /* Here we must have a target. Renew suspicion for new arrivals. */
12648 if (NpcSquad.Squad_Suspicion==0) {
12649 PointAlert(2,&marineStatusPointer->weaponTarget);
12650 }
12651
12652 if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) {
12653
12654 if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) {
12655 marineStatusPointer->HModelController.Playing=0;
12656 }
12657
12658 /* Only terminate if you haven't fired yet... */
12659 if(!MarineCanSeeTarget(sbPtr))
12660 {
12661 #if 1
12662 /* ... and remove the gunflash */
12663 if(marineStatusPointer->myGunFlash)
12664 {
12665 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12666 marineStatusPointer->myGunFlash = NULL;
12667 }
12668 #endif
12669
12670 /* .... and stop the sound */
12671 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12672 Sound_Stop(marineStatusPointer->soundHandle);
12673 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12674 }
12675
12676 #if MARINE_STATE_PRINT
12677 textprint("Returning no target.\n");
12678 #endif
12679 return(SRC_Request_Wait);
12680 }
12681
12682 GLOBALASSERT(marineStatusPointer->Target);
12683 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12684 /* Fix weapon target! */
12685 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
12686 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
12687 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12688 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
12689 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12690 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
12691 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12692 }
12693
12694 /* Aim up a little? */
12695 range=VectorDistance((&marineStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position));
12696
12697 marineStatusPointer->weaponTarget.vy-=(range/6);
12698
12699 /* orientate to firing point first */
12700 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
12701 orientationDirn.vy = 0;
12702 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
12703 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
12704
12705 /* we are not correctly orientated to the target: this could happen because we have
12706 just entered this state, or the target has moved during firing*/
12707 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
12708
12709 #if 1
12710 /* stop visual and audio cues: technically, we're not firing at this moment */
12711 if(marineStatusPointer->myGunFlash)
12712 {
12713 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12714 marineStatusPointer->myGunFlash = NULL;
12715 }
12716 #endif
12717 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12718 Sound_Stop(marineStatusPointer->soundHandle);
12719 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12720 }
12721 #if MARINE_STATE_PRINT
12722 textprint("Turning to face.\n");
12723 #endif
12724 return(SRC_No_Change);
12725 }
12726
12727 /* If you are correctly oriented, you can now fire! */
12728
12729 marineStatusPointer->HModelController.Playing=1;
12730 marineStatusPointer->HModelController.sequence_timer=0;
12731
12732 #if 0
12733 /* Can't afford to have the jam! */
12734 if (marineStatusPointer->internalState!=0) {
12735 /* Just in case. */
12736 return(SRC_No_Change);
12737 }
12738 #endif
12739
12740 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
12741 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
12742 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
12743
12744 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
12745 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
12746 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
12747
12748 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
12749
12750 /* Are they, by some chance, really close? */
12751 if (range<marineStatusPointer->My_Weapon->MinRange) {
12752 if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
12753 /* Stay cool. */
12754 return(SRC_Request_PullPistol);
12755 } else {
12756 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
12757 /* Fail twice, then flee... else continue. */
12758 return(SRC_Request_Retreat);
12759 }
12760 }
12761 }
12762
12763 #if 1
12764 /* look after the gun flash */
12765 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
12766 else CreateMarineGunFlash(sbPtr);
12767 #else
12768 /* KJL 15:50:48 05/01/98 - draw muzzleflash */
12769 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
12770 {
12771 VECTORCH direction;
12772
12773 direction.vx = marineStatusPointer->My_Gunflash_Section->SecMat.mat31;
12774 direction.vy = marineStatusPointer->My_Gunflash_Section->SecMat.mat32;
12775 direction.vz = marineStatusPointer->My_Gunflash_Section->SecMat.mat33;
12776
12777 DrawMuzzleFlash(&marineStatusPointer->My_Gunflash_Section->World_Offset,&direction,MUZZLE_FLASH_AMORPHOUS);
12778 }
12779 #endif
12780
12781 /* look after the sound */
12782 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
12783 else
12784 {
12785 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
12786 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
12787 }
12788
12789 /* Now fire a grenade. */
12790
12791
12792 {
12793 LOCALASSERT(marineStatusPointer->My_Gunflash_Section);
12794 //LOCALASSERT(marineStatusPointer->internalState==0);
12795
12796 CreateGrenadeKernel(I_BehaviourGrenade, &marineStatusPointer->My_Gunflash_Section->World_Offset, &marineStatusPointer->My_Gunflash_Section->SecMat,0);
12797
12798 if (marineStatusPointer->clipammo>0) {
12799 marineStatusPointer->clipammo--;
12800 }
12801 }
12802 }
12803
12804 if (marineStatusPointer->stateTimer<marineStatusPointer->My_Weapon->FiringTime) {
12805 /* Remove the gunflash */
12806 if(marineStatusPointer->myGunFlash)
12807 {
12808 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12809 marineStatusPointer->myGunFlash = NULL;
12810 }
12811 /* .... and stop the sound */
12812 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12813 Sound_Stop(marineStatusPointer->soundHandle);
12814 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12815 }
12816 }
12817
12818 marineStatusPointer->stateTimer -= NormalFrameTime;
12819
12820 /* You must have fired already. */
12821
12822 if(marineStatusPointer->stateTimer > 0) {
12823 #if MARINE_STATE_PRINT
12824 textprint("Returning continue at range %d.\n",range);
12825 #endif
12826 return(SRC_No_Change);
12827 }
12828
12829 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
12830 {
12831 /* renew firing, as we are still too close to approach */
12832 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
12833 marineStatusPointer->volleySize = 0;
12834 GLOBALASSERT(marineStatusPointer->Target);
12835 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12836 #if MARINE_STATE_PRINT
12837 textprint("Returning too close renewal at range %d.\n",range);
12838 #endif
12839 return(SRC_No_Change);
12840 }
12841 else
12842 {
12843 /* we are far enough away, so return to approach */
12844
12845 #if MARINE_STATE_PRINT
12846 textprint("Returning too far termination at range %d.\n",range);
12847 #endif
12848 return(SRC_Request_Approach);
12849 }
12850 return(SRC_No_Change);
12851 }
12852 #endif
12853
12854 static STATE_RETURN_CONDITION Execute_MNS_NewDischargeGL(STRATEGYBLOCK *sbPtr)
12855 {
12856 MARINE_STATUS_BLOCK *marineStatusPointer;
12857 VECTORCH orientationDirn,relPos,relPos2;
12858 int correctlyOrientated,range;
12859
12860 LOCALASSERT(sbPtr);
12861 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
12862 LOCALASSERT(marineStatusPointer);
12863
12864 /* zero velocity */
12865 LOCALASSERT(sbPtr->DynPtr);
12866 sbPtr->DynPtr->LinVelocity.vx = 0;
12867 sbPtr->DynPtr->LinVelocity.vy = 0;
12868 sbPtr->DynPtr->LinVelocity.vz = 0;
12869
12870 /* first of all, validate this state: if the target suddenly becomes cloaked, then
12871 we should switch immediately to wait state.*/
12872
12873 if(!MarineCanSeeTarget(sbPtr))
12874 {
12875
12876 /* Remove the gunflash */
12877 if(marineStatusPointer->myGunFlash)
12878 {
12879 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12880 marineStatusPointer->myGunFlash = NULL;
12881 }
12882 /* .... and stop the sound */
12883 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12884 Sound_Stop(marineStatusPointer->soundHandle);
12885 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12886 }
12887 return(SRC_Request_Wait);
12888 }
12889
12890 if (marineStatusPointer->clipammo==0) {
12891 return(SRC_Request_Reload);
12892 }
12893
12894 /* Here we must have a target. Renew suspicion for new arrivals. */
12895 if (NpcSquad.Squad_Suspicion==0) {
12896 PointAlert(2,&marineStatusPointer->weaponTarget);
12897 }
12898
12899 /* Deal with tweening part. */
12900 if (marineStatusPointer->internalState) {
12901 if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) {
12902 marineStatusPointer->HModelController.Playing=0;
12903 marineStatusPointer->HModelController.sequence_timer=0;
12904 marineStatusPointer->internalState=0;
12905 }
12906 return(SRC_No_Change);
12907 }
12908
12909 if (marineStatusPointer->HModelController.Playing==0) {
12910
12911 /* Only terminate if you haven't fired yet... */
12912 if(!MarineCanSeeTarget(sbPtr))
12913 {
12914
12915 /* ... and remove the gunflash */
12916 if(marineStatusPointer->myGunFlash)
12917 {
12918 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12919 marineStatusPointer->myGunFlash = NULL;
12920 }
12921
12922 /* .... and stop the sound */
12923 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12924 Sound_Stop(marineStatusPointer->soundHandle);
12925 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12926 }
12927
12928 #if MARINE_STATE_PRINT
12929 textprint("Returning no target.\n");
12930 #endif
12931 return(SRC_Request_Wait);
12932 }
12933
12934 GLOBALASSERT(marineStatusPointer->Target);
12935 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
12936 /* Fix weapon target! */
12937 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
12938 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
12939 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12940 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
12941 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12942 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
12943 marineStatusPointer->My_Weapon->TargetCallibrationShift);
12944 }
12945
12946 /* Aim up a little? */
12947 range=VectorDistance((&marineStatusPointer->weaponTarget),(&sbPtr->DynPtr->Position));
12948
12949 marineStatusPointer->weaponTarget.vy-=(range/8);
12950
12951 /* orientate to firing point first */
12952 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
12953 orientationDirn.vy = 0;
12954 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
12955 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
12956
12957 /* we are not correctly orientated to the target: this could happen because we have
12958 just entered this state, or the target has moved during firing*/
12959 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
12960
12961 /* stop visual and audio cues: technically, we're not firing at this moment */
12962 if(marineStatusPointer->myGunFlash)
12963 {
12964 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
12965 marineStatusPointer->myGunFlash = NULL;
12966 }
12967
12968 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
12969 Sound_Stop(marineStatusPointer->soundHandle);
12970 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
12971 }
12972 #if MARINE_STATE_PRINT
12973 textprint("Turning to face.\n");
12974 #endif
12975 return(SRC_No_Change);
12976 }
12977
12978 /* If you are correctly oriented, you can now fire! */
12979
12980 marineStatusPointer->HModelController.Playing=1;
12981 marineStatusPointer->HModelController.sequence_timer=0;
12982
12983 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
12984 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
12985 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
12986
12987 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
12988 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
12989 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
12990
12991 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
12992
12993 /* Are they, by some chance, really close? */
12994 if (range<marineStatusPointer->My_Weapon->MinRange) {
12995 if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
12996 /* Stay cool. */
12997 return(SRC_Request_PullPistol);
12998 } else {
12999 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
13000 /* Fail twice, then flee... else continue. */
13001 return(SRC_Request_Retreat);
13002 }
13003 }
13004 }
13005
13006 /* at this point we are correctly orientated: if we have no gunflash yet,
13007 and our state timer is set to marine_near_firetime then we have either
13008 just started firing, or have become dis-orienated between bursts. This is a good
13009 time to consider firing a grenade... */
13010
13011 /* look after the gun flash */
13012 if(marineStatusPointer->myGunFlash) {
13013 MaintainMarineGunFlash(sbPtr);
13014 } else {
13015 CreateMarineGunFlash(sbPtr);
13016 }
13017
13018 /* look after the sound */
13019 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
13020 else
13021 {
13022 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
13023 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
13024 }
13025
13026 /* Now fire a grenade. */
13027 {
13028 LOCALASSERT(marineStatusPointer->My_Gunflash_Section);
13029
13030 CreateGrenadeKernel(I_BehaviourGrenade, &marineStatusPointer->My_Gunflash_Section->World_Offset, &marineStatusPointer->My_Gunflash_Section->SecMat,0);
13031
13032 if (marineStatusPointer->clipammo>0) {
13033 marineStatusPointer->clipammo--;
13034 }
13035 }
13036
13037 } else {
13038
13039 /* Remove the gunflash */
13040 if(marineStatusPointer->myGunFlash)
13041 {
13042 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
13043 marineStatusPointer->myGunFlash = NULL;
13044 }
13045 /* .... and stop the sound */
13046 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
13047 Sound_Stop(marineStatusPointer->soundHandle);
13048 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
13049 }
13050 }
13051
13052 marineStatusPointer->stateTimer -= NormalFrameTime;
13053
13054 /* You must have fired already. */
13055
13056 GLOBALASSERT(marineStatusPointer->HModelController.Looped==0);
13057 if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) {
13058 return(SRC_Request_PumpAction);
13059 }
13060 return(SRC_No_Change);
13061
13062 }
13063
13064 static STATE_RETURN_CONDITION Execute_MNS_DischargeSADAR(STRATEGYBLOCK *sbPtr)
13065 {
13066 MARINE_STATUS_BLOCK *marineStatusPointer;
13067 VECTORCH orientationDirn,relPos,relPos2;
13068 int correctlyOrientated,range;
13069
13070 LOCALASSERT(sbPtr);
13071 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
13072 LOCALASSERT(marineStatusPointer);
13073
13074 #if MARINE_STATE_PRINT
13075 textprint("Firing SADAR... ");
13076 #endif
13077
13078 /* zero velocity */
13079 LOCALASSERT(sbPtr->DynPtr);
13080 sbPtr->DynPtr->LinVelocity.vx = 0;
13081 sbPtr->DynPtr->LinVelocity.vy = 0;
13082 sbPtr->DynPtr->LinVelocity.vz = 0;
13083
13084 /* first of all, validate this state: if the target suddenly becomes cloaked, then
13085 we should switch immediately to wait state.*/
13086
13087 if(!MarineCanSeeTarget(sbPtr))
13088 {
13089
13090 /* Remove the gunflash */
13091 if(marineStatusPointer->myGunFlash)
13092 {
13093 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
13094 marineStatusPointer->myGunFlash = NULL;
13095 }
13096 /* .... and stop the sound */
13097 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
13098 Sound_Stop(marineStatusPointer->soundHandle);
13099 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
13100 }
13101 return(SRC_Request_Wait);
13102 }
13103
13104 if (marineStatusPointer->clipammo==0) {
13105 /* Reload here. */
13106 return(SRC_Request_Reload);
13107 }
13108
13109 /* Here we must have a target. Renew suspicion for new arrivals. */
13110 if (NpcSquad.Squad_Suspicion==0) {
13111 PointAlert(2,&marineStatusPointer->weaponTarget);
13112 }
13113
13114 if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) {
13115
13116 if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) {
13117 marineStatusPointer->HModelController.Playing=0;
13118 }
13119
13120 /* Only terminate if you haven't fired yet... */
13121 if(!MarineCanSeeTarget(sbPtr))
13122 {
13123 #if 1
13124 /* ... and remove the gunflash */
13125 if(marineStatusPointer->myGunFlash)
13126 {
13127 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
13128 marineStatusPointer->myGunFlash = NULL;
13129 }
13130 #endif
13131
13132 /* .... and stop the sound */
13133 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
13134 Sound_Stop(marineStatusPointer->soundHandle);
13135 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
13136 }
13137
13138 #if MARINE_STATE_PRINT
13139 textprint("Returning no target.\n");
13140 #endif
13141 return(SRC_Request_Wait);
13142 }
13143
13144 GLOBALASSERT(marineStatusPointer->Target);
13145 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
13146 /* Fix weapon target! */
13147 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
13148 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
13149 marineStatusPointer->My_Weapon->TargetCallibrationShift);
13150 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
13151 marineStatusPointer->My_Weapon->TargetCallibrationShift);
13152 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
13153 marineStatusPointer->My_Weapon->TargetCallibrationShift);
13154 }
13155
13156 /* orientate to firing point first */
13157 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
13158 orientationDirn.vy = 0;
13159 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
13160 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
13161
13162 /* we are not correctly orientated to the target: this could happen because we have
13163 just entered this state, or the target has moved during firing*/
13164 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
13165
13166 #if 1
13167 /* stop visual and audio cues: technically, we're not firing at this moment */
13168 if(marineStatusPointer->myGunFlash)
13169 {
13170 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
13171 marineStatusPointer->myGunFlash = NULL;
13172 }
13173 #endif
13174 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
13175 Sound_Stop(marineStatusPointer->soundHandle);
13176 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
13177 }
13178 #if MARINE_STATE_PRINT
13179 textprint("Turning to face.\n");
13180 #endif
13181 return(SRC_No_Change);
13182 }
13183
13184 /* If you are correctly oriented, you can now fire! */
13185
13186 marineStatusPointer->HModelController.Playing=1;
13187 marineStatusPointer->HModelController.sequence_timer=0;
13188
13189 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
13190 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
13191 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
13192
13193 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
13194 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
13195 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
13196
13197 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
13198
13199 /* Are they, by some chance, really close? */
13200 if (range<marineStatusPointer->My_Weapon->MinRange) {
13201 if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
13202 /* Stay cool. */
13203 return(SRC_Request_PullPistol);
13204 } else {
13205 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
13206 /* Fail twice, then flee... else continue. */
13207 return(SRC_Request_Retreat);
13208 }
13209 }
13210 }
13211
13212 /* at this point we are correctly orientated: if we have no gunflash yet,
13213 and our state timer is set to marine_near_firetime then we have either
13214 just started firing, or have become dis-orienated between bursts. This is a good
13215 time to consider firing a grenade... */
13216
13217 #if 1
13218 /* look after the gun flash */
13219 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
13220 else CreateMarineGunFlash(sbPtr);
13221 #else
13222 /* KJL 15:50:48 05/01/98 - draw muzzleflash */
13223 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
13224 {
13225 VECTORCH direction;
13226
13227 direction.vx = marineStatusPointer->My_Gunflash_Section->SecMat.mat31;
13228 direction.vy = marineStatusPointer->My_Gunflash_Section->SecMat.mat32;
13229 direction.vz = marineStatusPointer->My_Gunflash_Section->SecMat.mat33;
13230
13231 DrawMuzzleFlash(&marineStatusPointer->My_Gunflash_Section->World_Offset,&direction,MUZZLE_FLASH_AMORPHOUS);
13232 }
13233 #endif
13234
13235 /* look after the sound */
13236 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
13237 else
13238 {
13239 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
13240 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
13241 }
13242
13243 /* Now fire a rocket. */
13244
13245 {
13246 SECTION_DATA *rocket_section;
13247
13248 rocket_section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum flash");
13249
13250 LOCALASSERT(rocket_section);
13251
13252 CreateRocketKernel(&rocket_section->World_Offset, &rocket_section->SecMat,0);
13253
13254 if (marineStatusPointer->clipammo>0) {
13255 marineStatusPointer->clipammo--;
13256 }
13257 }
13258 }
13259
13260 if (marineStatusPointer->stateTimer<marineStatusPointer->My_Weapon->FiringTime) {
13261 /* Remove the gunflash */
13262 if(marineStatusPointer->myGunFlash)
13263 {
13264 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
13265 marineStatusPointer->myGunFlash = NULL;
13266 }
13267 /* .... and stop the sound */
13268 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
13269 Sound_Stop(marineStatusPointer->soundHandle);
13270 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
13271 }
13272 }
13273
13274 marineStatusPointer->stateTimer -= NormalFrameTime;
13275
13276 /* You must have fired already. */
13277
13278 if(marineStatusPointer->stateTimer > 0) {
13279 #if MARINE_STATE_PRINT
13280 textprint("Returning continue at range %d.\n",range);
13281 #endif
13282 return(SRC_No_Change);
13283 }
13284
13285 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
13286 {
13287 /* renew firing, as we are still too close to approach */
13288 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
13289 marineStatusPointer->volleySize = 0;
13290 GLOBALASSERT(marineStatusPointer->Target);
13291 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
13292 #if MARINE_STATE_PRINT
13293 textprint("Returning too close renewal at range %d.\n",range);
13294 #endif
13295 return(SRC_No_Change);
13296 }
13297 else
13298 {
13299 /* we are far enough away, so return to approach */
13300
13301 #if MARINE_STATE_PRINT
13302 textprint("Returning too far termination at range %d.\n",range);
13303 #endif
13304 return(SRC_Request_Approach);
13305 }
13306 return(SRC_No_Change);
13307 }
13308
13309 void GetNewRandomDirection(MARINE_STATUS_BLOCK *marineStatusPointer) {
13310
13311 int rnum;
13312
13313 rnum=FastRandom()&65535;
13314
13315 marineStatusPointer->lastroundhit&=65535;
13316 marineStatusPointer->lastroundhit|=(rnum<<16);
13317
13318 }
13319
13320 void GetFirstRandomDirection(MARINE_STATUS_BLOCK *marineStatusPointer,VECTORCH *output) {
13321
13322 int rnum;
13323 MATRIXCH tempmat;
13324 EULER tempeul;
13325 VECTORCH tempvec;
13326
13327 rnum=FastRandom()&65535;
13328
13329 rnum>>=4;
13330
13331 tempeul.EulerX=0;
13332 tempeul.EulerY=rnum;
13333 tempeul.EulerZ=0;
13334
13335 CreateEulerMatrix(&tempeul,&tempmat);
13336
13337 tempvec.vx=0;
13338 tempvec.vy=0;
13339 tempvec.vz=65535;
13340
13341 RotateAndCopyVector(&tempvec,output,&tempmat);
13342
13343 marineStatusPointer->lastroundhit=(rnum<<20)+(rnum<<4);
13344
13345 }
13346
13347 void TurnToFaceRandomDirection(MARINE_STATUS_BLOCK *marineStatusPointer,VECTORCH *output) {
13348
13349 int currentangle,targetangle,deltaangle,deltaangle2;
13350 MATRIXCH tempmat;
13351 EULER tempeul;
13352 VECTORCH tempvec;
13353
13354 currentangle=(marineStatusPointer->lastroundhit)&(65535);
13355 targetangle=(marineStatusPointer->lastroundhit>>16)&(65535);
13356
13357 deltaangle=targetangle-currentangle;
13358 deltaangle2=deltaangle;
13359 if (deltaangle<0) deltaangle+=65536;
13360
13361 if (deltaangle>32767) {
13362 currentangle-=(NormalFrameTime>>1);
13363 if (currentangle<0) currentangle+=65536;
13364 } else {
13365 currentangle+=(NormalFrameTime>>1);
13366 if (currentangle>65535) currentangle-=65536;
13367 }
13368 /* Overshoot test. */
13369 deltaangle=targetangle-currentangle;
13370 if ((deltaangle*deltaangle2)<=0) {
13371 currentangle=targetangle;
13372 }
13373
13374 LOCALASSERT(currentangle<65536);
13375 marineStatusPointer->lastroundhit&=~65535;
13376 marineStatusPointer->lastroundhit|=currentangle;
13377
13378 currentangle>>=4;
13379
13380 tempeul.EulerX=0;
13381 tempeul.EulerY=currentangle;
13382 tempeul.EulerZ=0;
13383
13384 CreateEulerMatrix(&tempeul,&tempmat);
13385
13386 tempvec.vx=0;
13387 tempvec.vy=0;
13388 tempvec.vz=65535;
13389
13390 RotateAndCopyVector(&tempvec,output,&tempmat);
13391
13392 }
13393
13394 void Convert_To_RunningOnFire(STRATEGYBLOCK *sbPtr) {
13395
13396 SECTION *root;
13397 MARINE_STATUS_BLOCK *marineStatusPointer;
13398
13399 LOCALASSERT(sbPtr);
13400 LOCALASSERT(sbPtr->containingModule);
13401 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
13402 LOCALASSERT(marineStatusPointer);
13403
13404 /* Burn off tracker. */
13405 marineStatusPointer->mtracker_timer=-1;
13406
13407 /* Grimace. */
13408 Marine_SwitchExpression(sbPtr,5);
13409
13410 if (marineStatusPointer->behaviourState == MBS_Dying) {
13411 /* Just die. */
13412 return;
13413 }
13414
13415 /* get rid of the gun flash, if we've got it */
13416 if(marineStatusPointer->myGunFlash)
13417 {
13418 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
13419 marineStatusPointer->myGunFlash = NULL;
13420 }
13421
13422 /* Switch to template. */
13423 root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName);
13424
13425 /* Remove all deltas. */
13426 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Elevation");
13427 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
13428 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"Minigun");
13429 Remove_Delta_Sequence(&marineStatusPointer->HModelController,"sprintheaddelta");
13430
13431 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,
13432 root, 1, 0,0);
13433
13434 SetMarineAnimationSequence(sbPtr,HMSQT_MarineRun,MRSS_Tem_Run_On_Fire,
13435 (ONE_FIXED*3),(ONE_FIXED>>2));
13436
13437 GetFirstRandomDirection(marineStatusPointer,&(marineStatusPointer->wanderData.worldPosition));
13438 /* Hey, it's a spare vector. */
13439 marineStatusPointer->nearSpeed=MARINE_NEAR_SPEED>>1;
13440 NPCSetVelocity(sbPtr, &(marineStatusPointer->wanderData.worldPosition), marineStatusPointer->nearSpeed);
13441
13442 InitMission(sbPtr,MM_RunAroundOnFire);
13443
13444 marineStatusPointer->stateTimer=(ONE_FIXED);
13445
13446 /* Add crackling sound. */
13447
13448 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Stop(marineStatusPointer->soundHandle);
13449
13450 Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&marineStatusPointer->soundHandle,127);
13451
13452 }
13453
13454 static STATE_RETURN_CONDITION Execute_MNS_RunAroundOnFire(STRATEGYBLOCK *sbPtr)
13455 {
13456 MARINE_STATUS_BLOCK *marineStatusPointer;
13457 DYNAMICSBLOCK *dynPtr;
13458
13459 LOCALASSERT(sbPtr);
13460 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
13461 dynPtr = sbPtr->DynPtr;
13462 LOCALASSERT(marineStatusPointer);
13463 LOCALASSERT(dynPtr);
13464
13465 if (sbPtr->SBDamageBlock.IsOnFire==0) {
13466 /* Stay on fire! */
13467 sbPtr->SBDamageBlock.IsOnFire=1;
13468 }
13469
13470 /* check if we should be crouched or standing up */
13471 if(marineStatusPointer->IAmCrouched)
13472 {
13473 /* curently crouched */
13474 if(!(MarineShouldBeCrawling(sbPtr)))
13475 {
13476 /* should be running*/
13477 marineStatusPointer->IAmCrouched = 0;
13478 SetMarineAnimationSequence(sbPtr,HMSQT_MarineRun,MRSS_Tem_Run_On_Fire,ONE_FIXED,(ONE_FIXED>>3));
13479 }
13480 }
13481 else
13482 {
13483 /* currently standing */
13484 if(MarineShouldBeCrawling(sbPtr))
13485 {
13486 /* should be crawling, I guess... */
13487 marineStatusPointer->IAmCrouched = 1;
13488 SetMarineAnimationSequence(sbPtr,HMSQT_MarineCrawl,MCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3));
13489 }
13490 }
13491
13492 /* Set velocity for this frame. */
13493 marineStatusPointer->stateTimer-=NormalFrameTime;
13494 if (marineStatusPointer->stateTimer<0) {
13495 marineStatusPointer->stateTimer=0;
13496 //if (FastRandom()&15==0)
13497 {
13498 GetNewRandomDirection(marineStatusPointer);
13499 marineStatusPointer->stateTimer=(ONE_FIXED);
13500 }
13501 }
13502 TurnToFaceRandomDirection(marineStatusPointer,&(marineStatusPointer->wanderData.worldPosition));
13503 NPCSetVelocity(sbPtr, &(marineStatusPointer->wanderData.worldPosition), marineStatusPointer->nearSpeed);
13504
13505 /* Handle sound... */
13506 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
13507
13508 /* test here for impeding collisions, and not being able to reach target... */
13509 #if ALL_NEW_AVOIDANCE
13510 {
13511 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
13512 /* Go to all new avoidance. */
13513 return(SRC_Request_Avoidance);
13514 }
13515 }
13516 #else
13517 {
13518 STRATEGYBLOCK *destructableObject = NULL;
13519
13520 NPC_IsObstructed(sbPtr,&(marineStatusPointer->moveData),&marineStatusPointer->obstruction,&destructableObject);
13521 if((marineStatusPointer->obstruction.environment)||(marineStatusPointer->obstruction.otherCharacter))
13522 {
13523 /* go to avoidance */
13524 GetNewRandomDirection(marineStatusPointer);
13525 TurnToFaceRandomDirection(marineStatusPointer,&(marineStatusPointer->wanderData.worldPosition));
13526 NPCSetVelocity(sbPtr, &(marineStatusPointer->wanderData.worldPosition), marineStatusPointer->nearSpeed);
13527 return(SRC_Request_Avoidance);
13528 }
13529 if(marineStatusPointer->obstruction.destructableObject)
13530 {
13531 LOCALASSERT(destructableObject);
13532 CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
13533 }
13534 }
13535 #endif
13536
13537 return(SRC_No_Change);
13538 }
13539
13540 void RunAroundOnFireMission_Control(STRATEGYBLOCK *sbPtr) {
13541
13542 MARINE_STATUS_BLOCK *marineStatusPointer;
13543 STATE_RETURN_CONDITION state_result;
13544 int marineIsNear;
13545
13546 LOCALASSERT(sbPtr);
13547 LOCALASSERT(sbPtr->containingModule);
13548 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
13549 LOCALASSERT(marineStatusPointer);
13550
13551 /* Current Behaviour. */
13552
13553 if(sbPtr->SBdptr) {
13554 marineIsNear=1;
13555 LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]);
13556 } else {
13557 marineIsNear=0;
13558 }
13559
13560 {
13561
13562 switch(marineStatusPointer->behaviourState)
13563 {
13564 case(MBS_Dying):
13565 {
13566 if ((ShowSquadState)||((sbPtr->SBdptr)&&(ShowNearSquad))) {
13567 PrintDebuggingText("RAOF marine dying in %s\n",sbPtr->containingModule->name);
13568 }
13569
13570 if (marineIsNear) {
13571 Execute_Dying(sbPtr);
13572 } else {
13573 Execute_Dying(sbPtr);
13574 }
13575 break;
13576 }
13577 default:
13578 {
13579 if ((ShowSquadState)||((sbPtr->SBdptr)&&(ShowNearSquad))) {
13580 PrintDebuggingText("RAOF marine running in %s\n",sbPtr->containingModule->name);
13581 }
13582
13583 if (marineIsNear) {
13584 state_result=Execute_MNS_RunAroundOnFire(sbPtr);
13585 } else {
13586 Execute_MFS_Wait(sbPtr);
13587 }
13588 break;
13589 }
13590 }
13591 }
13592
13593 if (!marineIsNear) {
13594
13595 /* check here to see if marine is in a proximity door - if so, trigger it to open. */
13596 {
13597 MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule);
13598
13599 if(doorType == MDT_ProxDoor)
13600 ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->SBdataptr)->marineTrigger = 1;
13601 }
13602
13603 /* lastly, do a containment test: to make sure that we are inside a module. */
13604 #if UseLocalAssert
13605 {
13606 VECTORCH localCoords;
13607 MODULE *thisModule = sbPtr->containingModule;
13608
13609 LOCALASSERT(thisModule);
13610
13611 localCoords = sbPtr->DynPtr->Position;
13612 localCoords.vx -= thisModule->m_world.vx;
13613 localCoords.vy -= thisModule->m_world.vy;
13614 localCoords.vz -= thisModule->m_world.vz;
13615
13616 if(PointIsInModule(thisModule, &localCoords)==0)
13617 {
13618 textprint("FAR MARINE MODULE CONTAINMENT FAILURE \n");
13619 LOCALASSERT(1==0);
13620 }
13621 }
13622 #endif
13623 }
13624
13625 }
13626
13627 void GetPointToFaceMarineTowards(STRATEGYBLOCK *sbPtr,VECTORCH *output) {
13628
13629 MARINE_STATUS_BLOCK *marineStatusPointer;
13630 AIMODULE *targetModule;
13631 AIMODULE **AdjModuleRefPtr;
13632 AIMODULE* chosenModule = NULL;
13633 VECTORCH chosenEpWorld;
13634 int numFound = 0;
13635
13636 LOCALASSERT(sbPtr);
13637 if (sbPtr->containingModule==NULL) {
13638 return;
13639 }
13640 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
13641 LOCALASSERT(marineStatusPointer);
13642
13643 /* First trap... are you suspicious? */
13644 if (marineStatusPointer->suspicious) {
13645 MODULE *suspect_module;
13646
13647 suspect_module=ModuleFromPosition(&marineStatusPointer->suspect_point,sbPtr->containingModule);
13648
13649 if (suspect_module==NULL) {
13650 /* Gordon Bennet. */
13651 *output = marineStatusPointer->suspect_point;
13652 marineStatusPointer->gotapoint=1;
13653 /* Congratulations. */
13654 return;
13655 }
13656
13657 /* In the same module? */
13658 if (sbPtr->containingModule->m_aimodule==suspect_module->m_aimodule) {
13659 *output = marineStatusPointer->suspect_point;
13660 marineStatusPointer->gotapoint=1;
13661 /* Congratulations. */
13662 return;
13663 }
13664
13665 /* Can you see the suspect point? */
13666 if (sbPtr->SBdptr!=NULL) {
13667 if (IsThisObjectVisibleFromThisPosition(sbPtr->SBdptr,&marineStatusPointer->suspect_point,NPC_MAX_VIEWRANGE)) {
13668 *output = marineStatusPointer->suspect_point;
13669 marineStatusPointer->gotapoint=1;
13670 /* Congratulations. */
13671 return;
13672 }
13673 }
13674
13675 {
13676 /* Try to face towards the most appropriate EP. */
13677 targetModule=GetNextModuleForLink(sbPtr->containingModule->m_aimodule,suspect_module->m_aimodule,7,0);
13678 if ((targetModule==NULL)||(targetModule==sbPtr->containingModule->m_aimodule)) {
13679 *output = marineStatusPointer->suspect_point;
13680 marineStatusPointer->gotapoint=1;
13681 /* Congratulations. */
13682 return;
13683 } else {
13684 /* Get the EP. */
13685 FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
13686 if(thisEp) {
13687 VECTORCH thisEpWorld = thisEp->position;
13688
13689 thisEpWorld.vx += targetModule->m_world.vx;
13690 thisEpWorld.vy += targetModule->m_world.vy;
13691 thisEpWorld.vz += targetModule->m_world.vz;
13692
13693 *output = thisEpWorld;
13694 marineStatusPointer->gotapoint=1;
13695 /* Congratulations. */
13696 return;
13697
13698 }
13699 /* Still here? Can't you get anything right? */
13700 *output = marineStatusPointer->suspect_point;
13701 marineStatusPointer->gotapoint=1;
13702 /* Congratulations. */
13703 return;
13704 }
13705 }
13706 }
13707
13708 /* We know your module, don't we? */
13709
13710 marineStatusPointer->gotapoint=0;
13711 targetModule=NULL;
13712
13713 /* Okay. If you're a guard, do your job. */
13714 if (marineStatusPointer->Mission==MM_Guard) {
13715
13716 *output = marineStatusPointer->my_facing_point;
13717 marineStatusPointer->gotapoint=1;
13718 /* Congratulations. */
13719 return;
13720 }
13721
13722 // SBF - 20080518 - commented out - this block of code is a NO-OP
13723 // due to the aliased targetModule variable. This code might have
13724 // been disabled intentionally? In any case, disabling this code
13725 // works around a crash in FarNPC_GetTargetAIModuleForMarineRespond
13726 // during level reloads.
13727 #if 0 // SBF - 20080518 - commented out
13728 if (NpcSquad.alertZone) {
13729 /* Might want to face towards trouble. */
13730 if (sbPtr->containingModule->m_aimodule!=NpcSquad.alertZone) {
13731 AIMODULE *targetModule=0;
13732 targetModule = FarNPC_GetTargetAIModuleForMarineRespond(sbPtr);
13733 }
13734 }
13735
13736 /* Did that work? */
13737
13738 if (targetModule) {
13739 FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule);
13740 if(thisEp) {
13741 VECTORCH thisEpWorld = thisEp->position;
13742
13743 thisEpWorld.vx += targetModule->m_world.vx;
13744 thisEpWorld.vy += targetModule->m_world.vy;
13745 thisEpWorld.vz += targetModule->m_world.vz;
13746
13747 *output = thisEpWorld;
13748 marineStatusPointer->gotapoint=1;
13749 /* Congratulations. */
13750 return;
13751
13752 }
13753 }
13754 #endif // SBF - 20080518 - commented out
13755
13756 AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs;
13757 /* check if there is a module adjacency list */
13758 if(!AdjModuleRefPtr) {
13759 /* Just be random, then. */
13760 return;
13761 }
13762
13763 if(!(*AdjModuleRefPtr)) {
13764 /* Just be random, then. */
13765 return;
13766 }
13767
13768 while(*AdjModuleRefPtr != 0)
13769 {
13770 AIMODULE *nextAdjModule = *AdjModuleRefPtr;
13771 if (((*(nextAdjModule->m_module_ptrs))->m_flags&MODULEFLAG_AIRDUCT)==0)
13772 {
13773 /* Overlook airducts :-) */
13774 FARENTRYPOINT *thisEp = GetAIModuleEP(nextAdjModule, sbPtr->containingModule->m_aimodule);
13775 if(thisEp)
13776 {
13777 if (thisEp->alien_only==0) {
13778 /* aha. an ep!... */
13779 VECTORCH thisEpWorld = thisEp->position;
13780
13781 thisEpWorld.vx += nextAdjModule->m_world.vx;
13782 thisEpWorld.vy += nextAdjModule->m_world.vy;
13783 thisEpWorld.vz += nextAdjModule->m_world.vz;
13784
13785 numFound++;
13786 if(FastRandom()%numFound==0)
13787 {
13788 /* take this one */
13789 chosenModule = nextAdjModule;
13790 chosenEpWorld = thisEpWorld;
13791 }
13792 }
13793 }
13794 }
13795 AdjModuleRefPtr++;
13796 }
13797
13798 if(chosenModule)
13799 {
13800 LOCALASSERT(numFound>=1);
13801 *output = chosenEpWorld;
13802 marineStatusPointer->gotapoint=1;
13803 /* Congratulations. */
13804 return;
13805 }
13806
13807 /* else... return? */
13808
13809 return;
13810 }
13811
13812 int MarineSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset,STRATEGYBLOCK *target) {
13813
13814 MARINE_STATUS_BLOCK *marineStatusPointer;
13815
13816 LOCALASSERT(sbPtr);
13817 LOCALASSERT(sbPtr->containingModule);
13818 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
13819 LOCALASSERT(marineStatusPointer);
13820
13821 if (marineStatusPointer->Target==NULL) {
13822 /* Chop off the top 45 degrees. */
13823 if ( (localOffset->vz <0) && (
13824 ((localOffset->vy-100)>=0)||(((localOffset->vy-100)<0)&&((-(localOffset->vy-100)) < (-localOffset->vz)))
13825 )) {
13826 /* 180 horizontal, 180 vertical. */
13827 return(1);
13828 } else {
13829 return(0);
13830 }
13831 } else if (marineStatusPointer->Target!=target) {
13832
13833 if ( (localOffset->vz <0)
13834 // && (localOffset->vz < (localOffset->vy+500))
13835 // && (localOffset->vz > -(localOffset->vy+500))
13836 ) {
13837 /* 180 horizontal, 180 vertical. */
13838 return(1);
13839 } else {
13840 return(0);
13841 }
13842 } else {
13843 /* Slightly different now, for error correction. */
13844 if (localOffset->vz <0) {
13845 return(1);
13846 } else {
13847 /* 270 horizontal, 180 vertical. */
13848 if ( ((localOffset->vx>0)&&(localOffset->vx<localOffset->vz))
13849 ||((localOffset->vx<0)&&((-localOffset->vx)<localOffset->vz)) ) {
13850 return(0);
13851 } else {
13852 return(1);
13853 }
13854 }
13855 }
13856 }
13857
13858 int Marine_SoundInterest(SOUNDINDEX soundIndex) {
13859
13860 /* Returns 0->ONE_FIXED scale. 0 is ignored. Otherwise, larger value means
13861 lower priority. */
13862
13863 switch (soundIndex) {
13864 case SID_ALIEN_HISS:
13865 case SID_ALIEN_HISS1:
13866 case SID_ALIEN_SCREAM:
13867 case SID_SWIPE:
13868 case SID_SWISH:
13869 case SID_TAIL:
13870 case SID_PRED_LAUNCHER:
13871 case SID_PRED_FRISBEE:
13872 case SID_PRED_PISTOL:
13873 case SID_PRED_SNARL:
13874 case SID_PRED_SCREAM1:
13875 case SID_PRED_LASER:
13876 case SID_SWIPE2:
13877 case SID_SWIPE3:
13878 case SID_SWIPE4:
13879 case SID_PRED_HISS:
13880 case SID_HIT_FLESH:
13881 case SID_ALIEN_HIT:
13882 case SID_ALIEN_KILL:
13883 case SID_FHUG_ATTACKLOOP:
13884 case SID_FHUG_MOVE:
13885 case SID_BUGDIE1:
13886 case SID_BUGDIE2:
13887 case SID_BUGDIE3:
13888 case SID_MARINE_DEATH1:
13889 case SID_MARINE_DEATH2:
13890 case SID_PRED_LOUDROAR:
13891 case SID_MARINE_HIT:
13892 case SID_ALIEN_HIT2:
13893 case SID_PRED_SHORTROAR:
13894 case SID_PRED_SLASH:
13895 case SID_RIP:
13896 case SID_PRED_NEWROAR:
13897 case SID_PLASMABOLT_DISSIPATE:
13898 case SID_PLASMABOLT_HIT:
13899 case SID_ALIEN_JAW_ATTACK:
13900 case SID_BODY_BEING_HACKED_UP_0:
13901 case SID_BODY_BEING_HACKED_UP_1:
13902 case SID_BODY_BEING_HACKED_UP_2:
13903 case SID_BODY_BEING_HACKED_UP_3:
13904 case SID_BODY_BEING_HACKED_UP_4:
13905 case SID_PREDATOR_PICKUP_FIELDCHARGE:
13906 case SID_PREDATOR_PICKUP_WEAPON:
13907 case SID_PREDATOR_CLOAKING_ACTIVE:
13908 case SID_PREDATOR_CLOAKING_DAMAGED:
13909 case SID_PREDATOR_SPEARGUN_EMPTY:
13910 case SID_PREDATOR_PLASMACASTER_TARGET_FOUND:
13911 case SID_PREDATOR_PLASMACASTER_TARGET_LOCKED:
13912 case SID_PREDATOR_PLASMACASTER_TARGET_LOST:
13913 case SID_PREDATOR_PLASMACASTER_CHARGING:
13914 case SID_PREDATOR_PLASMACASTER_EMPTY:
13915 case SID_PREDATOR_DISK_TARGET_LOCKED:
13916 case SID_PREDATOR_DISK_FLYING:
13917 case SID_PREDATOR_DISK_HITTING_TARGET:
13918 case SID_PREDATOR_DISK_HITTING_WALL:
13919 case SID_PREDATOR_DISK_BEING_CAUGHT:
13920 case SID_PREDATOR_DISK_RECOVERED:
13921 case SID_PREDATOR_VOCAL_SNARL_1:
13922 case SID_PREDATOR_VOCAL_SNARL_2:
13923 case SID_ALIEN_TAILUNFURL:
13924 case SID_ALIEN_TAUNT_1:
13925 case SID_ALIEN_TAUNT_2:
13926 case SID_PRED_JUMP_START_1:
13927 case SID_PRED_JUMP_START_2:
13928 case SID_PRED_JUMP_START_3:
13929 case SID_PRED_CLOAKON:
13930 case SID_PRED_CLOAKOFF:
13931 case SID_PRED_SMALLLANDING:
13932 case SID_ED_FACEHUGGERSLAP:
13933 case SID_GRAPPLE_HIT_WALL:
13934 case SID_GRAPPLE_THROW:
13935 case SID_ED_ELEC_DEATH:
13936 /* Enemy sounds. */
13937 return(ONE_FIXED>>2);
13938 break;
13939 case SID_SWITCH1:
13940 case SID_SWITCH2:
13941 case SID_PULSE_START:
13942 case SID_PULSE_LOOP:
13943 case SID_PULSE_END:
13944 case SID_LIFT_START:
13945 case SID_LIFT_LOOP:
13946 case SID_LIFT_END:
13947 case SID_VISION_ON:
13948 case SID_VISION_LOOP:
13949 case SID_FIRE:
13950 case SID_PICKUP:
13951 case SID_SPLASH1:
13952 case SID_SPLASH2:
13953 case SID_SPLASH3:
13954 case SID_SPLASH4:
13955 case SID_POWERUP:
13956 case SID_POWERDN:
13957 case SID_ACID_SPRAY:
13958 case SID_DOORSTART:
13959 case SID_DOORMID:
13960 case SID_DOOREND:
13961 case SID_BORGON:
13962 case SID_SPARKS:
13963 case SID_STOMP:
13964 case SID_LOADMOVE:
13965 case SID_NOAMMO:
13966 case SID_LONGLOAD:
13967 case SID_NADELOAD:
13968 case SID_NADEFIRE:
13969 case SID_NADEEXPLODE:
13970 case SID_SHRTLOAD:
13971 case SID_INCIN_START:
13972 case SID_INCIN_LOOP:
13973 case SID_INCIN_END:
13974 case SID_ROCKFIRE:
13975 case SID_SHOTGUN:
13976 case SID_SMART1:
13977 case SID_SMART2:
13978 case SID_SMART3:
13979 case SID_SENTRY_GUN:
13980 case SID_SENTRY_END:
13981 case SID_NICE_EXPLOSION:
13982 case SID_EXPLOSION:
13983 case SID_MINIGUN_END:
13984 case SID_MINIGUN_LOOP:
13985 case SID_FRAG_RICOCHETS:
13986 case SID_SPEARGUN_HITTING_WALL:
13987 case SID_DISC_STICKSINWALL:
13988 case SID_PREDATOR_PLASMACASTER_REDTRIANGLES:
13989 case SID_WIL_PRED_PISTOL_EXPLOSION:
13990 case SID_PROX_GRENADE_READYTOBLOW:
13991 case SID_PROX_GRENADE_ACTIVE:
13992 case SID_ED_GRENADE_EXPLOSION:
13993 case SID_ED_GRENADE_PROXEXPLOSION:
13994 case SID_ED_MOLOTOV_EXPLOSION:
13995 case SID_SENTRYGUNDEST:
13996 return(ONE_FIXED);
13997 break;
13998 case SID_ARMSTART:
13999 case SID_ARMMID:
14000 case SID_ARMEND:
14001 case SID_TRACKER_CLICK:
14002 case SID_TRACKER_WHEEP:
14003 case SID_RICOCH1:
14004 case SID_RICOCH2:
14005 case SID_RICOCH3:
14006 case SID_RICOCH4:
14007 case SID_TELETEXT:
14008 case SID_TRACKER_WHEEP_HIGH:
14009 case SID_TRACKER_WHEEP_LOW:
14010 case SID_PULSE_RIFLE_FIRING_EMPTY:
14011 case SID_THROW_FLARE:
14012 case SID_CONSOLE_ACTIVATES:
14013 case SID_CONSOLE_DEACTIVATES:
14014 case SID_CONSOLE_MARINEMESSAGE:
14015 case SID_CONSOLE_ALIENMESSAGE:
14016 case SID_CONSOLE_PREDATORMESSAGE:
14017 case SID_MINIGUN_READY:
14018 case SID_MINIGUN_EMPTY:
14019 case SID_SMART_MODESWITCH:
14020 case SID_GRENADE_BOUNCE:
14021 case SID_BURNING_FLARE:
14022 case SID_FLAMETHROWER_PILOT_LIGHT:
14023 case SID_MARINE_JUMP_START:
14024 case SID_MARINE_JUMP_END:
14025 case SID_MARINE_PICKUP_WEAPON:
14026 case SID_MARINE_PICKUP_AMMO:
14027 case SID_MARINE_PICKUP_ARMOUR:
14028 case SID_SENTRYGUN_LOCK:
14029 case SID_SENTRYGUN_SHUTDOWN:
14030 case SID_WIL_MINIGUN_READY:
14031 case SID_SADAR_FIRE:
14032 case SID_MARINE_JUMP_START_2:
14033 case SID_MARINE_JUMP_START_3:
14034 case SID_MARINE_JUMP_START_4:
14035 case SID_ED_LARGEWEAPONDROP:
14036 case SID_MENUS_SELECT_ITEM:
14037 case SID_MENUS_CHANGE_ITEM:
14038 case SID_PRED_ZOOM_IN:
14039 case SID_PRED_ZOOM_OUT:
14040 case SID_MARINE_SMALLLANDING:
14041 case SID_LIGHT_FLICKER_ON:
14042 case SID_ED_SENTRYTURN01:
14043 case SID_PULSE_SWIPE01:
14044 case SID_PULSE_SWIPE02:
14045 case SID_PULSE_SWIPE03:
14046 case SID_PULSE_SWIPE04:
14047 case SID_ED_JETPACK_START:
14048 case SID_ED_JETPACK_MID:
14049 case SID_ED_JETPACK_END:
14050 case SID_IMAGE:
14051 case SID_IMAGE_OFF:
14052 /* Basic marine sounds, and the sentrygun. */
14053 return(0);
14054 break;
14055 case SID_STARTOF_LOADSLOTS:
14056 case SID_UNUSED_125:
14057 case SID_UNUSED_126:
14058 case SID_UNUSED_127:
14059 case SID_UNUSED_128:
14060 case SID_UNUSED_129:
14061 case SID_UNUSED_130:
14062 case SID_UNUSED_131:
14063 case SID_UNUSED_132:
14064 case SID_UNUSED_133:
14065 case SID_UNUSED_134:
14066 case SID_UNUSED_135:
14067 case SID_UNUSED_136:
14068 case SID_UNUSED_137:
14069 case SID_UNUSED_138:
14070 case SID_UNUSED_139:
14071 case SID_UNUSED_140:
14072 case SID_UNUSED_141:
14073 case SID_UNUSED_142:
14074 case SID_UNUSED_143:
14075 case SID_UNUSED_144:
14076 case SID_UNUSED_145:
14077 case SID_UNUSED_146:
14078 case SID_UNUSED_147:
14079 case SID_UNUSED_148:
14080 case SID_UNUSED_149:
14081 case SID_ENDOF_LOADSLOTS:
14082 /* Environment sounds. */
14083 return(ONE_FIXED<<1);
14084 break;
14085 default:
14086 /* Eh? Could be a scream... */
14087 return(ONE_FIXED<<1);
14088 break;
14089 }
14090
14091 }
14092
14093 int Marine_SoundCourageBonus(SOUNDINDEX soundIndex) {
14094
14095 /* Returns a FRI value. + is GOOD! */
14096
14097 switch (soundIndex) {
14098 case SID_ALIEN_HISS:
14099 case SID_ALIEN_HISS1:
14100 case SID_ALIEN_SCREAM:
14101 case SID_SWIPE:
14102 case SID_SWISH:
14103 case SID_TAIL:
14104 case SID_PRED_LAUNCHER:
14105 case SID_PRED_FRISBEE:
14106 case SID_PRED_PISTOL:
14107 case SID_PRED_SNARL:
14108 case SID_PRED_SCREAM1:
14109 case SID_PRED_LASER:
14110 case SID_SWIPE2:
14111 case SID_SWIPE3:
14112 case SID_SWIPE4:
14113 case SID_PRED_HISS:
14114 case SID_HIT_FLESH:
14115 case SID_ALIEN_HIT:
14116 case SID_ALIEN_KILL:
14117 case SID_FHUG_ATTACKLOOP:
14118 case SID_FHUG_MOVE:
14119 case SID_BUGDIE1:
14120 case SID_BUGDIE2:
14121 case SID_BUGDIE3:
14122 case SID_MARINE_DEATH1:
14123 case SID_MARINE_DEATH2:
14124 case SID_PRED_LOUDROAR:
14125 case SID_MARINE_HIT:
14126 case SID_ALIEN_HIT2:
14127 case SID_PRED_SHORTROAR:
14128 case SID_PRED_SLASH:
14129 case SID_RIP:
14130 case SID_PRED_NEWROAR:
14131 case SID_PLASMABOLT_DISSIPATE:
14132 case SID_PLASMABOLT_HIT:
14133 case SID_ALIEN_JAW_ATTACK:
14134 case SID_BODY_BEING_HACKED_UP_0:
14135 case SID_BODY_BEING_HACKED_UP_1:
14136 case SID_BODY_BEING_HACKED_UP_2:
14137 case SID_BODY_BEING_HACKED_UP_3:
14138 case SID_BODY_BEING_HACKED_UP_4:
14139 case SID_PREDATOR_PICKUP_FIELDCHARGE:
14140 case SID_PREDATOR_PICKUP_WEAPON:
14141 case SID_PREDATOR_CLOAKING_ACTIVE:
14142 case SID_PREDATOR_CLOAKING_DAMAGED:
14143 case SID_PREDATOR_SPEARGUN_EMPTY:
14144 case SID_PREDATOR_PLASMACASTER_TARGET_FOUND:
14145 case SID_PREDATOR_PLASMACASTER_TARGET_LOCKED:
14146 case SID_PREDATOR_PLASMACASTER_TARGET_LOST:
14147 case SID_PREDATOR_PLASMACASTER_CHARGING:
14148 case SID_PREDATOR_PLASMACASTER_EMPTY:
14149 case SID_PREDATOR_DISK_TARGET_LOCKED:
14150 case SID_PREDATOR_DISK_FLYING:
14151 case SID_PREDATOR_DISK_HITTING_TARGET:
14152 case SID_PREDATOR_DISK_HITTING_WALL:
14153 case SID_PREDATOR_DISK_BEING_CAUGHT:
14154 case SID_PREDATOR_DISK_RECOVERED:
14155 case SID_PREDATOR_VOCAL_SNARL_1:
14156 case SID_PREDATOR_VOCAL_SNARL_2:
14157 case SID_ALIEN_TAILUNFURL:
14158 case SID_ALIEN_TAUNT_1:
14159 case SID_ALIEN_TAUNT_2:
14160 case SID_PRED_JUMP_START_1:
14161 case SID_PRED_JUMP_START_2:
14162 case SID_PRED_JUMP_START_3:
14163 case SID_PRED_CLOAKON:
14164 case SID_PRED_CLOAKOFF:
14165 case SID_PRED_SMALLLANDING:
14166 case SID_ED_FACEHUGGERSLAP:
14167 case SID_GRAPPLE_HIT_WALL:
14168 case SID_GRAPPLE_THROW:
14169 case SID_ED_ELEC_DEATH:
14170 /* Enemy sounds! */
14171 return(MUL_FIXED(NormalFrameTime,-3000));
14172 break;
14173 case SID_MINIGUN_END:
14174 case SID_MINIGUN_LOOP:
14175 case SID_INCIN_START:
14176 case SID_INCIN_LOOP:
14177 case SID_INCIN_END:
14178 case SID_ROCKFIRE:
14179 case SID_PULSE_START:
14180 case SID_PULSE_LOOP:
14181 case SID_PULSE_END:
14182 case SID_SHOTGUN:
14183 case SID_SMART1:
14184 case SID_SMART2:
14185 case SID_SMART3:
14186 case SID_TRACKER_WHEEP_HIGH:
14187 case SID_TRACKER_WHEEP_LOW:
14188 case SID_PULSE_RIFLE_FIRING_EMPTY:
14189 case SID_THROW_FLARE:
14190 case SID_CONSOLE_ACTIVATES:
14191 case SID_CONSOLE_DEACTIVATES:
14192 case SID_CONSOLE_MARINEMESSAGE:
14193 case SID_CONSOLE_ALIENMESSAGE:
14194 case SID_CONSOLE_PREDATORMESSAGE:
14195 case SID_MINIGUN_READY:
14196 case SID_MINIGUN_EMPTY:
14197 case SID_SMART_MODESWITCH:
14198 case SID_GRENADE_BOUNCE:
14199 case SID_BURNING_FLARE:
14200 case SID_FLAMETHROWER_PILOT_LIGHT:
14201 case SID_MARINE_JUMP_START:
14202 case SID_MARINE_JUMP_END:
14203 case SID_MARINE_PICKUP_WEAPON:
14204 case SID_MARINE_PICKUP_AMMO:
14205 case SID_MARINE_PICKUP_ARMOUR:
14206 case SID_SENTRYGUN_LOCK:
14207 case SID_SENTRYGUN_SHUTDOWN:
14208 case SID_WIL_MINIGUN_READY:
14209 case SID_SADAR_FIRE:
14210 case SID_MARINE_JUMP_START_2:
14211 case SID_MARINE_JUMP_START_3:
14212 case SID_MARINE_JUMP_START_4:
14213 case SID_ED_GRENADE_EXPLOSION:
14214 case SID_ED_GRENADE_PROXEXPLOSION:
14215 case SID_ED_MOLOTOV_EXPLOSION:
14216 case SID_ED_LARGEWEAPONDROP:
14217 case SID_MENUS_SELECT_ITEM:
14218 case SID_MENUS_CHANGE_ITEM:
14219 case SID_IMAGE:
14220 case SID_IMAGE_OFF:
14221 /* Marine type sounds. */
14222 return(MUL_FIXED(NormalFrameTime,300));
14223 break;
14224 case SID_SWITCH1:
14225 case SID_SWITCH2:
14226 case SID_LIFT_START:
14227 case SID_LIFT_LOOP:
14228 case SID_LIFT_END:
14229 case SID_VISION_ON:
14230 case SID_VISION_LOOP:
14231 case SID_FIRE:
14232 case SID_PICKUP:
14233 case SID_SPLASH1:
14234 case SID_SPLASH2:
14235 case SID_SPLASH3:
14236 case SID_SPLASH4:
14237 case SID_POWERUP:
14238 case SID_POWERDN:
14239 case SID_ACID_SPRAY:
14240 case SID_DOORSTART:
14241 case SID_DOORMID:
14242 case SID_DOOREND:
14243 case SID_BORGON:
14244 case SID_SPARKS:
14245 case SID_STOMP:
14246 case SID_LOADMOVE:
14247 case SID_NOAMMO:
14248 case SID_LONGLOAD:
14249 case SID_NADELOAD:
14250 case SID_NADEFIRE:
14251 case SID_NADEEXPLODE:
14252 case SID_SHRTLOAD:
14253 case SID_SENTRY_GUN:
14254 case SID_SENTRY_END:
14255 case SID_NICE_EXPLOSION:
14256 case SID_EXPLOSION:
14257 case SID_FRAG_RICOCHETS:
14258 case SID_SPEARGUN_HITTING_WALL:
14259 case SID_DISC_STICKSINWALL:
14260 case SID_PREDATOR_PLASMACASTER_REDTRIANGLES:
14261 case SID_WIL_PRED_PISTOL_EXPLOSION:
14262 case SID_PROX_GRENADE_READYTOBLOW:
14263 case SID_PROX_GRENADE_ACTIVE:
14264 case SID_SENTRYGUNDEST:
14265 /* Weird sounds. */
14266 return(ONE_FIXED);
14267 break;
14268 case SID_ARMSTART:
14269 case SID_ARMMID:
14270 case SID_ARMEND:
14271 case SID_TRACKER_CLICK:
14272 case SID_TRACKER_WHEEP:
14273 case SID_TELETEXT:
14274 case SID_RICOCH1:
14275 case SID_RICOCH2:
14276 case SID_RICOCH3:
14277 case SID_RICOCH4:
14278 case SID_NOSOUND:
14279 case SID_PRED_ZOOM_IN:
14280 case SID_PRED_ZOOM_OUT:
14281 case SID_MARINE_SMALLLANDING:
14282 case SID_LIGHT_FLICKER_ON:
14283 case SID_ED_SENTRYTURN01:
14284 case SID_PULSE_SWIPE01:
14285 case SID_PULSE_SWIPE02:
14286 case SID_PULSE_SWIPE03:
14287 case SID_PULSE_SWIPE04:
14288 case SID_ED_JETPACK_START:
14289 case SID_ED_JETPACK_MID:
14290 case SID_ED_JETPACK_END:
14291 /* Basic marine sounds, and the sentrygun. */
14292 return(0);
14293 break;
14294 case SID_STARTOF_LOADSLOTS:
14295 case SID_UNUSED_125:
14296 case SID_UNUSED_126:
14297 case SID_UNUSED_127:
14298 case SID_UNUSED_128:
14299 case SID_UNUSED_129:
14300 case SID_UNUSED_130:
14301 case SID_UNUSED_131:
14302 case SID_UNUSED_132:
14303 case SID_UNUSED_133:
14304 case SID_UNUSED_134:
14305 case SID_UNUSED_135:
14306 case SID_UNUSED_136:
14307 case SID_UNUSED_137:
14308 case SID_UNUSED_138:
14309 case SID_UNUSED_139:
14310 case SID_UNUSED_140:
14311 case SID_UNUSED_141:
14312 case SID_UNUSED_142:
14313 case SID_UNUSED_143:
14314 case SID_UNUSED_144:
14315 case SID_UNUSED_145:
14316 case SID_UNUSED_146:
14317 case SID_UNUSED_147:
14318 case SID_UNUSED_148:
14319 case SID_UNUSED_149:
14320 case SID_ENDOF_LOADSLOTS:
14321 /* Environment sounds. */
14322 return(MUL_FIXED(NormalFrameTime,-300));
14323 break;
14324 default:
14325 /* Eh? Could be a scream... */
14326 return(MUL_FIXED(NormalFrameTime,-1500));
14327 break;
14328 }
14329
14330 }
14331
14332 void DoMarineHearing(STRATEGYBLOCK *sbPtr) {
14333
14334 int a,nearest,neardist,dist,priority;
14335 MARINE_STATUS_BLOCK *marineStatusPointer;
14336 VECTORCH offset;
14337
14338 LOCALASSERT(sbPtr);
14339 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14340 LOCALASSERT(marineStatusPointer);
14341
14342 #if 0
14343 /* Hearing is low priority. */
14344 if (marineStatusPointer->suspicious) {
14345 return;
14346 }
14347 #endif
14348
14349 nearest=-1;
14350 neardist=10000000;
14351 /* Hence, if you're still interested in something else, return. */
14352
14353 for(a=0;a<SOUND_MAXACTIVE;a++)
14354 {
14355 /* Ignore sounds with no position. */
14356 if ((ActiveSounds[a].threedee)&&(ActiveSounds[a].loop==0)&&(ActiveSounds[a].marine_ignore==0)
14357 &&(ActiveSounds[a].soundIndex!=SID_NOSOUND)) {
14358 priority=Marine_SoundInterest(ActiveSounds[a].soundIndex);
14359 if (marineStatusPointer->Android==0) {
14360 marineStatusPointer->Courage+=Marine_SoundCourageBonus(ActiveSounds[a].soundIndex);
14361 }
14362 if (priority) {
14363 int test_dist;
14364 /* Interesting sound... */
14365 offset.vx=sbPtr->DynPtr->Position.vx-ActiveSounds[a].threedeedata.position.vx;
14366 offset.vy=sbPtr->DynPtr->Position.vy-ActiveSounds[a].threedeedata.position.vy;
14367 offset.vz=sbPtr->DynPtr->Position.vz-ActiveSounds[a].threedeedata.position.vz;
14368
14369 dist=Approximate3dMagnitude(&offset);
14370
14371 if (ActiveSounds[a].threedeedata.outer_range==-1) {
14372 test_dist=100000;
14373 /* 100 m. */
14374 } else {
14375 test_dist=ActiveSounds[a].threedeedata.outer_range;
14376 }
14377
14378 if (dist<=test_dist) {
14379 /* In range. Modify by priority. */
14380 dist=MUL_FIXED(dist,priority);
14381
14382 if (dist<neardist) {
14383 /* Got one! */
14384 nearest=a;
14385 neardist=dist;
14386 }
14387 }
14388 }
14389 }
14390 }
14391
14392 /* Finally, test the player. */
14393 {
14394 extern int playerNoise;
14395
14396 if (playerNoise) {
14397
14398 offset.vx=sbPtr->DynPtr->Position.vx-Player->ObStrategyBlock->DynPtr->Position.vx;
14399 offset.vy=sbPtr->DynPtr->Position.vy-Player->ObStrategyBlock->DynPtr->Position.vy;
14400 offset.vz=sbPtr->DynPtr->Position.vz-Player->ObStrategyBlock->DynPtr->Position.vz;
14401
14402 dist=Approximate3dMagnitude(&offset);
14403
14404 if (dist<=100000) {
14405 /* In range. Assume priority is ONE_FIXED. */
14406 if (dist<neardist) {
14407 /* Got one! */
14408 nearest=-2;
14409 neardist=dist;
14410 }
14411 }
14412
14413 }
14414 }
14415
14416 if (nearest!=-1) {
14417 int level,priority;
14418
14419 if (nearest==-2) {
14420 /* Heard the player! */
14421
14422 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
14423 marineStatusPointer->suspect_point=Player->ObStrategyBlock->DynPtr->Position;
14424 /* Set this to zero when you get a *new* suspicion. */
14425 marineStatusPointer->previous_suspicion=0;
14426 marineStatusPointer->using_squad_suspicion=0;
14427
14428 level=2;
14429
14430 } else {
14431
14432 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
14433 marineStatusPointer->suspect_point=ActiveSounds[nearest].threedeedata.position;
14434 /* Set this to zero when you get a *new* suspicion. */
14435 marineStatusPointer->previous_suspicion=0;
14436 marineStatusPointer->using_squad_suspicion=0;
14437
14438 priority=Marine_SoundInterest(ActiveSounds[nearest].soundIndex);
14439 if (priority>ONE_FIXED) {
14440 level=1;
14441 } else if (priority<ONE_FIXED) {
14442 level=3;
14443 } else {
14444 level=2;
14445 }
14446
14447 }
14448
14449 PointAlert(level,&marineStatusPointer->suspect_point);
14450 }
14451
14452 }
14453
14454 static STATE_RETURN_CONDITION Execute_MNS_Taunting(STRATEGYBLOCK *sbPtr)
14455 {
14456
14457 MARINE_STATUS_BLOCK *marineStatusPointer;
14458
14459 LOCALASSERT(sbPtr);
14460 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14461 LOCALASSERT(marineStatusPointer);
14462
14463 /* zero velocity */
14464 LOCALASSERT(sbPtr->DynPtr);
14465 sbPtr->DynPtr->LinVelocity.vx = 0;
14466 sbPtr->DynPtr->LinVelocity.vy = 0;
14467 sbPtr->DynPtr->LinVelocity.vz = 0;
14468
14469 if (!sbPtr->SBdptr) {
14470 /* We're far... do the timer! */
14471 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
14472 }
14473
14474 if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) {
14475 return(SRC_Request_Wait);
14476 } else {
14477 return(SRC_No_Change);
14478 }
14479
14480 }
14481
14482 static STATE_RETURN_CONDITION Execute_MNS_Reloading(STRATEGYBLOCK *sbPtr)
14483 {
14484
14485 MARINE_STATUS_BLOCK *marineStatusPointer;
14486
14487 LOCALASSERT(sbPtr);
14488 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14489 LOCALASSERT(marineStatusPointer);
14490
14491 /* zero velocity */
14492 LOCALASSERT(sbPtr->DynPtr);
14493 sbPtr->DynPtr->LinVelocity.vx = 0;
14494 sbPtr->DynPtr->LinVelocity.vy = 0;
14495 sbPtr->DynPtr->LinVelocity.vz = 0;
14496
14497 if (!sbPtr->SBdptr) {
14498 /* We're far... do the timer! */
14499 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
14500 }
14501
14502 /* Clip management. */
14503 if (marineStatusPointer->My_Weapon->ClipName) {
14504 SECTION_DATA *clip;
14505 clip=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ClipName);
14506 if (clip) {
14507 /* Now, check keyframe flags. */
14508 if (marineStatusPointer->HModelController.keyframe_flags&4) {
14509 /* Vanish it. */
14510 clip->flags|=(section_data_terminate_here|section_data_notreal);
14511 }
14512
14513 if (marineStatusPointer->HModelController.keyframe_flags&1) {
14514 /* Trim it off. */
14515 MakeHierarchicalDebris(NULL,clip, &clip->World_Offset, &clip->SecMat,NULL,0);
14516 }
14517
14518 if (marineStatusPointer->HModelController.keyframe_flags&2) {
14519 /* Put it back. */
14520 if ((marineStatusPointer->My_Weapon->id==MNPCW_SADAR)
14521 ||(marineStatusPointer->My_Weapon->id==MNPCW_Skeeter)) {
14522 SECTION *root_section;
14523 /* Heaven help us. */
14524 clip->flags&=(~(section_data_terminate_here|section_data_notreal));
14525
14526 root_section=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->HierarchyName);
14527 GLOBALASSERT(root_section);
14528
14529 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root_section,0,1,1);
14530 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
14531 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName);
14532 marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection);
14533 } else {
14534 clip->flags&=(~(section_data_terminate_here|section_data_notreal));
14535 }
14536 }
14537 }
14538 }
14539
14540 if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) {
14541 marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size;
14542 return(SRC_Request_Approach);
14543 } else {
14544 return(SRC_No_Change);
14545 }
14546
14547 }
14548
14549 static STATE_RETURN_CONDITION Execute_MNS_PanicReloading(STRATEGYBLOCK *sbPtr)
14550 {
14551
14552 MARINE_STATUS_BLOCK *marineStatusPointer;
14553
14554 LOCALASSERT(sbPtr);
14555 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14556 LOCALASSERT(marineStatusPointer);
14557
14558 /* zero velocity */
14559 LOCALASSERT(sbPtr->DynPtr);
14560 sbPtr->DynPtr->LinVelocity.vx = 0;
14561 sbPtr->DynPtr->LinVelocity.vy = 0;
14562 sbPtr->DynPtr->LinVelocity.vz = 0;
14563
14564 if (!sbPtr->SBdptr) {
14565 /* We're far... do the timer! */
14566 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
14567 }
14568
14569 /* Scream handling. */
14570 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
14571 if (marineStatusPointer->incidentFlag) {
14572 if (Marine_HasHisMouthOpen(sbPtr)) {
14573 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
14574 Marine_PanicScream(sbPtr);
14575 } else {
14576 Marine_AngryScream(sbPtr);
14577 }
14578 } else {
14579 /* Scream anyway? */
14580 Marine_PanicScream(sbPtr);
14581 /* Open the mouth? */
14582 Marine_AssumePanicExpression(sbPtr);
14583 }
14584 }
14585 }
14586
14587 /* Clip management. */
14588 if (marineStatusPointer->My_Weapon->ClipName) {
14589 SECTION_DATA *clip;
14590 clip=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ClipName);
14591 if (clip) {
14592 /* Now, check keyframe flags. */
14593 if (marineStatusPointer->HModelController.keyframe_flags&4) {
14594 /* Vanish it. */
14595 clip->flags|=(section_data_terminate_here|section_data_notreal);
14596 }
14597
14598 if (marineStatusPointer->HModelController.keyframe_flags&1) {
14599 /* Trim it off. */
14600 MakeHierarchicalDebris(NULL,clip, &clip->World_Offset, &clip->SecMat,NULL,0);
14601 }
14602
14603 if (marineStatusPointer->HModelController.keyframe_flags&2) {
14604 /* Put it back. */
14605 if (marineStatusPointer->My_Weapon->id==MNPCW_SADAR) {
14606 SECTION *root_section;
14607 /* Heaven help us. */
14608 clip->flags&=(~(section_data_terminate_here|section_data_notreal));
14609
14610 root_section=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->HierarchyName);
14611 GLOBALASSERT(root_section);
14612
14613 Transmogrify_HModels(sbPtr,&marineStatusPointer->HModelController,root_section,0,1,1);
14614 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
14615 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName);
14616 marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection);
14617 } else {
14618 clip->flags&=(~(section_data_terminate_here|section_data_notreal));
14619 }
14620 }
14621 }
14622 }
14623
14624 if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) {
14625 marineStatusPointer->clipammo=marineStatusPointer->My_Weapon->clip_size;
14626 return(SRC_Request_Approach);
14627 } else {
14628 return(SRC_No_Change);
14629 }
14630
14631 }
14632
14633 static STATE_RETURN_CONDITION Execute_MNS_GetWeapon(STRATEGYBLOCK *sbPtr)
14634 {
14635
14636 MARINE_STATUS_BLOCK *marineStatusPointer;
14637
14638 LOCALASSERT(sbPtr);
14639 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14640 LOCALASSERT(marineStatusPointer);
14641
14642 /* zero velocity */
14643 LOCALASSERT(sbPtr->DynPtr);
14644 sbPtr->DynPtr->LinVelocity.vx = 0;
14645 sbPtr->DynPtr->LinVelocity.vy = 0;
14646 sbPtr->DynPtr->LinVelocity.vz = 0;
14647
14648 if (!sbPtr->SBdptr) {
14649 /* We're far... do the timer! */
14650 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
14651 }
14652
14653 if (HModelAnimation_IsFinished(&marineStatusPointer->HModelController)) {
14654 return(SRC_Request_Wait);
14655 } else {
14656 return(SRC_No_Change);
14657 }
14658
14659 }
14660
14661 int NPCFireMinigun_Core(STRATEGYBLOCK *sbPtr) {
14662
14663 MARINE_STATUS_BLOCK *marineStatusPointer;
14664
14665 LOCALASSERT(sbPtr);
14666 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14667 LOCALASSERT(marineStatusPointer);
14668
14669 marineStatusPointer->weapon_variable+=(NormalFrameTime<<7);
14670
14671 if (marineStatusPointer->weapon_variable>=MINIGUN_MAX_SPEED) {
14672
14673 marineStatusPointer->weapon_variable=MINIGUN_MAX_SPEED;
14674
14675 /* Fire! */
14676 DischargeLOSWeapon_Core(sbPtr);
14677
14678 return(1);
14679 }
14680
14681 /* Maintain_Minigun called anyway. */
14682
14683 return(0);
14684
14685 }
14686
14687
14688 void NPC_Maintain_Minigun(STRATEGYBLOCK *sbPtr, DELTA_CONTROLLER *mgd) {
14689
14690 MARINE_STATUS_BLOCK *marineStatusPointer;
14691
14692 LOCALASSERT(sbPtr);
14693 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14694 LOCALASSERT(marineStatusPointer);
14695
14696 if (mgd==NULL) {
14697 return;
14698 }
14699
14700 if ((marineStatusPointer->behaviourState!=MBS_Firing)
14701 ||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)
14702 ||(marineStatusPointer->HModelController.Playing==0)) {
14703 /* Not firing. */
14704 marineStatusPointer->weapon_variable-=(NormalFrameTime<<3);
14705 if (marineStatusPointer->weapon_variable<MINIGUN_IDLE_SPEED) {
14706 marineStatusPointer->weapon_variable=MINIGUN_IDLE_SPEED;
14707 }
14708 }
14709
14710 if (marineStatusPointer->weapon_variable!=marineStatusPointer->weapon_variable2) {
14711 int hmspinrate;
14712
14713 if (marineStatusPointer->weapon_variable) {
14714
14715 hmspinrate=DIV_FIXED(ONE_FIXED,marineStatusPointer->weapon_variable);
14716
14717 Delta_Sequence_ChangeSpeed(mgd,hmspinrate);
14718 mgd->Playing=1;
14719 } else {
14720 mgd->Playing=0;
14721 }
14722 }
14723
14724 marineStatusPointer->weapon_variable2=marineStatusPointer->weapon_variable;
14725
14726 }
14727
14728 static STATE_RETURN_CONDITION Execute_MNS_DischargeMinigun(STRATEGYBLOCK *sbPtr)
14729 {
14730 MARINE_STATUS_BLOCK *marineStatusPointer;
14731 VECTORCH orientationDirn,relPos,relPos2;
14732 int correctlyOrientated,range;
14733
14734 LOCALASSERT(sbPtr);
14735 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14736 LOCALASSERT(marineStatusPointer);
14737
14738 /* zero velocity */
14739 LOCALASSERT(sbPtr->DynPtr);
14740 sbPtr->DynPtr->LinVelocity.vx = 0;
14741 sbPtr->DynPtr->LinVelocity.vy = 0;
14742 sbPtr->DynPtr->LinVelocity.vz = 0;
14743
14744 marineStatusPointer->HModelController.Playing=1;
14745
14746 #if MARINE_STATE_PRINT
14747 textprint("Marine firing... ");
14748 #endif
14749
14750 /* first of all, validate this state: if the target suddenly becomes cloaked, then
14751 we should switch immediately to wait state*/
14752
14753 if (marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize) {
14754 /* Keep firing! */
14755 } else {
14756
14757 if(!MarineCanSeeTarget(sbPtr))
14758 {
14759
14760 /* ... and remove the gunflash */
14761 if(marineStatusPointer->myGunFlash)
14762 {
14763 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
14764 marineStatusPointer->myGunFlash = NULL;
14765 }
14766
14767 /* .... and stop the sound */
14768 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
14769 Sound_Stop(marineStatusPointer->soundHandle);
14770 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
14771 }
14772
14773 #if MARINE_STATE_PRINT
14774 textprint("Returning no target.\n");
14775 #endif
14776 marineStatusPointer->lastroundhit=0;
14777 marineStatusPointer->lasthitsection=NULL;
14778 return(SRC_Request_Wait);
14779 }
14780 }
14781
14782 if (marineStatusPointer->Target) {
14783 GLOBALASSERT(marineStatusPointer->Target);
14784 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
14785 /* Fix weapon target! */
14786 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
14787 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
14788 marineStatusPointer->My_Weapon->TargetCallibrationShift);
14789 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
14790 marineStatusPointer->My_Weapon->TargetCallibrationShift);
14791 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
14792 marineStatusPointer->My_Weapon->TargetCallibrationShift);
14793 }
14794
14795 /* Here we must have a target. Renew suspicion for new arrivals. */
14796 if (NpcSquad.Squad_Suspicion==0) {
14797 PointAlert(2,&marineStatusPointer->weaponTarget);
14798 }
14799 }
14800 /* Otherwise, stay facing the same way. */
14801
14802 /* orientate to firing point first */
14803 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
14804 orientationDirn.vy = 0;
14805 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
14806 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
14807
14808 /* I have a cunning plan... */
14809 {
14810 DELTA_CONTROLLER *delta;
14811
14812 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
14813 if (delta) {
14814 if (!(DeltaAnimation_IsFinished(delta))) {
14815 correctlyOrientated=0;
14816 }
14817 }
14818 }
14819 /* I have another cunning plan... */
14820 if ((marineStatusPointer->volleySize>0)&&
14821 (marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize)) {
14822 correctlyOrientated=1;
14823 }
14824
14825 /* we are not correctly orientated to the target: this could happen because we have
14826 just entered this state, or the target has moved during firing */
14827 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
14828
14829 /* stop visual and audio cues: technically, we're not firing at this moment */
14830 if(marineStatusPointer->myGunFlash)
14831 {
14832 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
14833 marineStatusPointer->myGunFlash = NULL;
14834 }
14835
14836 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
14837 Sound_Stop(marineStatusPointer->soundHandle);
14838 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
14839 }
14840 #if MARINE_STATE_PRINT
14841 textprint("Turning to face.\n");
14842 #endif
14843 marineStatusPointer->lastroundhit=0;
14844 marineStatusPointer->lasthitsection=NULL;
14845 return(SRC_No_Change);
14846 }
14847
14848 NPCFireMinigun_Core(sbPtr);
14849
14850 if (marineStatusPointer->Target==NULL) {
14851 /* Getting out of here! */
14852 return(SRC_No_Change);
14853 }
14854
14855 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
14856 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
14857 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
14858
14859 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
14860 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
14861 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
14862
14863 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
14864
14865 /* Did we get him? */
14866 if ((NPC_IsDead(marineStatusPointer->Target))
14867 &&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) {
14868 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
14869 if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) {
14870 /* Huzzah! */
14871 if(marineStatusPointer->myGunFlash)
14872 {
14873 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
14874 marineStatusPointer->myGunFlash = NULL;
14875 }
14876 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
14877 Sound_Stop(marineStatusPointer->soundHandle);
14878 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
14879 }
14880 marineStatusPointer->lastroundhit=0;
14881 marineStatusPointer->lasthitsection=NULL;
14882 return(SRC_Request_Taunt);
14883 }
14884 }
14885 }
14886
14887 if(marineStatusPointer->stateTimer > 0) {
14888 #if MARINE_STATE_PRINT
14889 textprint("Returning continue at range %d.\n",range);
14890 #endif
14891 return(SRC_No_Change);
14892 }
14893
14894 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
14895 {
14896 /* renew firing, as we are still too close to approach */
14897 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
14898 marineStatusPointer->volleySize = 0;
14899 GLOBALASSERT(marineStatusPointer->Target);
14900 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
14901 #if MARINE_STATE_PRINT
14902 textprint("Returning too close renewal at range %d.\n",range);
14903 #endif
14904
14905 /* stop visual and audio cues: technically, we're not firing at this moment */
14906 if(marineStatusPointer->myGunFlash)
14907 {
14908 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
14909 marineStatusPointer->myGunFlash = NULL;
14910 }
14911
14912 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
14913 Sound_Stop(marineStatusPointer->soundHandle);
14914 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
14915 }
14916 if (marineStatusPointer->Android==0) {
14917 marineStatusPointer->Courage-=(ONE_FIXED>>3);
14918 }
14919 return(SRC_Request_Fire);
14920 }
14921 else
14922 {
14923 /* we are far enough away, so return to approach */
14924
14925 /* ... and remove the gunflash */
14926 if(marineStatusPointer->myGunFlash)
14927 {
14928 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
14929 marineStatusPointer->myGunFlash = NULL;
14930 }
14931
14932 /* .... and stop the sound */
14933 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
14934 Sound_Stop(marineStatusPointer->soundHandle);
14935 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
14936 }
14937 #if MARINE_STATE_PRINT
14938 textprint("Returning too far termination at range %d.\n",range);
14939 #endif
14940 return(SRC_Request_Approach);
14941 }
14942 return(SRC_No_Change);
14943 }
14944
14945 static STATE_RETURN_CONDITION Execute_MNS_NullPanicFire(STRATEGYBLOCK *sbPtr) {
14946
14947 /* This MUST exist to redirect weapons with no panic fire. */
14948
14949 /* zero velocity */
14950 LOCALASSERT(sbPtr->DynPtr);
14951 sbPtr->DynPtr->LinVelocity.vx = 0;
14952 sbPtr->DynPtr->LinVelocity.vy = 0;
14953 sbPtr->DynPtr->LinVelocity.vz = 0;
14954
14955 return(SRC_Request_Wait);
14956
14957 }
14958
14959 static STATE_RETURN_CONDITION Execute_MNS_PanicFireLOSWeapon(STRATEGYBLOCK *sbPtr)
14960 {
14961 MARINE_STATUS_BLOCK *marineStatusPointer;
14962 VECTORCH orientationDirn;
14963 int correctlyOrientated;
14964 int volleytime,volleyrounds;
14965
14966 LOCALASSERT(sbPtr);
14967 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
14968 LOCALASSERT(marineStatusPointer);
14969
14970 marineStatusPointer->HModelController.Playing=1;
14971
14972 /* zero velocity */
14973 LOCALASSERT(sbPtr->DynPtr);
14974 sbPtr->DynPtr->LinVelocity.vx = 0;
14975 sbPtr->DynPtr->LinVelocity.vy = 0;
14976 sbPtr->DynPtr->LinVelocity.vz = 0;
14977
14978 #if MARINE_STATE_PRINT
14979 textprint("Marine panic firing... ");
14980 #endif
14981
14982 /* Stabilise sequence. */
14983 if (marineStatusPointer->Target==NULL) {
14984 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
14985 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
14986
14987 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
14988 }
14989 } else {
14990 int offsetx,offsety,offsetz,offseta,angle1;
14991 VECTORCH *gunpos;
14992 int sequence=0;
14993 /* Pick a sequence based on angle. */
14994
14995 if (marineStatusPointer->My_Elevation_Section) {
14996 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
14997 } else {
14998 gunpos=&sbPtr->DynPtr->Position;
14999 }
15000 /* Aim at Target. */
15001
15002 offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx);
15003 offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz);
15004 offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy));
15005
15006 while( (offsetx>(ONE_FIXED>>2))
15007 ||(offsety>(ONE_FIXED>>2))
15008 ||(offseta>(ONE_FIXED>>2))
15009 ||(offsetx<-(ONE_FIXED>>2))
15010 ||(offsety<-(ONE_FIXED>>2))
15011 ||(offseta<-(ONE_FIXED>>2))) {
15012
15013 offsetx>>=1;
15014 offsety>>=1;
15015 offseta>>=1;
15016
15017 }
15018
15019 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
15020 angle1=ArcTan(offseta,offsetz);
15021
15022 if (angle1>=3072) angle1-=4096;
15023 if (angle1>=2048) angle1=angle1-3072;
15024 if (angle1>1024) angle1=2048-angle1;
15025
15026 GLOBALASSERT(angle1>=-1024);
15027 GLOBALASSERT(angle1<=1024);
15028
15029 sequence=0;
15030 /* Now correct for hysteresis... */
15031 {
15032 int threshold22,threshold45,threshold67,threshold90,ideal_sequence;
15033
15034 if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) {
15035 threshold22=70;
15036 threshold45=220;
15037 threshold67=490;
15038 threshold90=730;
15039 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_67) {
15040 threshold22=70;
15041 threshold45=220;
15042 threshold67=490;
15043 threshold90=768;
15044 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) {
15045 threshold22=70;
15046 threshold45=220;
15047 threshold67=512;
15048 threshold90=768;
15049 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_22) {
15050 threshold22=70;
15051 threshold45=256;
15052 threshold67=512;
15053 threshold90=768;
15054 } else {
15055 threshold22=90;
15056 threshold45=256;
15057 threshold67=512;
15058 threshold90=768;
15059 }
15060
15061 if (angle1>threshold90) {
15062 ideal_sequence=4;
15063 } else if (angle1>threshold67) {
15064 ideal_sequence=3;
15065 } else if (angle1>threshold45) {
15066 ideal_sequence=2;
15067 } else if (angle1>threshold22) {
15068 ideal_sequence=1;
15069 } else {
15070 ideal_sequence=0;
15071 }
15072
15073 sequence=-1;
15074 while (sequence==-1) {
15075 switch (ideal_sequence) {
15076 case 0:
15077 default:
15078 sequence=0;
15079 break;
15080 case 1:
15081 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_22)) {
15082 sequence=1;
15083 } else {
15084 ideal_sequence=0;
15085 }
15086 break;
15087 case 2:
15088 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) {
15089 sequence=2;
15090 } else {
15091 ideal_sequence=1;
15092 }
15093 break;
15094 case 3:
15095 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_67)) {
15096 sequence=3;
15097 } else {
15098 ideal_sequence=2;
15099 }
15100 break;
15101 case 4:
15102 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) {
15103 sequence=4;
15104 } else {
15105 ideal_sequence=3;
15106 }
15107 break;
15108 }
15109 }
15110 }
15111
15112 switch (sequence) {
15113 case 4:
15114 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15115 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) {
15116 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3));
15117 }
15118 break;
15119 case 3:
15120 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15121 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_67)) {
15122 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_67,-1,(ONE_FIXED>>3));
15123 }
15124 break;
15125 case 2:
15126 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15127 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) {
15128 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3));
15129 }
15130 break;
15131 case 1:
15132 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15133 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_22)) {
15134 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_22,-1,(ONE_FIXED>>3));
15135 }
15136 break;
15137 case 0:
15138 default:
15139 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15140 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
15141 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
15142 }
15143 break;
15144 }
15145 }
15146
15147 if (marineStatusPointer->clipammo==0) {
15148 return(SRC_Request_PanicReload);
15149 }
15150
15151 /* Scream handling. */
15152 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
15153 if (marineStatusPointer->incidentFlag) {
15154 if (Marine_HasHisMouthOpen(sbPtr)) {
15155 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
15156 Marine_AngryScream(sbPtr);
15157 }
15158 }
15159 }
15160 }
15161
15162 if (marineStatusPointer->Target==NULL) {
15163 if (marineStatusPointer->incidentFlag) {
15164 /* Courage roll to stop. */
15165 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
15166 /* Okay, calm down a bit. */
15167 if(marineStatusPointer->myGunFlash)
15168 {
15169 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15170 marineStatusPointer->myGunFlash = NULL;
15171 }
15172
15173 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15174 Sound_Stop(marineStatusPointer->soundHandle);
15175 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15176 }
15177 /* Try to be suspicious? */
15178 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
15179 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
15180 /* Set this to zero when you get a *new* suspicion. */
15181 marineStatusPointer->previous_suspicion=0;
15182 marineStatusPointer->using_squad_suspicion=0;
15183
15184 return(SRC_Request_Wait);
15185 }
15186 }
15187 } else {
15188 GLOBALASSERT(marineStatusPointer->Target);
15189
15190 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
15191
15192 /* orientate to firing point first */
15193 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
15194 orientationDirn.vy = 0;
15195 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
15196 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
15197 if (correctlyOrientated) {
15198 if (MarineCanSeeTarget(sbPtr)) {
15199 /* Lost target... */
15200 marineStatusPointer->Target=NULL;
15201 }
15202 }
15203 }
15204
15205 if (NpcSquad.Squad_Suspicion==0) {
15206 if (marineStatusPointer->Target) {
15207 /* Here we must have a target. Renew suspicion for new arrivals. */
15208 PointAlert(2,&marineStatusPointer->weaponTarget);
15209 } else {
15210 PointAlert(1,&sbPtr->DynPtr->Position);
15211 }
15212 }
15213
15214 /* Wait for end of tweening before we proceed. */
15215 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
15216 #if 1
15217 /* stop visual and audio cues: technically, we're not firing at this moment */
15218 if(marineStatusPointer->myGunFlash)
15219 {
15220 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15221 marineStatusPointer->myGunFlash = NULL;
15222 }
15223 #endif
15224 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15225 Sound_Stop(marineStatusPointer->soundHandle);
15226 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15227 }
15228 return(SRC_No_Change);
15229 }
15230
15231 /* Right. Correctly orientated or not, we blaze away. */
15232
15233 /* look after the gun flash */
15234 if(marineStatusPointer->myGunFlash) {
15235 MaintainMarineGunFlash(sbPtr);
15236 } else {
15237 CreateMarineGunFlash(sbPtr);
15238 }
15239
15240 /* look after the sound */
15241 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
15242 else
15243 {
15244 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
15245 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
15246 }
15247
15248 marineStatusPointer->stateTimer -= NormalFrameTime;
15249
15250 /* Volleysize is now rounds fired this state. */
15251
15252 volleytime=marineStatusPointer->My_Weapon->FiringTime-marineStatusPointer->stateTimer;
15253 /* It was that or reverse the state timer for this state. */
15254 volleyrounds=MUL_FIXED(volleytime,marineStatusPointer->My_Weapon->FiringRate);
15255 volleyrounds>>=ONE_FIXED_SHIFT;
15256
15257 volleyrounds-=marineStatusPointer->volleySize;
15258 marineStatusPointer->volleySize+=volleyrounds;
15259
15260 LOCALASSERT(volleyrounds>=0);
15261
15262 if (marineStatusPointer->clipammo!=-1) {
15263 /* We're counting ammo. */
15264 if (volleyrounds>marineStatusPointer->clipammo) {
15265 volleyrounds=marineStatusPointer->clipammo;
15266 }
15267 marineStatusPointer->clipammo-=volleyrounds;
15268 LOCALASSERT(marineStatusPointer->clipammo>=0);
15269 }
15270
15271 /* Now fire volleyrounds bullets. */
15272 if (volleyrounds>0) {
15273 VECTORCH shotvector;
15274
15275 shotvector.vx=0;
15276 shotvector.vy=0;
15277 shotvector.vz=65535;
15278 RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat);
15279
15280 CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, volleyrounds,1);
15281
15282 }
15283
15284 /* Now, consider termination. */
15285
15286 if (marineStatusPointer->incidentFlag) {
15287 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15288 /* Two consecutive tests... */
15289 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15290
15291 /* stop visual and audio cues: technically, we're not firing at this moment */
15292 if(marineStatusPointer->myGunFlash)
15293 {
15294 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15295 marineStatusPointer->myGunFlash = NULL;
15296 }
15297
15298 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15299 Sound_Stop(marineStatusPointer->soundHandle);
15300 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15301 }
15302 return(SRC_Request_Retreat);
15303 }
15304 }
15305 }
15306
15307 return(SRC_No_Change);
15308
15309 }
15310
15311 static STATE_RETURN_CONDITION Execute_MNS_PanicFireFlamethrower(STRATEGYBLOCK *sbPtr)
15312 {
15313 MARINE_STATUS_BLOCK *marineStatusPointer;
15314 VECTORCH orientationDirn;
15315 int correctlyOrientated;
15316
15317 LOCALASSERT(sbPtr);
15318 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
15319 LOCALASSERT(marineStatusPointer);
15320
15321 marineStatusPointer->HModelController.Playing=1;
15322
15323 /* zero velocity */
15324 LOCALASSERT(sbPtr->DynPtr);
15325 sbPtr->DynPtr->LinVelocity.vx = 0;
15326 sbPtr->DynPtr->LinVelocity.vy = 0;
15327 sbPtr->DynPtr->LinVelocity.vz = 0;
15328
15329 #if MARINE_STATE_PRINT
15330 textprint("Marine panic firing... ");
15331 #endif
15332
15333 /* Stabilise sequence. */
15334 if (marineStatusPointer->Target==NULL) {
15335 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15336 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
15337
15338 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
15339 }
15340 } else {
15341 int offsetx,offsety,offsetz,offseta,angle1;
15342 VECTORCH *gunpos;
15343 int sequence=0;
15344 /* Pick a sequence based on angle. */
15345
15346 if (marineStatusPointer->My_Elevation_Section) {
15347 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
15348 } else {
15349 gunpos=&sbPtr->DynPtr->Position;
15350 }
15351 /* Aim at Target. */
15352
15353 offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx);
15354 offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz);
15355 offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy));
15356
15357 while( (offsetx>(ONE_FIXED>>2))
15358 ||(offsety>(ONE_FIXED>>2))
15359 ||(offseta>(ONE_FIXED>>2))
15360 ||(offsetx<-(ONE_FIXED>>2))
15361 ||(offsety<-(ONE_FIXED>>2))
15362 ||(offseta<-(ONE_FIXED>>2))) {
15363
15364 offsetx>>=1;
15365 offsety>>=1;
15366 offseta>>=1;
15367
15368 }
15369
15370 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
15371 angle1=ArcTan(offseta,offsetz);
15372
15373 if (angle1>=3072) angle1-=4096;
15374 if (angle1>=2048) angle1=angle1-3072;
15375 if (angle1>1024) angle1=2048-angle1;
15376
15377 GLOBALASSERT(angle1>=-1024);
15378 GLOBALASSERT(angle1<=1024);
15379
15380 sequence=0;
15381 /* Now correct for hysteresis... */
15382 {
15383 int highthreshold,topthreshold;
15384
15385 if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) {
15386 highthreshold=90;
15387 topthreshold=(1024-300);
15388 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) {
15389 highthreshold=90;
15390 topthreshold=(1024-256);
15391 } else {
15392 highthreshold=128;
15393 topthreshold=(1024-256);
15394 }
15395
15396 if (angle1>topthreshold) {
15397 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) {
15398 sequence=2;
15399 } else {
15400 sequence=0;
15401 }
15402 } else if (angle1>highthreshold) { //Was 256!
15403 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) {
15404 sequence=1;
15405 } else {
15406 sequence=0;
15407 }
15408 } else {
15409 sequence=0;
15410 }
15411 }
15412
15413 switch (sequence) {
15414 case 2:
15415 /* Escape for civvie flamethrower here? */
15416 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15417 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) {
15418 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3));
15419 }
15420 break;
15421 case 1:
15422 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15423 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) {
15424 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3));
15425 }
15426 break;
15427 case 0:
15428 default:
15429 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15430 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
15431 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
15432 }
15433 break;
15434 }
15435 }
15436
15437 if (marineStatusPointer->Target==NULL) {
15438 if (marineStatusPointer->incidentFlag) {
15439 /* Courage roll to stop. */
15440 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
15441 /* Okay, calm down a bit. */
15442 if(marineStatusPointer->myGunFlash)
15443 {
15444 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15445 marineStatusPointer->myGunFlash = NULL;
15446 }
15447
15448 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15449 Sound_Stop(marineStatusPointer->soundHandle);
15450 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15451 }
15452 /* Try to be suspicious? */
15453 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
15454 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
15455 /* Set this to zero when you get a *new* suspicion. */
15456 marineStatusPointer->previous_suspicion=0;
15457 marineStatusPointer->using_squad_suspicion=0;
15458
15459 return(SRC_Request_Wait);
15460 }
15461 }
15462 } else {
15463 GLOBALASSERT(marineStatusPointer->Target);
15464
15465 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
15466
15467 /* orientate to firing point first */
15468 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
15469 orientationDirn.vy = 0;
15470 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
15471 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
15472
15473 if (correctlyOrientated) {
15474 if (MarineCanSeeTarget(sbPtr)) {
15475 /* Lost target... */
15476 marineStatusPointer->Target=NULL;
15477 }
15478 }
15479 }
15480
15481 if (marineStatusPointer->clipammo==0) {
15482 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15483 if (marineStatusPointer->My_Weapon->ARealMarine) {
15484 return(SRC_Request_PullPistol);
15485 } else {
15486 return(SRC_Request_PanicReload);
15487 }
15488 } else {
15489 return(SRC_Request_PanicReload);
15490 }
15491 }
15492
15493 /* Scream handling. */
15494 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
15495 if (marineStatusPointer->incidentFlag) {
15496 if (Marine_HasHisMouthOpen(sbPtr)) {
15497 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
15498 Marine_AngryScream(sbPtr);
15499 }
15500 }
15501 }
15502 }
15503
15504 if (NpcSquad.Squad_Suspicion==0) {
15505 if (marineStatusPointer->Target) {
15506 /* Here we must have a target. Renew suspicion for new arrivals. */
15507 PointAlert(2,&marineStatusPointer->weaponTarget);
15508 } else {
15509 PointAlert(1,&sbPtr->DynPtr->Position);
15510 }
15511 }
15512
15513 /* Wait for end of tweening before we proceed. */
15514 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
15515 #if 1
15516 /* stop visual and audio cues: technically, we're not firing at this moment */
15517 if(marineStatusPointer->myGunFlash)
15518 {
15519 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15520 marineStatusPointer->myGunFlash = NULL;
15521 }
15522 #endif
15523 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15524 Sound_Stop(marineStatusPointer->soundHandle);
15525 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15526 }
15527 return(SRC_No_Change);
15528 }
15529
15530 /* Right. Correctly orientated or not, we blaze away. */
15531
15532 /* look after the gun flash */
15533 if(marineStatusPointer->myGunFlash) {
15534 /* No gunflash, neither. */
15535 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15536 }
15537
15538 /* look after the sound */
15539 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
15540 else
15541 {
15542 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
15543 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
15544 }
15545
15546 marineStatusPointer->stateTimer -= NormalFrameTime;
15547
15548 MarineFireFlameThrower(sbPtr);
15549
15550 /* Lighting? */
15551 if (sbPtr->SBdptr) {
15552 AddLightingEffectToObject(sbPtr->SBdptr,LFX_MUZZLEFLASH);
15553 }
15554
15555 if (marineStatusPointer->clipammo>0) {
15556 marineStatusPointer->clipammo-=NormalFrameTime;
15557 if (marineStatusPointer->clipammo<0) {
15558 marineStatusPointer->clipammo=0;
15559 }
15560 }
15561
15562 /* Now, consider termination. */
15563
15564 if (marineStatusPointer->incidentFlag) {
15565 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15566 /* Two consecutive tests... */
15567 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15568
15569 /* stop visual and audio cues: technically, we're not firing at this moment */
15570 if(marineStatusPointer->myGunFlash)
15571 {
15572 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15573 marineStatusPointer->myGunFlash = NULL;
15574 }
15575
15576 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15577 Sound_Stop(marineStatusPointer->soundHandle);
15578 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15579 }
15580 return(SRC_Request_Retreat);
15581 }
15582 }
15583 }
15584
15585 return(SRC_No_Change);
15586
15587 }
15588
15589 void Marine_SwitchExpression(STRATEGYBLOCK *sbPtr,int state) {
15590
15591 MARINE_STATUS_BLOCK *marineStatusPointer;
15592 SECTION_DATA *head;
15593 TXACTRLBLK *tacb;
15594
15595 LOCALASSERT(sbPtr);
15596 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
15597 LOCALASSERT(marineStatusPointer);
15598
15599 head=GetThisSectionData(marineStatusPointer->HModelController.section_data,"head");
15600
15601 marineStatusPointer->Expression=state;
15602 marineStatusPointer->Blink=-1;
15603
15604 if (head) {
15605 if ((head->flags§ion_data_notreal)==0) {
15606
15607 tacb=head->tac_ptr;
15608
15609 while (tacb) {
15610 tacb->tac_sequence = state ;
15611 tacb->tac_txah_s = GetTxAnimHeaderFromShape(tacb, head->ShapeNum);
15612
15613 tacb=tacb->tac_next;
15614 }
15615 }
15616 }
15617 }
15618
15619 static STATE_RETURN_CONDITION Execute_MNS_PanicFireGL(STRATEGYBLOCK *sbPtr)
15620 {
15621 MARINE_STATUS_BLOCK *marineStatusPointer;
15622 VECTORCH orientationDirn;
15623 int correctlyOrientated;
15624 int keyframeflags,a;
15625
15626 LOCALASSERT(sbPtr);
15627 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
15628 LOCALASSERT(marineStatusPointer);
15629
15630 /* zero velocity */
15631 LOCALASSERT(sbPtr->DynPtr);
15632 sbPtr->DynPtr->LinVelocity.vx = 0;
15633 sbPtr->DynPtr->LinVelocity.vy = 0;
15634 sbPtr->DynPtr->LinVelocity.vz = 0;
15635
15636 marineStatusPointer->HModelController.Playing=1;
15637
15638 #if MARINE_STATE_PRINT
15639 textprint("Marine panic firing... ");
15640 #endif
15641
15642 /* Stabilise sequence. */
15643 if (marineStatusPointer->Target==NULL) {
15644 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15645 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
15646
15647 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
15648 }
15649 } else {
15650 int offsetx,offsety,offsetz,offseta,angle1;
15651 VECTORCH *gunpos;
15652 int sequence=0;
15653 /* Pick a sequence based on angle. */
15654
15655 if (marineStatusPointer->My_Elevation_Section) {
15656 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
15657 } else {
15658 gunpos=&sbPtr->DynPtr->Position;
15659 }
15660 /* Aim at Target. */
15661
15662 offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx);
15663 offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz);
15664 offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy));
15665
15666 while( (offsetx>(ONE_FIXED>>2))
15667 ||(offsety>(ONE_FIXED>>2))
15668 ||(offseta>(ONE_FIXED>>2))
15669 ||(offsetx<-(ONE_FIXED>>2))
15670 ||(offsety<-(ONE_FIXED>>2))
15671 ||(offseta<-(ONE_FIXED>>2))) {
15672
15673 offsetx>>=1;
15674 offsety>>=1;
15675 offseta>>=1;
15676
15677 }
15678
15679 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
15680 angle1=ArcTan(offseta,offsetz);
15681
15682 if (angle1>=3072) angle1-=4096;
15683 if (angle1>=2048) angle1=angle1-3072;
15684 if (angle1>1024) angle1=2048-angle1;
15685
15686 GLOBALASSERT(angle1>=-1024);
15687 GLOBALASSERT(angle1<=1024);
15688
15689 sequence=0;
15690 /* Now correct for hysteresis... */
15691 {
15692 int highthreshold,topthreshold;
15693
15694 if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) {
15695 highthreshold=90;
15696 topthreshold=(1024-300);
15697 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) {
15698 highthreshold=90;
15699 topthreshold=(1024-256);
15700 } else {
15701 highthreshold=128;
15702 topthreshold=(1024-256);
15703 }
15704
15705 if (angle1>topthreshold) {
15706 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) {
15707 sequence=2;
15708 } else {
15709 sequence=0;
15710 }
15711 } else if (angle1>highthreshold) { //Was 256!
15712 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) {
15713 sequence=1;
15714 } else {
15715 sequence=0;
15716 }
15717 } else {
15718 sequence=0;
15719 }
15720 }
15721
15722 switch (sequence) {
15723 case 2:
15724 /* Escape for civvie flamethrower here? */
15725 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15726 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) {
15727 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3));
15728 }
15729 break;
15730 case 1:
15731 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15732 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) {
15733 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3));
15734 }
15735 break;
15736 case 0:
15737 default:
15738 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15739 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
15740 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
15741 }
15742 break;
15743 }
15744 }
15745
15746 if (marineStatusPointer->Target==NULL) {
15747 if (marineStatusPointer->incidentFlag) {
15748 /* Courage roll to stop. */
15749 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
15750 /* Okay, calm down a bit. */
15751 if(marineStatusPointer->myGunFlash)
15752 {
15753 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15754 marineStatusPointer->myGunFlash = NULL;
15755 }
15756
15757 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15758 Sound_Stop(marineStatusPointer->soundHandle);
15759 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15760 }
15761 /* Try to be suspicious? */
15762 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
15763 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
15764 /* Set this to zero when you get a *new* suspicion. */
15765 marineStatusPointer->previous_suspicion=0;
15766 marineStatusPointer->using_squad_suspicion=0;
15767
15768 return(SRC_Request_Wait);
15769 }
15770 }
15771 } else {
15772 GLOBALASSERT(marineStatusPointer->Target);
15773
15774 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
15775
15776 /* orientate to firing point first */
15777 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
15778 orientationDirn.vy = 0;
15779 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
15780 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
15781
15782 if (correctlyOrientated) {
15783 if (MarineCanSeeTarget(sbPtr)) {
15784 /* Lost target... */
15785 marineStatusPointer->Target=NULL;
15786 }
15787 }
15788 }
15789
15790 if (marineStatusPointer->clipammo==0) {
15791 /* Reload here. */
15792 return(SRC_Request_PanicReload);
15793 }
15794
15795 /* Scream handling. */
15796 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
15797 if (marineStatusPointer->incidentFlag) {
15798 if (Marine_HasHisMouthOpen(sbPtr)) {
15799 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
15800 Marine_AngryScream(sbPtr);
15801 }
15802 }
15803 }
15804 }
15805
15806 if (NpcSquad.Squad_Suspicion==0) {
15807 if (marineStatusPointer->Target) {
15808 /* Here we must have a target. Renew suspicion for new arrivals. */
15809 PointAlert(2,&marineStatusPointer->weaponTarget);
15810 } else {
15811 PointAlert(1,&sbPtr->DynPtr->Position);
15812 }
15813 }
15814
15815 /* Wait for end of tweening before we proceed. */
15816 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
15817 #if 1
15818 /* stop visual and audio cues: technically, we're not firing at this moment */
15819 if(marineStatusPointer->myGunFlash)
15820 {
15821 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15822 marineStatusPointer->myGunFlash = NULL;
15823 }
15824 #endif
15825 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15826 Sound_Stop(marineStatusPointer->soundHandle);
15827 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15828 }
15829 return(SRC_No_Change);
15830 }
15831
15832 /* Stop cues anyway? */
15833 if(marineStatusPointer->myGunFlash) {
15834 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15835 marineStatusPointer->myGunFlash = NULL;
15836 }
15837 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15838 Sound_Stop(marineStatusPointer->soundHandle);
15839 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15840 }
15841
15842 if (marineStatusPointer->Target) {
15843 int range;
15844
15845 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
15846
15847 /* Are they, by some chance, really close? */
15848 if (range<marineStatusPointer->My_Weapon->MinRange) {
15849 if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
15850 /* Stay cool. */
15851 return(SRC_Request_PullPistol);
15852 }
15853 /* Probably can't flee... :-) */
15854 }
15855 }
15856
15857 /* Right. Correctly orientated or not, we blaze away. */
15858
15859 keyframeflags=marineStatusPointer->HModelController.keyframe_flags>>1;
15860
15861 /* I know there are only four firing points... */
15862 for (a=0; a<4; a++) {
15863 if (keyframeflags&1) {
15864 /* Fire a grenade! */
15865
15866 /* look after the gun flash */
15867 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
15868 else CreateMarineGunFlash(sbPtr);
15869
15870 /* look after the sound */
15871 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
15872 else {
15873 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
15874 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
15875 }
15876
15877 LOCALASSERT(marineStatusPointer->My_Gunflash_Section);
15878 CreateGrenadeKernel(I_BehaviourGrenade, &marineStatusPointer->My_Gunflash_Section->World_Offset, &marineStatusPointer->My_Gunflash_Section->SecMat,0);
15879 if (marineStatusPointer->clipammo>0) {
15880 marineStatusPointer->clipammo--;
15881 }
15882 }
15883 keyframeflags>>=1;
15884 }
15885 /* ...and they are all identical. */
15886
15887 /* Now, consider termination. */
15888
15889 if (marineStatusPointer->incidentFlag) {
15890 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15891 /* Two consecutive tests... */
15892 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
15893
15894 /* stop visual and audio cues: technically, we're not firing at this moment */
15895 if(marineStatusPointer->myGunFlash)
15896 {
15897 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
15898 marineStatusPointer->myGunFlash = NULL;
15899 }
15900
15901 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
15902 Sound_Stop(marineStatusPointer->soundHandle);
15903 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
15904 }
15905 return(SRC_Request_Retreat);
15906 }
15907 }
15908 }
15909
15910 return(SRC_No_Change);
15911
15912 }
15913
15914 static STATE_RETURN_CONDITION Execute_MNS_PanicFireMinigun(STRATEGYBLOCK *sbPtr)
15915 {
15916 MARINE_STATUS_BLOCK *marineStatusPointer;
15917 VECTORCH orientationDirn;
15918 int correctlyOrientated;
15919
15920 LOCALASSERT(sbPtr);
15921 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
15922 LOCALASSERT(marineStatusPointer);
15923
15924 marineStatusPointer->HModelController.Playing=1;
15925
15926 #if MARINE_STATE_PRINT
15927 textprint("Marine panic firing... ");
15928 #endif
15929
15930 /* zero velocity */
15931 LOCALASSERT(sbPtr->DynPtr);
15932 sbPtr->DynPtr->LinVelocity.vx = 0;
15933 sbPtr->DynPtr->LinVelocity.vy = 0;
15934 sbPtr->DynPtr->LinVelocity.vz = 0;
15935
15936 /* Stabilise sequence. */
15937 if (marineStatusPointer->Target==NULL) {
15938 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
15939 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
15940
15941 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
15942 }
15943 } else {
15944 int offsetx,offsety,offsetz,offseta,angle1;
15945 VECTORCH *gunpos;
15946 int sequence=0;
15947 /* Pick a sequence based on angle. */
15948
15949 if (marineStatusPointer->My_Elevation_Section) {
15950 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
15951 } else {
15952 gunpos=&sbPtr->DynPtr->Position;
15953 }
15954 /* Aim at Target. */
15955
15956 offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx);
15957 offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz);
15958 offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy));
15959
15960 while( (offsetx>(ONE_FIXED>>2))
15961 ||(offsety>(ONE_FIXED>>2))
15962 ||(offseta>(ONE_FIXED>>2))
15963 ||(offsetx<-(ONE_FIXED>>2))
15964 ||(offsety<-(ONE_FIXED>>2))
15965 ||(offseta<-(ONE_FIXED>>2))) {
15966
15967 offsetx>>=1;
15968 offsety>>=1;
15969 offseta>>=1;
15970
15971 }
15972
15973 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
15974 angle1=ArcTan(offseta,offsetz);
15975
15976 if (angle1>=3072) angle1-=4096;
15977 if (angle1>=2048) angle1=angle1-3072;
15978 if (angle1>1024) angle1=2048-angle1;
15979
15980 GLOBALASSERT(angle1>=-1024);
15981 GLOBALASSERT(angle1<=1024);
15982
15983 sequence=0;
15984 /* Now correct for hysteresis... */
15985 {
15986 int highthreshold,topthreshold;
15987
15988 if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) {
15989 highthreshold=90;
15990 topthreshold=(1024-300);
15991 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) {
15992 highthreshold=90;
15993 topthreshold=(1024-256);
15994 } else {
15995 highthreshold=128;
15996 topthreshold=(1024-256);
15997 }
15998
15999 if (angle1>topthreshold) {
16000 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) {
16001 sequence=2;
16002 } else {
16003 sequence=0;
16004 }
16005 } else if (angle1>highthreshold) { //Was 256!
16006 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) {
16007 sequence=1;
16008 } else {
16009 sequence=0;
16010 }
16011 } else {
16012 sequence=0;
16013 }
16014 }
16015
16016 switch (sequence) {
16017 case 2:
16018 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16019 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) {
16020 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3));
16021 }
16022 break;
16023 case 1:
16024 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16025 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) {
16026 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3));
16027 }
16028 break;
16029 case 0:
16030 default:
16031 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16032 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
16033 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
16034 }
16035 break;
16036 }
16037 }
16038
16039 if (marineStatusPointer->clipammo==0) {
16040 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16041 return(SRC_Request_PullPistol);
16042 } else {
16043 return(SRC_Request_PanicReload);
16044 }
16045 }
16046
16047 /* Scream handling. */
16048 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
16049 if (marineStatusPointer->incidentFlag) {
16050 if (Marine_HasHisMouthOpen(sbPtr)) {
16051 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
16052 Marine_AngryScream(sbPtr);
16053 }
16054 }
16055 }
16056 }
16057
16058 if ((marineStatusPointer->Target==NULL)&&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) {
16059 if (marineStatusPointer->incidentFlag) {
16060 /* Courage roll to stop. */
16061 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
16062 /* Okay, calm down a bit. */
16063 if(marineStatusPointer->myGunFlash)
16064 {
16065 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16066 marineStatusPointer->myGunFlash = NULL;
16067 }
16068
16069 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16070 Sound_Stop(marineStatusPointer->soundHandle);
16071 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16072 }
16073 /* Try to be suspicious? */
16074 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
16075 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
16076 /* Set this to zero when you get a *new* suspicion. */
16077 marineStatusPointer->previous_suspicion=0;
16078 marineStatusPointer->using_squad_suspicion=0;
16079
16080 return(SRC_Request_Wait);
16081 }
16082 }
16083 } else {
16084 if (marineStatusPointer->Target) {
16085
16086 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
16087
16088 /* orientate to firing point first */
16089 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
16090 orientationDirn.vy = 0;
16091 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
16092 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
16093
16094 if (correctlyOrientated) {
16095 if (MarineCanSeeTarget(sbPtr)) {
16096 /* Lost target... */
16097 marineStatusPointer->Target=NULL;
16098 }
16099 }
16100 } else {
16101 /* Who cares! */
16102 correctlyOrientated=1;
16103 }
16104 }
16105
16106 if (NpcSquad.Squad_Suspicion==0) {
16107 if (marineStatusPointer->Target) {
16108 /* Here we must have a target. Renew suspicion for new arrivals. */
16109 PointAlert(2,&marineStatusPointer->weaponTarget);
16110 } else {
16111 PointAlert(1,&sbPtr->DynPtr->Position);
16112 }
16113 }
16114
16115 /* Wait for end of tweening before we proceed. */
16116 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
16117 #if 1
16118 /* stop visual and audio cues: technically, we're not firing at this moment */
16119 if(marineStatusPointer->myGunFlash)
16120 {
16121 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16122 marineStatusPointer->myGunFlash = NULL;
16123 }
16124 #endif
16125 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16126 Sound_Stop(marineStatusPointer->soundHandle);
16127 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16128 }
16129 return(SRC_No_Change);
16130 }
16131
16132 /* Right. Correctly orientated or not, we blaze away. */
16133
16134 NPCFireMinigun_Core(sbPtr);
16135
16136 /* Now, consider termination. */
16137
16138 if (marineStatusPointer->volleySize<MINIGUN_MINIMUM_BURST) {
16139 /* Can't terminate yet. */
16140 return(SRC_No_Change);
16141 }
16142
16143 if (marineStatusPointer->incidentFlag) {
16144 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16145 /* Two consecutive tests... */
16146 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16147
16148 /* stop visual and audio cues: technically, we're not firing at this moment */
16149 if(marineStatusPointer->myGunFlash)
16150 {
16151 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16152 marineStatusPointer->myGunFlash = NULL;
16153 }
16154
16155 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16156 Sound_Stop(marineStatusPointer->soundHandle);
16157 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16158 }
16159 return(SRC_Request_Retreat);
16160 }
16161 }
16162 }
16163
16164 return(SRC_No_Change);
16165
16166 }
16167
16168 static STATE_RETURN_CONDITION Execute_MNS_PanicFirePistol(STRATEGYBLOCK *sbPtr)
16169 {
16170 MARINE_STATUS_BLOCK *marineStatusPointer;
16171 VECTORCH orientationDirn;
16172 int correctlyOrientated;
16173 int a,keyframeflags;
16174
16175 LOCALASSERT(sbPtr);
16176 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
16177 LOCALASSERT(marineStatusPointer);
16178
16179 marineStatusPointer->HModelController.Playing=1;
16180
16181 #if MARINE_STATE_PRINT
16182 textprint("Marine panic firing... ");
16183 #endif
16184
16185 /* zero velocity */
16186 LOCALASSERT(sbPtr->DynPtr);
16187 sbPtr->DynPtr->LinVelocity.vx = 0;
16188 sbPtr->DynPtr->LinVelocity.vy = 0;
16189 sbPtr->DynPtr->LinVelocity.vz = 0;
16190
16191 /* Stabilise sequence. */
16192 if (marineStatusPointer->Target==NULL) {
16193 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16194 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
16195
16196 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
16197 }
16198 } else {
16199 int offsetx,offsety,offsetz,offseta,angle1;
16200 VECTORCH *gunpos;
16201 int sequence=0;
16202 /* Pick a sequence based on angle. */
16203
16204 if (marineStatusPointer->My_Elevation_Section) {
16205 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
16206 } else {
16207 gunpos=&sbPtr->DynPtr->Position;
16208 }
16209 /* Aim at Target. */
16210
16211 offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx);
16212 offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz);
16213 offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy));
16214
16215 while( (offsetx>(ONE_FIXED>>2))
16216 ||(offsety>(ONE_FIXED>>2))
16217 ||(offseta>(ONE_FIXED>>2))
16218 ||(offsetx<-(ONE_FIXED>>2))
16219 ||(offsety<-(ONE_FIXED>>2))
16220 ||(offseta<-(ONE_FIXED>>2))) {
16221
16222 offsetx>>=1;
16223 offsety>>=1;
16224 offseta>>=1;
16225
16226 }
16227
16228 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
16229 angle1=ArcTan(offseta,offsetz);
16230
16231 if (angle1>=3072) angle1-=4096;
16232 if (angle1>=2048) angle1=angle1-3072;
16233 if (angle1>1024) angle1=2048-angle1;
16234
16235 GLOBALASSERT(angle1>=-1024);
16236 GLOBALASSERT(angle1<=1024);
16237
16238 sequence=0;
16239 /* Now correct for hysteresis... */
16240 {
16241 int highthreshold,topthreshold;
16242
16243 if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) {
16244 highthreshold=90;
16245 topthreshold=(1024-300);
16246 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) {
16247 highthreshold=90;
16248 topthreshold=(1024-256);
16249 } else {
16250 highthreshold=128;
16251 topthreshold=(1024-256);
16252 }
16253
16254 if (angle1>topthreshold) {
16255 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) {
16256 sequence=2;
16257 } else {
16258 sequence=0;
16259 }
16260 } else if (angle1>highthreshold) { //Was 256!
16261 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) {
16262 sequence=1;
16263 } else {
16264 sequence=0;
16265 }
16266 } else {
16267 sequence=0;
16268 }
16269 }
16270
16271 switch (sequence) {
16272 case 2:
16273 /* Escape for civvie flamethrower here? */
16274 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16275 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) {
16276 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3));
16277 }
16278 break;
16279 case 1:
16280 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16281 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) {
16282 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3));
16283 }
16284 break;
16285 case 0:
16286 default:
16287 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16288 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
16289 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
16290 }
16291 break;
16292 }
16293 }
16294
16295 if (marineStatusPointer->clipammo==0) {
16296 return(SRC_Request_PanicReload);
16297 }
16298
16299 /* Scream handling. */
16300 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
16301 if (marineStatusPointer->incidentFlag) {
16302 if (Marine_HasHisMouthOpen(sbPtr)) {
16303 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
16304 Marine_AngryScream(sbPtr);
16305 }
16306 }
16307 }
16308 }
16309
16310 if (marineStatusPointer->Target==NULL) {
16311 if (marineStatusPointer->incidentFlag) {
16312 /* Courage roll to stop. */
16313 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
16314 /* Okay, calm down a bit. */
16315 if(marineStatusPointer->myGunFlash)
16316 {
16317 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16318 marineStatusPointer->myGunFlash = NULL;
16319 }
16320
16321 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16322 Sound_Stop(marineStatusPointer->soundHandle);
16323 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16324 }
16325 /* Try to be suspicious? */
16326 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
16327 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
16328 /* Set this to zero when you get a *new* suspicion. */
16329 marineStatusPointer->previous_suspicion=0;
16330 marineStatusPointer->using_squad_suspicion=0;
16331
16332 return(SRC_Request_Wait);
16333 }
16334 }
16335 } else {
16336 GLOBALASSERT(marineStatusPointer->Target);
16337
16338 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
16339 /* Fix weapon target! */
16340 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
16341 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
16342 marineStatusPointer->My_Weapon->TargetCallibrationShift);
16343 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
16344 marineStatusPointer->My_Weapon->TargetCallibrationShift);
16345 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
16346 marineStatusPointer->My_Weapon->TargetCallibrationShift);
16347 }
16348
16349 /* orientate to firing point first */
16350 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
16351 orientationDirn.vy = 0;
16352 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
16353 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
16354
16355 if (correctlyOrientated) {
16356 if (MarineCanSeeTarget(sbPtr)) {
16357 /* Lost target... */
16358 marineStatusPointer->Target=NULL;
16359 }
16360 }
16361 }
16362
16363 if (NpcSquad.Squad_Suspicion==0) {
16364 if (marineStatusPointer->Target) {
16365 /* Here we must have a target. Renew suspicion for new arrivals. */
16366 PointAlert(2,&marineStatusPointer->weaponTarget);
16367 } else {
16368 PointAlert(1,&sbPtr->DynPtr->Position);
16369 }
16370 }
16371
16372 /* Wait for end of tweening before we proceed. */
16373 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
16374 #if 1
16375 /* stop visual and audio cues: technically, we're not firing at this moment */
16376 if(marineStatusPointer->myGunFlash)
16377 {
16378 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16379 marineStatusPointer->myGunFlash = NULL;
16380 }
16381 #endif
16382 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16383 Sound_Stop(marineStatusPointer->soundHandle);
16384 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16385 }
16386 return(SRC_No_Change);
16387 }
16388
16389 /* Stop cues anyway? */
16390 if(marineStatusPointer->myGunFlash) {
16391 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16392 marineStatusPointer->myGunFlash = NULL;
16393 }
16394 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16395 Sound_Stop(marineStatusPointer->soundHandle);
16396 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16397 }
16398
16399 /* Right. Correctly orientated or not, we blaze away. */
16400
16401 keyframeflags=marineStatusPointer->HModelController.keyframe_flags>>1;
16402
16403 /* I know there are only six possible firing points... */
16404 for (a=0; a<6; a++) {
16405 if ((keyframeflags&1)||((a==0)&&(marineStatusPointer->HModelController.Tweening==Controller_EndTweening))) {
16406 /* Fire a shot. */
16407
16408 /* look after the gun flash */
16409 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
16410 else CreateMarineGunFlash(sbPtr);
16411
16412 /* look after the sound */
16413 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
16414 else {
16415 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
16416 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
16417 }
16418
16419 {
16420 VECTORCH shotvector;
16421
16422 shotvector.vx=0;
16423 shotvector.vy=0;
16424 shotvector.vz=65535;
16425 RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat);
16426
16427 CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, 1,1);
16428 if (marineStatusPointer->clipammo>0) {
16429 marineStatusPointer->clipammo--;
16430 }
16431 }
16432 }
16433 keyframeflags>>=1;
16434 }
16435 /* ...and they are all identical. */
16436
16437 /* Now, consider termination. */
16438
16439 if (marineStatusPointer->incidentFlag) {
16440 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16441 /* Two consecutive tests... */
16442 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16443
16444 /* stop visual and audio cues: technically, we're not firing at this moment */
16445 if(marineStatusPointer->myGunFlash)
16446 {
16447 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16448 marineStatusPointer->myGunFlash = NULL;
16449 }
16450
16451 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16452 Sound_Stop(marineStatusPointer->soundHandle);
16453 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16454 }
16455 return(SRC_Request_Retreat);
16456 }
16457 }
16458 }
16459
16460 return(SRC_No_Change);
16461
16462 }
16463
16464 static STATE_RETURN_CONDITION Execute_MNS_PanicFireShotgun(STRATEGYBLOCK *sbPtr)
16465 {
16466 MARINE_STATUS_BLOCK *marineStatusPointer;
16467 VECTORCH orientationDirn;
16468 int correctlyOrientated;
16469 int keyframeflags,a,b;
16470
16471 LOCALASSERT(sbPtr);
16472 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
16473 LOCALASSERT(marineStatusPointer);
16474
16475 marineStatusPointer->HModelController.Playing=1;
16476
16477 #if MARINE_STATE_PRINT
16478 textprint("Marine panic firing... ");
16479 #endif
16480
16481 /* zero velocity */
16482 LOCALASSERT(sbPtr->DynPtr);
16483 sbPtr->DynPtr->LinVelocity.vx = 0;
16484 sbPtr->DynPtr->LinVelocity.vy = 0;
16485 sbPtr->DynPtr->LinVelocity.vz = 0;
16486
16487 /* Stabilise sequence. */
16488 if (marineStatusPointer->Target==NULL) {
16489 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16490 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
16491
16492 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
16493 }
16494 } else {
16495 int offsetx,offsety,offsetz,offseta,angle1;
16496 VECTORCH *gunpos;
16497 int sequence=0;
16498 /* Pick a sequence based on angle. */
16499
16500 if (marineStatusPointer->My_Elevation_Section) {
16501 gunpos=&marineStatusPointer->My_Elevation_Section->World_Offset;
16502 } else {
16503 gunpos=&sbPtr->DynPtr->Position;
16504 }
16505 /* Aim at Target. */
16506
16507 offsetx=(marineStatusPointer->Target->DynPtr->Position.vx)-(gunpos->vx);
16508 offsety=(marineStatusPointer->Target->DynPtr->Position.vz)-(gunpos->vz);
16509 offseta=-((marineStatusPointer->Target->DynPtr->Position.vy)-(gunpos->vy));
16510
16511 while( (offsetx>(ONE_FIXED>>2))
16512 ||(offsety>(ONE_FIXED>>2))
16513 ||(offseta>(ONE_FIXED>>2))
16514 ||(offsetx<-(ONE_FIXED>>2))
16515 ||(offsety<-(ONE_FIXED>>2))
16516 ||(offseta<-(ONE_FIXED>>2))) {
16517
16518 offsetx>>=1;
16519 offsety>>=1;
16520 offseta>>=1;
16521
16522 }
16523
16524 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
16525 angle1=ArcTan(offseta,offsetz);
16526
16527 if (angle1>=3072) angle1-=4096;
16528 if (angle1>=2048) angle1=angle1-3072;
16529 if (angle1>1024) angle1=2048-angle1;
16530
16531 GLOBALASSERT(angle1>=-1024);
16532 GLOBALASSERT(angle1<=1024);
16533
16534 sequence=0;
16535 /* Now correct for hysteresis... */
16536 {
16537 int highthreshold,topthreshold;
16538
16539 if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_90) {
16540 highthreshold=90;
16541 topthreshold=(1024-300);
16542 } else if (marineStatusPointer->HModelController.Sub_Sequence==MSSS_WildFire_45) {
16543 highthreshold=90;
16544 topthreshold=(1024-256);
16545 } else {
16546 highthreshold=128;
16547 topthreshold=(1024-256);
16548 }
16549
16550 if (angle1>topthreshold) {
16551 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_90)) {
16552 sequence=2;
16553 } else {
16554 sequence=0;
16555 }
16556 } else if (angle1>highthreshold) { //Was 256!
16557 if (HModelSequence_Exists(&marineStatusPointer->HModelController,HMSQT_MarineStand,MSSS_WildFire_45)) {
16558 sequence=1;
16559 } else {
16560 sequence=0;
16561 }
16562 } else {
16563 sequence=0;
16564 }
16565 }
16566
16567 switch (sequence) {
16568 case 2:
16569 /* Escape for civvie flamethrower here? */
16570 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16571 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90)) {
16572 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>3));
16573 }
16574 break;
16575 case 1:
16576 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16577 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)) {
16578 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>3));
16579 }
16580 break;
16581 case 0:
16582 default:
16583 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16584 ||(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)) {
16585 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>3));
16586 }
16587 break;
16588 }
16589 }
16590
16591 if (marineStatusPointer->clipammo==0) {
16592 return(SRC_Request_PanicReload);
16593 }
16594
16595 /* Scream handling. */
16596 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
16597 if (marineStatusPointer->incidentFlag) {
16598 if (Marine_HasHisMouthOpen(sbPtr)) {
16599 if (marineStatusPointer->My_Weapon->id==MNPCW_MUnarmed) {
16600 Marine_AngryScream(sbPtr);
16601 }
16602 }
16603 }
16604 }
16605
16606 if (marineStatusPointer->Target==NULL) {
16607 if (marineStatusPointer->incidentFlag) {
16608 /* Courage roll to stop. */
16609 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
16610 /* Okay, calm down a bit. */
16611 if(marineStatusPointer->myGunFlash)
16612 {
16613 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16614 marineStatusPointer->myGunFlash = NULL;
16615 }
16616
16617 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16618 Sound_Stop(marineStatusPointer->soundHandle);
16619 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16620 }
16621 /* Try to be suspicious? */
16622 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
16623 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
16624 /* Set this to zero when you get a *new* suspicion. */
16625 marineStatusPointer->previous_suspicion=0;
16626 marineStatusPointer->using_squad_suspicion=0;
16627
16628 return(SRC_Request_Wait);
16629 }
16630 }
16631 } else {
16632 GLOBALASSERT(marineStatusPointer->Target);
16633
16634 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
16635
16636 /* orientate to firing point first */
16637 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
16638 orientationDirn.vy = 0;
16639 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
16640 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
16641
16642 if (correctlyOrientated) {
16643 if (MarineCanSeeTarget(sbPtr)) {
16644 /* Lost target... */
16645 marineStatusPointer->Target=NULL;
16646 }
16647 }
16648 }
16649
16650 if (NpcSquad.Squad_Suspicion==0) {
16651 if (marineStatusPointer->Target) {
16652 /* Here we must have a target. Renew suspicion for new arrivals. */
16653 PointAlert(2,&marineStatusPointer->weaponTarget);
16654 } else {
16655 PointAlert(1,&sbPtr->DynPtr->Position);
16656 }
16657 }
16658
16659 /* Wait for end of tweening before we proceed. */
16660 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
16661 #if 1
16662 /* stop visual and audio cues: technically, we're not firing at this moment */
16663 if(marineStatusPointer->myGunFlash)
16664 {
16665 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16666 marineStatusPointer->myGunFlash = NULL;
16667 }
16668 #endif
16669 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16670 Sound_Stop(marineStatusPointer->soundHandle);
16671 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16672 }
16673 return(SRC_No_Change);
16674 }
16675
16676 /* Stop cues anyway? */
16677 if(marineStatusPointer->myGunFlash) {
16678 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16679 marineStatusPointer->myGunFlash = NULL;
16680 }
16681 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16682 Sound_Stop(marineStatusPointer->soundHandle);
16683 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16684 }
16685
16686 /* Right. Correctly orientated or not, we blaze away. */
16687
16688 keyframeflags=marineStatusPointer->HModelController.keyframe_flags>>1;
16689
16690 /* I know there are only three firing points... */
16691 for (a=0; a<3; a++) {
16692 if (keyframeflags&1) {
16693
16694 /* look after the gun flash */
16695 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
16696 else CreateMarineGunFlash(sbPtr);
16697
16698 /* look after the sound */
16699 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
16700 else {
16701 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
16702 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
16703 }
16704
16705 /* Now hit the target with a shotgun blast. */
16706
16707 b=0;
16708
16709 while (ShotgunBlast[b].vz>0) {
16710 VECTORCH world_vec;
16711
16712 RotateAndCopyVector(&ShotgunBlast[b],&world_vec,&marineStatusPointer->My_Gunflash_Section->SecMat);
16713 CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&world_vec, marineStatusPointer->My_Weapon->Ammo_Type, 1,0);
16714
16715 b++;
16716 }
16717 if (marineStatusPointer->clipammo>0) {
16718 marineStatusPointer->clipammo--;
16719 }
16720 }
16721 keyframeflags>>=1;
16722 }
16723 /* ...and they are all identical. */
16724
16725 /* Now, consider termination. */
16726
16727 if (marineStatusPointer->incidentFlag) {
16728 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16729 /* Two consecutive tests... */
16730 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16731
16732 /* stop visual and audio cues: technically, we're not firing at this moment */
16733 if(marineStatusPointer->myGunFlash)
16734 {
16735 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16736 marineStatusPointer->myGunFlash = NULL;
16737 }
16738
16739 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16740 Sound_Stop(marineStatusPointer->soundHandle);
16741 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16742 }
16743 return(SRC_Request_Retreat);
16744 }
16745 }
16746 }
16747
16748 return(SRC_No_Change);
16749
16750 }
16751
16752 static void Marine_EnterExtremePanicAnimation(STRATEGYBLOCK *sbPtr) {
16753
16754 if ((FastRandom()&65535)<21845) {
16755 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_90,-1,(ONE_FIXED>>1));
16756 } else if ((FastRandom()&65535)<21845) {
16757 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_45,-1,(ONE_FIXED>>1));
16758 } else {
16759 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_WildFire_0,-1,(ONE_FIXED>>1));
16760 }
16761
16762 }
16763
16764 static void Marine_EnterLesserPanicAnimation(STRATEGYBLOCK *sbPtr) {
16765
16766 if ((FastRandom()&65535)<32767) {
16767 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Panic_One,-1,(ONE_FIXED>>1));
16768 } else {
16769 SetMarineAnimationSequence_Null(sbPtr,HMSQT_MarineStand,MSSS_Panic_Two,-1,(ONE_FIXED>>1));
16770 }
16771
16772 }
16773
16774 static STATE_RETURN_CONDITION Execute_MNS_PanicFireUnarmed(STRATEGYBLOCK *sbPtr)
16775 {
16776 MARINE_STATUS_BLOCK *marineStatusPointer;
16777 VECTORCH orientationDirn;
16778
16779 /* Also known as... gibber in terror. */
16780
16781 LOCALASSERT(sbPtr);
16782 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
16783 LOCALASSERT(marineStatusPointer);
16784
16785 marineStatusPointer->HModelController.Playing=1;
16786
16787 #if MARINE_STATE_PRINT
16788 textprint("Marine panic firing... ");
16789 #endif
16790
16791 /* zero velocity */
16792 LOCALASSERT(sbPtr->DynPtr);
16793 sbPtr->DynPtr->LinVelocity.vx = 0;
16794 sbPtr->DynPtr->LinVelocity.vy = 0;
16795 sbPtr->DynPtr->LinVelocity.vz = 0;
16796
16797 /* Firstly, are we trying to retreat? */
16798 if (marineStatusPointer->internalState==1) {
16799 /* Wait for tweening to finish... */
16800 if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) {
16801 /* Then the first incidentFlag we get, we're outta here. */
16802 if (marineStatusPointer->incidentFlag) {
16803 return(SRC_Request_Retreat);
16804 }
16805 }
16806 return(SRC_No_Change);
16807 }
16808
16809 /* Stabilise sequence. */
16810 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16811 ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_0)
16812 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_45)
16813 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_WildFire_90))) {
16814
16815 /* If we're not in one of the 'extreme panic' animations, are we in one of the others? */
16816 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16817 ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_One)
16818 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_Two))) {
16819 /* No, we're not. See which level of panic to go into... */
16820 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16821 /* It's PaNiC tImE! */
16822 Marine_EnterExtremePanicAnimation(sbPtr);
16823 } else {
16824 /* Just look worried. */
16825 Marine_EnterLesserPanicAnimation(sbPtr);
16826 }
16827 } else {
16828 /* Yes, we are. Is it getting worse? */
16829 int range;
16830 STRATEGYBLOCK *threat;
16831
16832 if (marineStatusPointer->incidentFlag) {
16833
16834 threat=Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr);
16835 if (threat) {
16836 range=VectorDistance(&sbPtr->DynPtr->Position,&threat->DynPtr->Position);
16837 } else {
16838 range=100000;
16839 }
16840
16841 if ((MarineRetreatsInTheFaceOfDanger(sbPtr))||(range<3000)) {
16842 if (range<3000) {
16843 if (marineStatusPointer->Android==0) {
16844 marineStatusPointer->Courage-=5000;
16845 }
16846 }
16847 Marine_EnterExtremePanicAnimation(sbPtr);
16848 } else {
16849 /* Feeling really brave? */
16850 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
16851 Marine_QueueGrimaceExpression(sbPtr);
16852 }
16853 }
16854 }
16855 /* Else remain as you were. */
16856 }
16857 } else {
16858 /* We are in extreme panic. Is it getting better? */
16859 if (marineStatusPointer->incidentFlag) {
16860 if ((FastRandom()&65535)<13107) {
16861 if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
16862 if (!(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
16863 /* Two consecutive tests. */
16864 Marine_EnterLesserPanicAnimation(sbPtr);
16865 }
16866 }
16867 }
16868 }
16869 /* Enforce panic expression, too. */
16870 Marine_QueuePanicExpression(sbPtr);
16871 }
16872
16873 if (marineStatusPointer->Target==NULL) {
16874 /* Civvies with courage 0 get a bonus to shut up... */
16875 if (marineStatusPointer->Courage==0) {
16876 /* No reason to block this for Androids. */
16877 marineStatusPointer->Courage=5000;
16878 }
16879
16880 if (marineStatusPointer->incidentFlag) {
16881 /* Courage roll to stop. */
16882 if (MarineRetreatsInTheFaceOfDanger(sbPtr)==0) {
16883 /* Okay, calm down a bit. */
16884 if(marineStatusPointer->myGunFlash)
16885 {
16886 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16887 marineStatusPointer->myGunFlash = NULL;
16888 }
16889
16890 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16891 Sound_Stop(marineStatusPointer->soundHandle);
16892 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16893 }
16894 /* Try to be suspicious? */
16895 marineStatusPointer->suspicious=MARINE_PANIC_TIME;
16896 marineStatusPointer->suspect_point=marineStatusPointer->weaponTarget;
16897 /* Set this to zero when you get a *new* suspicion. */
16898 marineStatusPointer->previous_suspicion=0;
16899 marineStatusPointer->using_squad_suspicion=0;
16900
16901 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16902 ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_One)
16903 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_Two))) {
16904 Marine_EnterLesserPanicAnimation(sbPtr);
16905 return(SRC_No_Change);
16906 } else {
16907 return(SRC_Request_Wait);
16908 }
16909 }
16910 }
16911 } else {
16912 GLOBALASSERT(marineStatusPointer->Target);
16913 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
16914
16915 /* May as well keep an eye out. */
16916 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
16917 orientationDirn.vy = 0;
16918 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
16919 #if 0
16920 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
16921 #endif
16922 }
16923
16924 /* Scream handling. */
16925 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
16926 if (marineStatusPointer->incidentFlag) {
16927 if (Marine_HasHisMouthOpen(sbPtr)) {
16928 Marine_Sobbing(sbPtr);
16929 } else {
16930 /* Start yelling again? */
16931 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
16932 Marine_QueuePanicExpression(sbPtr);
16933 }
16934 }
16935 }
16936 }
16937
16938 if (NpcSquad.Squad_Suspicion==0) {
16939 if (marineStatusPointer->Target) {
16940 /* Here we must have a target. Renew suspicion for new arrivals. */
16941 PointAlert(2,&marineStatusPointer->weaponTarget);
16942 } else {
16943 PointAlert(1,&sbPtr->DynPtr->Position);
16944 }
16945 }
16946
16947 /* Wait for end of tweening before we proceed. */
16948 if (marineStatusPointer->HModelController.Tweening!=Controller_NoTweening) {
16949 #if 1
16950 /* stop visual and audio cues: technically, we're not firing at this moment */
16951 if(marineStatusPointer->myGunFlash)
16952 {
16953 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16954 marineStatusPointer->myGunFlash = NULL;
16955 }
16956 #endif
16957 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16958 Sound_Stop(marineStatusPointer->soundHandle);
16959 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16960 }
16961 return(SRC_No_Change);
16962 }
16963
16964 /* No functionality in here... */
16965
16966 marineStatusPointer->stateTimer -= NormalFrameTime;
16967
16968 /* Now, consider termination. */
16969
16970 if (marineStatusPointer->incidentFlag) {
16971 if ((FastRandom()&65535)<13107) {
16972 if ((!(MarineRetreatsInTheFaceOfDanger(sbPtr)))
16973 ||(!(MarineRetreatsInTheFaceOfDanger(sbPtr)))) {
16974 /* Two chances... */
16975
16976 /* stop visual and audio cues: technically, we're not firing at this moment */
16977 if(marineStatusPointer->myGunFlash)
16978 {
16979 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
16980 marineStatusPointer->myGunFlash = NULL;
16981 }
16982
16983 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
16984 Sound_Stop(marineStatusPointer->soundHandle);
16985 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
16986 }
16987 if ((marineStatusPointer->HModelController.Sequence_Type!=HMSQT_MarineStand)
16988 ||((marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_One)
16989 &&(marineStatusPointer->HModelController.Sub_Sequence!=MSSS_Panic_Two))) {
16990 Marine_EnterLesserPanicAnimation(sbPtr);
16991 marineStatusPointer->internalState=1;
16992 /* This is a bit pre-emptive, but never mind. */
16993 if (marineStatusPointer->Android==0) {
16994 marineStatusPointer->Courage-=5000;
16995 }
16996 return(SRC_No_Change);
16997 } else {
16998 return(SRC_Request_Retreat);
16999 }
17000 }
17001 }
17002 }
17003
17004 return(SRC_No_Change);
17005
17006 }
17007
17008 void Marine_AssumeNeutralExpression(STRATEGYBLOCK *sbPtr) {
17009
17010 MARINE_STATUS_BLOCK *marineStatusPointer;
17011
17012 LOCALASSERT(sbPtr);
17013 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17014 LOCALASSERT(marineStatusPointer);
17015
17016 if ((marineStatusPointer->Expression>2)&&(marineStatusPointer->Expression<6)) {
17017 /* In a blink. */
17018 Marine_SwitchExpression(sbPtr,3);
17019 if (marineStatusPointer->Blink<0) {
17020 /* Dunno why, but you never know. */
17021 marineStatusPointer->Blink=0;
17022 }
17023 } else {
17024 /* Not in a blink. */
17025 Marine_SwitchExpression(sbPtr,0);
17026 }
17027
17028 }
17029
17030 void Marine_AssumeGrimaceExpression(STRATEGYBLOCK *sbPtr) {
17031
17032 MARINE_STATUS_BLOCK *marineStatusPointer;
17033
17034 LOCALASSERT(sbPtr);
17035 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17036 LOCALASSERT(marineStatusPointer);
17037
17038 if ((marineStatusPointer->Expression>2)&&(marineStatusPointer->Expression<6)) {
17039 /* In a blink. */
17040 Marine_SwitchExpression(sbPtr,4);
17041 if (marineStatusPointer->Blink<0) {
17042 /* Dunno why, but you never know. */
17043 marineStatusPointer->Blink=0;
17044 }
17045 } else {
17046 /* Not in a blink. */
17047 Marine_SwitchExpression(sbPtr,1);
17048 }
17049
17050 }
17051
17052 void Marine_AssumePanicExpression(STRATEGYBLOCK *sbPtr) {
17053
17054 MARINE_STATUS_BLOCK *marineStatusPointer;
17055
17056 LOCALASSERT(sbPtr);
17057 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17058 LOCALASSERT(marineStatusPointer);
17059
17060 if ((marineStatusPointer->Expression>2)&&(marineStatusPointer->Expression<6)) {
17061 /* In a blink. */
17062 Marine_SwitchExpression(sbPtr,5);
17063 if (marineStatusPointer->Blink<0) {
17064 /* Dunno why, but you never know. */
17065 marineStatusPointer->Blink=0;
17066 }
17067 } else {
17068 /* Not in a blink. */
17069 Marine_SwitchExpression(sbPtr,2);
17070 }
17071
17072 }
17073
17074 void Marine_AssumeWink1Expression(STRATEGYBLOCK *sbPtr) {
17075
17076 MARINE_STATUS_BLOCK *marineStatusPointer;
17077
17078 LOCALASSERT(sbPtr);
17079 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17080 LOCALASSERT(marineStatusPointer);
17081
17082 /* Who cares about blinking? */
17083 Marine_SwitchExpression(sbPtr,6);
17084 marineStatusPointer->Blink=-1;
17085
17086 }
17087
17088 void Marine_AssumeWink2Expression(STRATEGYBLOCK *sbPtr) {
17089
17090 MARINE_STATUS_BLOCK *marineStatusPointer;
17091
17092 LOCALASSERT(sbPtr);
17093 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17094 LOCALASSERT(marineStatusPointer);
17095
17096 /* Who cares about blinking? */
17097 Marine_SwitchExpression(sbPtr,7);
17098 marineStatusPointer->Blink=-1;
17099
17100 }
17101
17102 static STATE_RETURN_CONDITION Execute_MNS_PumpAction(STRATEGYBLOCK *sbPtr)
17103 {
17104
17105 MARINE_STATUS_BLOCK *marineStatusPointer;
17106 int range;
17107
17108 LOCALASSERT(sbPtr);
17109 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17110 LOCALASSERT(marineStatusPointer);
17111
17112 /* zero velocity */
17113 LOCALASSERT(sbPtr->DynPtr);
17114 sbPtr->DynPtr->LinVelocity.vx = 0;
17115 sbPtr->DynPtr->LinVelocity.vy = 0;
17116 sbPtr->DynPtr->LinVelocity.vz = 0;
17117
17118 if (!sbPtr->SBdptr) {
17119 /* We're far... do the timer! */
17120 ProveHModel_Far(&marineStatusPointer->HModelController,sbPtr);
17121 }
17122
17123 if (!(HModelAnimation_IsFinished(&marineStatusPointer->HModelController))) {
17124 return(SRC_No_Change);
17125 }
17126
17127 /* Exit procedure... same as firing was. */
17128
17129 if (marineStatusPointer->Target==NULL) {
17130 return(SRC_Request_Wait);
17131 }
17132
17133 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
17134
17135 /* State timer should be continuous from fire state. */
17136 if(marineStatusPointer->stateTimer > 0) {
17137 #if MARINE_STATE_PRINT
17138 textprint("Returning firing at range %d.\n",range);
17139 #endif
17140 return(SRC_Request_Fire);
17141 }
17142
17143 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
17144 {
17145 /* renew firing, as we are still too close to approach */
17146 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
17147 marineStatusPointer->volleySize = 0;
17148 GLOBALASSERT(marineStatusPointer->Target);
17149 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
17150 #if MARINE_STATE_PRINT
17151 textprint("Returning too close firing at range %d.\n",range);
17152 #endif
17153 return(SRC_Request_Fire);
17154 }
17155 else
17156 {
17157 /* we are far enough away, so return to approach */
17158
17159 if (marineStatusPointer->Android) {
17160 return(SRC_Request_Fire);
17161 } else {
17162 #if MARINE_STATE_PRINT
17163 textprint("Returning too far termination at range %d.\n",range);
17164 #endif
17165 return(SRC_Request_Approach);
17166 }
17167 }
17168 return(SRC_Request_Fire);
17169
17170 }
17171
17172 void Marine_CorpseSightingTest(STRATEGYBLOCK *corpse) {
17173
17174 int a;
17175 STRATEGYBLOCK *candidate;
17176 MARINE_STATUS_BLOCK *marineStatusPointer;
17177
17178 /* This is called from CORPSE behaviour. */
17179 for (a=0; a<NumActiveStBlocks; a++) {
17180 candidate=ActiveStBlockList[a];
17181 GLOBALASSERT(candidate);
17182
17183 if (candidate->I_SBtype==I_BehaviourMarine) {
17184 /* Are you already suspicious? */
17185 marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr);
17186
17187 if (((marineStatusPointer->suspicious==0)||(marineStatusPointer->using_squad_suspicion))
17188 /* As if we'd care... */
17189 &&(marineStatusPointer->Target==NULL)
17190 /* To make the tests a bit rarer. */
17191 &&(marineStatusPointer->incidentFlag)) {
17192 /* Did you see that? */
17193 if (NPCCanSeeTarget(candidate,corpse,MARINE_NEAR_VIEW_WIDTH)) {
17194 /* Okay, react. */
17195 marineStatusPointer->suspicious=MARINE_PARANOIA_TIME;
17196 marineStatusPointer->suspect_point=corpse->DynPtr->Position;
17197 /* Set this to zero when you get a *new* suspicion. */
17198 marineStatusPointer->previous_suspicion=0;
17199 marineStatusPointer->using_squad_suspicion=0;
17200 }
17201 }
17202 }
17203 }
17204 }
17205
17206 void Marine_MuteVoice(STRATEGYBLOCK *sbPtr) {
17207
17208 MARINE_STATUS_BLOCK *marineStatusPointer;
17209
17210 LOCALASSERT(sbPtr);
17211 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17212 LOCALASSERT(marineStatusPointer);
17213
17214 if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
17215 /* Cut them off! */
17216 Sound_Stop(marineStatusPointer->soundHandle2);
17217 }
17218
17219 }
17220
17221 void Marine_OoophSound(STRATEGYBLOCK *sbPtr) {
17222
17223 MARINE_STATUS_BLOCK *marineStatusPointer;
17224
17225 LOCALASSERT(sbPtr);
17226 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17227 LOCALASSERT(marineStatusPointer);
17228
17229 if (marineStatusPointer->Android) {
17230 return;
17231 }
17232
17233 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17234 PlayMarineScream(marineStatusPointer->Voice,SC_Oooph,marineStatusPointer->VoicePitch,
17235 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17236 }
17237 }
17238
17239 void Marine_SurpriseSound(STRATEGYBLOCK *sbPtr) {
17240
17241 MARINE_STATUS_BLOCK *marineStatusPointer;
17242
17243 LOCALASSERT(sbPtr);
17244 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17245 LOCALASSERT(marineStatusPointer);
17246
17247 if (marineStatusPointer->Android) {
17248 return;
17249 }
17250
17251 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17252 PlayMarineScream(marineStatusPointer->Voice,SC_Surprise,marineStatusPointer->VoicePitch,
17253 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17254 if (marineStatusPointer->Android==0) {
17255 marineStatusPointer->Courage-=5000;
17256 }
17257 }
17258
17259 /* Open the mouth? */
17260 Marine_AssumePanicExpression(sbPtr);
17261
17262 }
17263
17264 void Marine_WoundedScream(STRATEGYBLOCK *sbPtr) {
17265
17266 MARINE_STATUS_BLOCK *marineStatusPointer;
17267
17268 LOCALASSERT(sbPtr);
17269 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17270 LOCALASSERT(marineStatusPointer);
17271
17272 if (marineStatusPointer->Android) {
17273 return;
17274 }
17275
17276 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17277 PlayMarineScream(marineStatusPointer->Voice,SC_Pain,marineStatusPointer->VoicePitch,
17278 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17279 }
17280 }
17281
17282 void Marine_AcidScream(STRATEGYBLOCK *sbPtr) {
17283
17284 MARINE_STATUS_BLOCK *marineStatusPointer;
17285
17286 LOCALASSERT(sbPtr);
17287 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17288 LOCALASSERT(marineStatusPointer);
17289
17290 if (marineStatusPointer->Android) {
17291 return;
17292 }
17293
17294 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17295 PlayMarineScream(marineStatusPointer->Voice,SC_Acid,marineStatusPointer->VoicePitch,
17296 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17297 }
17298 }
17299
17300 void Marine_BurningScream(STRATEGYBLOCK *sbPtr) {
17301
17302 MARINE_STATUS_BLOCK *marineStatusPointer;
17303
17304 LOCALASSERT(sbPtr);
17305 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17306 LOCALASSERT(marineStatusPointer);
17307
17308 if (marineStatusPointer->Android) {
17309 return;
17310 }
17311
17312 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17313 PlayMarineScream(marineStatusPointer->Voice,SC_OnFire,marineStatusPointer->VoicePitch,
17314 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17315 }
17316 /* Urgh, that was really grim. */
17317
17318 }
17319
17320 void Marine_DeathScream(STRATEGYBLOCK *sbPtr) {
17321
17322 MARINE_STATUS_BLOCK *marineStatusPointer;
17323
17324 LOCALASSERT(sbPtr);
17325 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17326 LOCALASSERT(marineStatusPointer);
17327
17328 if (marineStatusPointer->Android) {
17329 return;
17330 }
17331
17332 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17333 /* I figure if you're screaming already, forget it. */
17334 PlayMarineScream(marineStatusPointer->Voice,SC_Death,marineStatusPointer->VoicePitch,
17335 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17336 }
17337
17338 }
17339
17340 void Marine_ElectrocutionScream(STRATEGYBLOCK *sbPtr) {
17341
17342 MARINE_STATUS_BLOCK *marineStatusPointer;
17343
17344 LOCALASSERT(sbPtr);
17345 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17346 LOCALASSERT(marineStatusPointer);
17347
17348 if (marineStatusPointer->Android) {
17349 return;
17350 }
17351
17352 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17353 /* I figure if you're screaming already, forget it. */
17354 PlayMarineScream(marineStatusPointer->Voice,SC_Electrocution,marineStatusPointer->VoicePitch,
17355 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17356 }
17357
17358 }
17359
17360 void Marine_BurningDeathScream(STRATEGYBLOCK *sbPtr) {
17361
17362 MARINE_STATUS_BLOCK *marineStatusPointer;
17363
17364 LOCALASSERT(sbPtr);
17365 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17366 LOCALASSERT(marineStatusPointer);
17367
17368 if (marineStatusPointer->Android) {
17369 return;
17370 }
17371
17372 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17373 /* I figure if you're screaming already, forget it. */
17374 PlayMarineScream(marineStatusPointer->Voice,SC_OnFire,marineStatusPointer->VoicePitch,
17375 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17376 }
17377 /* That too was really quite unpleasant. */
17378
17379 }
17380
17381 void Marine_AngryScream(STRATEGYBLOCK *sbPtr) {
17382
17383 MARINE_STATUS_BLOCK *marineStatusPointer;
17384
17385 LOCALASSERT(sbPtr);
17386 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17387 LOCALASSERT(marineStatusPointer);
17388
17389 if (marineStatusPointer->Android) {
17390 return;
17391 }
17392
17393 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17394 PlayMarineScream(marineStatusPointer->Voice,SC_Angry,marineStatusPointer->VoicePitch,
17395 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17396 }
17397 }
17398
17399 void Marine_PanicScream(STRATEGYBLOCK *sbPtr) {
17400
17401 MARINE_STATUS_BLOCK *marineStatusPointer;
17402
17403 LOCALASSERT(sbPtr);
17404 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17405 LOCALASSERT(marineStatusPointer);
17406
17407 if (marineStatusPointer->Android) {
17408 return;
17409 }
17410
17411 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17412 PlayMarineScream(marineStatusPointer->Voice,SC_Panic,marineStatusPointer->VoicePitch,
17413 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17414 }
17415 }
17416
17417 void Marine_Sobbing(STRATEGYBLOCK *sbPtr) {
17418
17419 MARINE_STATUS_BLOCK *marineStatusPointer;
17420
17421 LOCALASSERT(sbPtr);
17422 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17423 LOCALASSERT(marineStatusPointer);
17424
17425 if (marineStatusPointer->Android) {
17426 return;
17427 }
17428
17429 /* This is getting quite upsetting... */
17430
17431 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17432 PlayMarineScream(marineStatusPointer->Voice,SC_Sobbing,marineStatusPointer->VoicePitch,
17433 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17434 }
17435 }
17436
17437 void Marine_TauntShout(STRATEGYBLOCK *sbPtr) {
17438
17439 MARINE_STATUS_BLOCK *marineStatusPointer;
17440
17441 LOCALASSERT(sbPtr);
17442 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17443 LOCALASSERT(marineStatusPointer);
17444
17445 if (marineStatusPointer->Android) {
17446 return;
17447 }
17448
17449 if (marineStatusPointer->soundHandle2==SOUND_NOACTIVEINDEX) {
17450 PlayMarineScream(marineStatusPointer->Voice,SC_Taunt,marineStatusPointer->VoicePitch,
17451 &marineStatusPointer->soundHandle2,&sbPtr->DynPtr->Position);
17452 }
17453 }
17454
17455 int Marine_HasHisMouthOpen(STRATEGYBLOCK *sbPtr) {
17456
17457 MARINE_STATUS_BLOCK *marineStatusPointer;
17458
17459 LOCALASSERT(sbPtr);
17460 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17461 LOCALASSERT(marineStatusPointer);
17462
17463 if ((marineStatusPointer->Expression==2)||(marineStatusPointer->Expression==5)) {
17464 /* yeah, okay, it's hard coded. */
17465 return(1);
17466 } else {
17467 return(0);
17468 }
17469
17470 }
17471
17472 void Marine_QueueNeutralExpression(STRATEGYBLOCK *sbPtr) {
17473
17474 MARINE_STATUS_BLOCK *marineStatusPointer;
17475
17476 LOCALASSERT(sbPtr);
17477 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17478 LOCALASSERT(marineStatusPointer);
17479
17480 marineStatusPointer->Target_Expression=0;
17481
17482 }
17483
17484 void Marine_QueueGrimaceExpression(STRATEGYBLOCK *sbPtr) {
17485
17486 MARINE_STATUS_BLOCK *marineStatusPointer;
17487
17488 LOCALASSERT(sbPtr);
17489 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17490 LOCALASSERT(marineStatusPointer);
17491
17492 marineStatusPointer->Target_Expression=1;
17493
17494 }
17495
17496 void Marine_QueuePanicExpression(STRATEGYBLOCK *sbPtr) {
17497
17498 MARINE_STATUS_BLOCK *marineStatusPointer;
17499
17500 LOCALASSERT(sbPtr);
17501 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17502 LOCALASSERT(marineStatusPointer);
17503
17504 marineStatusPointer->Target_Expression=2;
17505
17506 }
17507
17508 void Marine_QueueWink1Expression(STRATEGYBLOCK *sbPtr) {
17509
17510 MARINE_STATUS_BLOCK *marineStatusPointer;
17511
17512 LOCALASSERT(sbPtr);
17513 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17514 LOCALASSERT(marineStatusPointer);
17515
17516 marineStatusPointer->Target_Expression=6;
17517
17518 }
17519
17520 void Marine_QueueWink2Expression(STRATEGYBLOCK *sbPtr) {
17521
17522 MARINE_STATUS_BLOCK *marineStatusPointer;
17523
17524 LOCALASSERT(sbPtr);
17525 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17526 LOCALASSERT(marineStatusPointer);
17527
17528 marineStatusPointer->Target_Expression=7;
17529
17530 }
17531
17532 void Marine_UpdateFace(STRATEGYBLOCK *sbPtr) {
17533
17534 MARINE_STATUS_BLOCK *marineStatusPointer;
17535
17536 LOCALASSERT(sbPtr);
17537 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17538 LOCALASSERT(marineStatusPointer);
17539
17540 if (marineStatusPointer->Expression!=marineStatusPointer->Target_Expression) {
17541 /* Right, consider this. */
17542 if (Marine_HasHisMouthOpen(sbPtr)) {
17543 /* Does the target expression also have it's mouth open? */
17544 if (!((marineStatusPointer->Target_Expression==2)||(marineStatusPointer->Target_Expression==5))) {
17545 /* Are we screaming? */
17546 if (marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
17547 /* Can't close our mouth yet. */
17548 return;
17549 }
17550 }
17551 }
17552 }
17553 /* Also ignore if you're in the wink counterpart of the target. */
17554 switch (marineStatusPointer->Target_Expression) {
17555 case 0:
17556 if (marineStatusPointer->Expression==3) {
17557 return;
17558 }
17559 break;
17560 case 1:
17561 if (marineStatusPointer->Expression==4) {
17562 return;
17563 }
17564 break;
17565 case 2:
17566 if (marineStatusPointer->Expression==5) {
17567 return;
17568 }
17569 break;
17570 default:
17571 break;
17572 }
17573 /* Exit if current==target? */
17574 if (marineStatusPointer->Expression==marineStatusPointer->Target_Expression) {
17575 return;
17576 }
17577
17578 /* If we got here, it must be okay... but do it properly! */
17579 switch (marineStatusPointer->Target_Expression) {
17580 case 0:
17581 case 3:
17582 Marine_AssumeNeutralExpression(sbPtr);
17583 break;
17584 case 1:
17585 case 4:
17586 Marine_AssumeGrimaceExpression(sbPtr);
17587 break;
17588 case 2:
17589 case 5:
17590 Marine_AssumePanicExpression(sbPtr);
17591 break;
17592 case 6:
17593 Marine_AssumeWink1Expression(sbPtr);
17594 break;
17595 case 7:
17596 Marine_AssumeWink2Expression(sbPtr);
17597 break;
17598 default:
17599 GLOBALASSERT(0);
17600 break;
17601 }
17602 }
17603
17604 static void Marine_MirrorSuspectPoint(STRATEGYBLOCK *sbPtr) {
17605
17606 MARINE_STATUS_BLOCK *marineStatusPointer;
17607
17608 LOCALASSERT(sbPtr);
17609 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17610 LOCALASSERT(marineStatusPointer);
17611
17612 {
17613 VECTORCH offset;
17614
17615 offset.vx=marineStatusPointer->suspect_point.vx-sbPtr->DynPtr->Position.vx;
17616 offset.vy=marineStatusPointer->suspect_point.vy-sbPtr->DynPtr->Position.vy;
17617 offset.vz=marineStatusPointer->suspect_point.vz-sbPtr->DynPtr->Position.vz;
17618
17619 marineStatusPointer->suspect_point.vx=sbPtr->DynPtr->Position.vx-offset.vx;
17620 marineStatusPointer->suspect_point.vy=sbPtr->DynPtr->Position.vy-offset.vy;
17621 marineStatusPointer->suspect_point.vz=sbPtr->DynPtr->Position.vz-offset.vz;
17622 }
17623
17624 }
17625
17626
17627
17628 void SendRequestToMarine(STRATEGYBLOCK* sbPtr,BOOL state,int extended_data)
17629 {
17630 //handle RequestState (from switches etc.)
17631
17632 MARINE_STATUS_BLOCK *marineStatusPointer;
17633
17634 LOCALASSERT(sbPtr);
17635 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17636 LOCALASSERT(marineStatusPointer);
17637
17638 if(extended_data & 1)
17639 {
17640 //change mission type
17641 MARINE_MISSION new_mission=MM_Wait_Then_Wander;
17642 int new_path=-1;
17643 int new_stepnumber=-1;
17644 //state must be 1
17645 if(!state) return;
17646
17647 //can't change mission type if non-combatant or if on fire
17648 if(marineStatusPointer->Mission==MM_NonCom ||
17649 marineStatusPointer->Mission==MM_RunAroundOnFire)
17650 return;
17651
17652 switch((extended_data>>7)&0xff)
17653 {
17654 case 0:
17655 new_mission=MM_Wait_Then_Wander;
17656 break;
17657 case 1:
17658 new_mission=MM_Wander;
17659 break;
17660 case 2:
17661 new_mission=MM_Guard;
17662 //need to cacluculate mission module from 'myspot' guard location
17663 {
17664 MODULE* module=ModuleFromPosition(&marineStatusPointer->my_spot,0);
17665 GLOBALASSERT(module);
17666 marineStatusPointer->missionmodule=module->m_aimodule;
17667 }
17668 break;
17669 case 3:
17670 new_mission=MM_LocalGuard;
17671 break;
17672 case 4:
17673 new_mission=MM_Pathfinder;
17674 break;
17675
17676 }
17677 if(new_mission==MM_Pathfinder)
17678 {
17679 //find the path and stepnumber
17680 new_path=(extended_data>>15)&0xff;
17681 new_stepnumber=GetClosestStepInPath(new_path,sbPtr->containingModule);
17682 }
17683
17684 marineStatusPointer->path=new_path;
17685 marineStatusPointer->stepnumber=new_stepnumber;
17686 InitMission(sbPtr,new_mission);
17687
17688 }
17689
17690 }
17691
17692 static void Marine_ConsiderFallingDamage(STRATEGYBLOCK *sbPtr) {
17693
17694 MARINE_STATUS_BLOCK *marineStatusPointer;
17695
17696 LOCALASSERT(sbPtr);
17697 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17698 LOCALASSERT(marineStatusPointer);
17699
17700 if (sbPtr->DynPtr->IsInContactWithFloor) {
17701 if (marineStatusPointer->lastframe_fallingspeed>0) {
17702
17703 if (marineStatusPointer->lastframe_fallingspeed>Marine_Terminal_Velocity) {
17704 VECTORCH point,point2;
17705 enum PARTICLE_ID blood_type;
17706
17707 /* Kill marine... */
17708 CauseDamageToObject(sbPtr,&FallingDamage, (50*ONE_FIXED), NULL);
17709 /* Experiment with blood. */
17710 GetTargetingPointOfObject_Far(sbPtr,&point);
17711 point2=sbPtr->DynPtr->Position;
17712 point2.vy-=200;
17713 blood_type=GetBloodType(sbPtr);
17714 MakeBloodExplosion(&point2,127,&point,50,blood_type);
17715 /* Crunching sound optional. */
17716 }
17717 }
17718 marineStatusPointer->lastframe_fallingspeed=0;
17719 } else {
17720 /* Compute falling speed. */
17721 if (marineStatusPointer->lastframe_fallingspeed>=0) {
17722 int offset;
17723
17724 offset=sbPtr->DynPtr->Position.vy-sbPtr->DynPtr->PrevPosition.vy;
17725
17726 marineStatusPointer->lastframe_fallingspeed=DIV_FIXED(offset,NormalFrameTime);
17727 if (marineStatusPointer->lastframe_fallingspeed<0) {
17728 marineStatusPointer->lastframe_fallingspeed=0;
17729 }
17730 } else {
17731 marineStatusPointer->lastframe_fallingspeed=0;
17732 }
17733 }
17734 }
17735
17736 static STATE_RETURN_CONDITION Execute_MNS_DischargeSmartgun(STRATEGYBLOCK *sbPtr)
17737 {
17738 MARINE_STATUS_BLOCK *marineStatusPointer;
17739 VECTORCH orientationDirn,relPos,relPos2;
17740 int correctlyOrientated,range;
17741
17742 /* Alternative smartgun function? */
17743
17744 LOCALASSERT(sbPtr);
17745 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
17746 LOCALASSERT(marineStatusPointer);
17747
17748 marineStatusPointer->HModelController.Playing=1;
17749
17750 #if MARINE_STATE_PRINT
17751 textprint("Marine firing... ");
17752 #endif
17753
17754 /* zero velocity */
17755 LOCALASSERT(sbPtr->DynPtr);
17756 sbPtr->DynPtr->LinVelocity.vx = 0;
17757 sbPtr->DynPtr->LinVelocity.vy = 0;
17758 sbPtr->DynPtr->LinVelocity.vz = 0;
17759
17760 /* first of all, validate this state: if the target suddenly becomes cloaked, then
17761 we should switch immediately to wait state*/
17762 if (marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize) {
17763 /* Keep firing! */
17764 } else {
17765 if(!MarineCanSeeTarget(sbPtr))
17766 {
17767
17768 /* ... and remove the gunflash */
17769 if(marineStatusPointer->myGunFlash)
17770 {
17771 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
17772 marineStatusPointer->myGunFlash = NULL;
17773 }
17774
17775 /* .... and stop the sound */
17776 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
17777 Sound_Stop(marineStatusPointer->soundHandle);
17778 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
17779 }
17780
17781 #if MARINE_STATE_PRINT
17782 textprint("Returning no target.\n");
17783 #endif
17784 marineStatusPointer->lastroundhit=0;
17785 marineStatusPointer->lasthitsection=NULL;
17786 return(SRC_Request_Wait);
17787 }
17788 }
17789
17790 if (marineStatusPointer->clipammo==0) {
17791 /* Reload here. */
17792 return(SRC_Request_Reload);
17793 }
17794
17795
17796 if (marineStatusPointer->Target) {
17797 GLOBALASSERT(marineStatusPointer->Target);
17798 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
17799 /* Fix weapon target! */
17800 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
17801 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
17802 marineStatusPointer->My_Weapon->TargetCallibrationShift);
17803 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
17804 marineStatusPointer->My_Weapon->TargetCallibrationShift);
17805 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
17806 marineStatusPointer->My_Weapon->TargetCallibrationShift);
17807 }
17808
17809 /* Here we must have a target. Renew suspicion for new arrivals. */
17810 if (NpcSquad.Squad_Suspicion==0) {
17811 PointAlert(2,&marineStatusPointer->weaponTarget);
17812 }
17813 }
17814 /* Otherwise, stay facing the same way. */
17815
17816 /* orientate to firing point first */
17817 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
17818 orientationDirn.vy = 0;
17819 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
17820 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
17821
17822 /* I have a cunning plan... */
17823 {
17824 DELTA_CONTROLLER *delta;
17825
17826 delta=Get_Delta_Sequence(&marineStatusPointer->HModelController,"HitDelta");
17827 if (delta) {
17828 if (!(DeltaAnimation_IsFinished(delta))) {
17829 correctlyOrientated=0;
17830 }
17831 }
17832 }
17833 /* I have another cunning plan... */
17834 if ((marineStatusPointer->volleySize>0)&&
17835 (marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize)) {
17836 correctlyOrientated=1;
17837 }
17838
17839
17840 /* we are not correctly orientated to the target: this could happen because we have
17841 just entered this state, or the target has moved during firing*/
17842 if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening!=Controller_NoTweening)) {
17843
17844 /* stop visual and audio cues: technically, we're not firing at this moment */
17845 if(marineStatusPointer->myGunFlash)
17846 {
17847 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
17848 marineStatusPointer->myGunFlash = NULL;
17849 }
17850
17851 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
17852 Sound_Stop(marineStatusPointer->soundHandle);
17853 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
17854 }
17855 #if MARINE_STATE_PRINT
17856 textprint("Turning to face.\n");
17857 #endif
17858 marineStatusPointer->lastroundhit=0;
17859 marineStatusPointer->lasthitsection=NULL;
17860 return(SRC_No_Change);
17861 }
17862
17863 if (marineStatusPointer->Target) {
17864 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
17865 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
17866 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
17867
17868 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
17869 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
17870 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
17871
17872 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
17873 }
17874
17875 #if 0
17876 DischargeLOSWeapon_Core(sbPtr);
17877 #else
17878 {
17879 int volleytime,volleyrounds;
17880
17881 /* look after the gun flash */
17882 if(marineStatusPointer->myGunFlash) {
17883 MaintainMarineGunFlash(sbPtr);
17884 } else {
17885 CreateMarineGunFlash(sbPtr);
17886 }
17887
17888 /* look after the sound */
17889 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
17890 else
17891 {
17892 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
17893 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
17894 }
17895
17896 marineStatusPointer->stateTimer -= NormalFrameTime;
17897
17898 /* Volleysize is now rounds fired this state. */
17899
17900 volleytime=marineStatusPointer->My_Weapon->FiringTime-marineStatusPointer->stateTimer;
17901 /* It was that or reverse the state timer for this state. */
17902 volleyrounds=MUL_FIXED(volleytime,marineStatusPointer->My_Weapon->FiringRate);
17903 volleyrounds>>=ONE_FIXED_SHIFT;
17904
17905 volleyrounds-=marineStatusPointer->volleySize;
17906 marineStatusPointer->volleySize+=volleyrounds;
17907
17908 LOCALASSERT(volleyrounds>=0);
17909
17910 if (marineStatusPointer->clipammo!=-1) {
17911 /* We're counting ammo. */
17912 if (volleyrounds>marineStatusPointer->clipammo) {
17913 volleyrounds=marineStatusPointer->clipammo;
17914 }
17915 marineStatusPointer->clipammo-=volleyrounds;
17916 LOCALASSERT(marineStatusPointer->clipammo>=0);
17917 }
17918
17919 marineStatusPointer->roundsForThisTarget+=volleyrounds;
17920
17921 /* Now hit the target with volleyrounds bullets. */
17922
17923 {
17924 VECTORCH shotvector;
17925
17926 shotvector.vx=0;
17927 shotvector.vy=0;
17928 shotvector.vz=65535;
17929 RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat);
17930
17931 CastLOSProjectile(sbPtr,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, volleyrounds,1);
17932 }
17933 }
17934 #endif
17935
17936 if (marineStatusPointer->Target==NULL) {
17937 /* Getting out of here! */
17938 return(SRC_No_Change);
17939 }
17940
17941 /* Did we get him? */
17942 if ((NPC_IsDead(marineStatusPointer->Target))
17943 &&(marineStatusPointer->volleySize>=marineStatusPointer->My_Weapon->MinimumBurstSize)) {
17944 if (MarineRetreatsInTheFaceOfDanger(sbPtr)) {
17945 if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) {
17946 /* Huzzah! */
17947 if(marineStatusPointer->myGunFlash)
17948 {
17949 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
17950 marineStatusPointer->myGunFlash = NULL;
17951 }
17952 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
17953 Sound_Stop(marineStatusPointer->soundHandle);
17954 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
17955 }
17956 marineStatusPointer->lastroundhit=0;
17957 marineStatusPointer->lasthitsection=NULL;
17958 return(SRC_Request_Taunt);
17959 }
17960 }
17961 }
17962
17963 if(marineStatusPointer->stateTimer > 0) {
17964 #if MARINE_STATE_PRINT
17965 textprint("Returning continue at range %d.\n",range);
17966 #endif
17967 return(SRC_No_Change);
17968 }
17969
17970 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
17971 {
17972 /* renew firing, as we are still too close to approach */
17973 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
17974 marineStatusPointer->volleySize = 0;
17975 GLOBALASSERT(marineStatusPointer->Target);
17976 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
17977 #if MARINE_STATE_PRINT
17978 textprint("Returning too close renewal at range %d.\n",range);
17979 #endif
17980 #if 1
17981 /* stop visual and audio cues: technically, we're not firing at this moment */
17982 if(marineStatusPointer->myGunFlash)
17983 {
17984 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
17985 marineStatusPointer->myGunFlash = NULL;
17986 }
17987 #endif
17988 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
17989 Sound_Stop(marineStatusPointer->soundHandle);
17990 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
17991 }
17992 if (marineStatusPointer->Android==0) {
17993 marineStatusPointer->Courage-=(ONE_FIXED>>3);
17994 }
17995 return(SRC_Request_Fire);
17996 }
17997 else
17998 {
17999 /* we are far enough away, so return to approach */
18000
18001 #if 1
18002 /* ... and remove the gunflash */
18003 if(marineStatusPointer->myGunFlash)
18004 {
18005 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18006 marineStatusPointer->myGunFlash = NULL;
18007 }
18008 #endif
18009 /* .... and stop the sound */
18010 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18011 Sound_Stop(marineStatusPointer->soundHandle);
18012 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18013 }
18014 #if MARINE_STATE_PRINT
18015 textprint("Returning too far termination at range %d.\n",range);
18016 #endif
18017 return(SRC_Request_Approach);
18018 }
18019 return(SRC_No_Change);
18020 }
18021
18022 int MakeModifiedTargetNum(int targetnum,int dist) {
18023
18024 /* Adjust targetnum by range? */
18025 if (dist>10000) {
18026 int factor,tdist;
18027
18028 tdist=dist-10000;
18029 if (tdist>100000) {
18030 tdist=100000;
18031 }
18032 factor=DIV_FIXED(tdist,100000);
18033 factor=ONE_FIXED-factor;
18034 if (factor<(ONE_FIXED>>3)) {
18035 factor=(ONE_FIXED>>3);
18036 }
18037
18038 return(MUL_FIXED(factor,targetnum));
18039 }
18040 return(targetnum);
18041 }
18042
18043
18044
18045
18046
18047 /*--------------------**
18048 ** Loading and Saving **
18049 **--------------------*/
18050 #include "savegame.h"
18051 typedef struct marine_save_block
18052 {
18053 SAVE_BLOCK_STRATEGY_HEADER header;
18054
18055 //from marine status block
18056 signed int health;
18057 signed int volleySize;
18058 signed int primaryWeaponDamage;
18059
18060 MARINE_BHSTATE behaviourState;
18061 MARINE_BHSTATE lastState;
18062
18063 MARINE_MISSION Mission;
18064
18065 VECTORCH my_spot;
18066 VECTORCH my_facing_point;
18067
18068 /* Movement data. */
18069 signed int nearSpeed;
18070 int acceleration;
18071 int speedConstant;
18072 int accelerationConstant;
18073 /* Sense data */
18074 int mtracker_timer;
18075 VECTORCH suspect_point;
18076 int suspicious;
18077 int previous_suspicion;
18078 int using_squad_suspicion;
18079 int sawlastframe;
18080 int gotapoint;
18081 int lastframe_fallingspeed;
18082 /* Pathfinder parameters */
18083 int path;
18084 int stepnumber;
18085 /* Pathfinder parameters */
18086 int stateTimer;
18087 int internalState;
18088
18089 VECTORCH weaponTarget; /* position for firing weapon at */
18090
18091 NPC_OBSTRUCTIONREPORT obstruction;
18092 NPC_WANDERDATA wanderData;
18093
18094 int IAmCrouched;
18095
18096 int lastroundhit;
18097
18098 int GibbFactor;
18099 int Wounds;
18100
18101 int incidentFlag;
18102 int incidentTimer;
18103
18104 int weapon_variable;
18105 int weapon_variable2;
18106 int clipammo;
18107 int roundsForThisTarget;
18108
18109 int Female;
18110 int Android;
18111 int Skill;
18112 int Courage;
18113 int Voice;
18114 int VoicePitch;
18115
18116 int FiringAnim;
18117 int Expression;
18118 int Target_Expression;
18119 int Blink;
18120 int SpotFlag;
18121
18122
18123 //annoying pointer related things
18124 int lastmodule_index;
18125 int destinationmodule_index;
18126 int missionmodule_index;
18127 int fearmodule_index;
18128
18129
18130 char Target_SBname[SB_NAME_LENGTH];
18131 char Generator_SBname[SB_NAME_LENGTH];
18132
18133 int weapon_id;
18134
18135 //strategyblock stuff
18136 int integrity;
18137 DAMAGEBLOCK SBDamageBlock;
18138 DYNAMICSBLOCK dynamics;
18139 }MARINE_SAVE_BLOCK;
18140
18141 //defines for load/save macros
18142 #define SAVELOAD_BLOCK block
18143 #define SAVELOAD_BEHAV marineStatusPointer
18144
18145
18146 void LoadStrategy_Marine(SAVE_BLOCK_STRATEGY_HEADER* header)
18147 {
18148 STRATEGYBLOCK* sbPtr;
18149 MARINE_STATUS_BLOCK* marineStatusPointer;
18150 MARINE_SAVE_BLOCK* block = (MARINE_SAVE_BLOCK*) header;
18151
18152 //check the size of the save block
18153 if(header->size!=sizeof(*block)) return;
18154
18155 //find the existing strategy block
18156 sbPtr = FindSBWithName(header->SBname);
18157
18158 if(sbPtr)
18159 {
18160 //make sure the strategy found is of the right type
18161 if(sbPtr->I_SBtype != I_BehaviourMarine) return;
18162 }
18163 else
18164 {
18165 //we will have to generate an alien then
18166 TOOLS_DATA_MARINE tdm;
18167
18168 //make sure the marine is in a module
18169 if(!ModuleFromPosition(&block->dynamics.Position,NULL)) return;
18170
18171 sbPtr = CreateActiveStrategyBlock();
18172 if(!sbPtr) return;
18173
18174 sbPtr->I_SBtype = I_BehaviourMarine;
18175 sbPtr->shapeIndex = 0;
18176 sbPtr->maintainVisibility = 1;
18177 COPY_NAME(sbPtr->SBname,block->header.SBname);
18178
18179 //create using a fake tools data
18180 memset(&tdm,0,sizeof(TOOLS_DATA_MARINE));
18181
18182 tdm.position = block->dynamics.Position;
18183 COPY_NAME(tdm.nameID,block->header.SBname);
18184 tdm. marine_type = block->weapon_id;
18185
18186 EnableBehaviourType(sbPtr,I_BehaviourMarine , &tdm );
18187
18188 }
18189
18190
18191 marineStatusPointer = (MARINE_STATUS_BLOCK*) sbPtr->SBdataptr;
18192
18193 //start copying stuff
18194
18195 COPYELEMENT_LOAD(health)
18196 COPYELEMENT_LOAD(volleySize)
18197 COPYELEMENT_LOAD(primaryWeaponDamage)
18198 COPYELEMENT_LOAD(behaviourState)
18199 COPYELEMENT_LOAD(lastState)
18200 COPYELEMENT_LOAD(Mission)
18201 COPYELEMENT_LOAD(my_spot)
18202 COPYELEMENT_LOAD(my_facing_point)
18203 COPYELEMENT_LOAD(nearSpeed)
18204 COPYELEMENT_LOAD(acceleration)
18205 COPYELEMENT_LOAD(speedConstant)
18206 COPYELEMENT_LOAD(accelerationConstant)
18207 COPYELEMENT_LOAD(mtracker_timer)
18208 COPYELEMENT_LOAD(suspect_point)
18209 COPYELEMENT_LOAD(suspicious)
18210 COPYELEMENT_LOAD(previous_suspicion)
18211 COPYELEMENT_LOAD(using_squad_suspicion)
18212 COPYELEMENT_LOAD(sawlastframe)
18213 COPYELEMENT_LOAD(gotapoint)
18214 COPYELEMENT_LOAD(lastframe_fallingspeed)
18215 COPYELEMENT_LOAD(path)
18216 COPYELEMENT_LOAD(stepnumber)
18217 COPYELEMENT_LOAD(stateTimer)
18218 COPYELEMENT_LOAD(internalState)
18219 COPYELEMENT_LOAD(weaponTarget) /* position for firing weapon at */
18220 COPYELEMENT_LOAD(obstruction)
18221 COPYELEMENT_LOAD(wanderData)
18222 COPYELEMENT_LOAD(IAmCrouched)
18223 COPYELEMENT_LOAD(lastroundhit)
18224 COPYELEMENT_LOAD(GibbFactor)
18225 COPYELEMENT_LOAD(Wounds)
18226
18227 COPYELEMENT_LOAD(incidentFlag)
18228 COPYELEMENT_LOAD(incidentTimer)
18229
18230 COPYELEMENT_LOAD(weapon_variable)
18231 COPYELEMENT_LOAD(weapon_variable2)
18232 COPYELEMENT_LOAD(clipammo)
18233 COPYELEMENT_LOAD(roundsForThisTarget)
18234
18235 COPYELEMENT_LOAD(Female)
18236 COPYELEMENT_LOAD(Android)
18237 COPYELEMENT_LOAD(Skill)
18238 COPYELEMENT_LOAD(Courage)
18239 COPYELEMENT_LOAD(Voice)
18240 COPYELEMENT_LOAD(VoicePitch)
18241
18242 COPYELEMENT_LOAD(FiringAnim)
18243 COPYELEMENT_LOAD(Expression)
18244 COPYELEMENT_LOAD(Target_Expression)
18245 COPYELEMENT_LOAD(Blink)
18246 COPYELEMENT_LOAD(SpotFlag)
18247
18248
18249 //load ai module pointers
18250 marineStatusPointer->lastmodule = GetPointerFromAIModuleIndex(block->lastmodule_index);
18251 marineStatusPointer->destinationmodule = GetPointerFromAIModuleIndex(block->destinationmodule_index);
18252 marineStatusPointer->missionmodule = GetPointerFromAIModuleIndex(block->missionmodule_index);
18253 marineStatusPointer->fearmodule = GetPointerFromAIModuleIndex(block->fearmodule_index);
18254
18255 //load target
18256 COPY_NAME(marineStatusPointer->Target_SBname,block->Target_SBname);
18257 marineStatusPointer->Target = FindSBWithName(marineStatusPointer->Target_SBname);
18258
18259
18260 //find the marine's generator
18261 marineStatusPointer->generator_sbptr = FindSBWithName(block->Generator_SBname);
18262
18263 //get marine's weapon
18264 marineStatusPointer->My_Weapon = GetThisNPCMarineWeapon(block->weapon_id);
18265
18266 //copy strategy block stuff
18267 *sbPtr->DynPtr = block->dynamics;
18268 sbPtr->integrity = block->integrity;
18269 sbPtr->SBDamageBlock = block->SBDamageBlock;
18270
18271 //load hierarchy
18272 {
18273 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
18274 if(hier_header)
18275 {
18276 LoadHierarchy(hier_header,&marineStatusPointer->HModelController);
18277 }
18278 }
18279
18280 //get section data pointers
18281 if(marineStatusPointer->My_Weapon)
18282 {
18283 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->GunflashName);
18284 marineStatusPointer->My_Elevation_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,marineStatusPointer->My_Weapon->ElevationSection);
18285 }
18286
18287 Load_SoundState(&marineStatusPointer->soundHandle);
18288 Load_SoundState(&marineStatusPointer->soundHandle2);
18289 }
18290
18291 void SaveStrategy_Marine(STRATEGYBLOCK* sbPtr)
18292 {
18293 MARINE_SAVE_BLOCK *block;
18294 MARINE_STATUS_BLOCK* marineStatusPointer;
18295
18296 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
18297 marineStatusPointer = (MARINE_STATUS_BLOCK*) sbPtr->SBdataptr;
18298
18299 //start copying stuff
18300
18301 COPYELEMENT_SAVE(health)
18302 COPYELEMENT_SAVE(volleySize)
18303 COPYELEMENT_SAVE(primaryWeaponDamage)
18304 COPYELEMENT_SAVE(behaviourState)
18305 COPYELEMENT_SAVE(lastState)
18306 COPYELEMENT_SAVE(Mission)
18307 COPYELEMENT_SAVE(my_spot)
18308 COPYELEMENT_SAVE(my_facing_point)
18309 COPYELEMENT_SAVE(nearSpeed)
18310 COPYELEMENT_SAVE(acceleration)
18311 COPYELEMENT_SAVE(speedConstant)
18312 COPYELEMENT_SAVE(accelerationConstant)
18313 COPYELEMENT_SAVE(mtracker_timer)
18314 COPYELEMENT_SAVE(suspect_point)
18315 COPYELEMENT_SAVE(suspicious)
18316 COPYELEMENT_SAVE(previous_suspicion)
18317 COPYELEMENT_SAVE(using_squad_suspicion)
18318 COPYELEMENT_SAVE(sawlastframe)
18319 COPYELEMENT_SAVE(gotapoint)
18320 COPYELEMENT_SAVE(lastframe_fallingspeed)
18321 COPYELEMENT_SAVE(path)
18322 COPYELEMENT_SAVE(stepnumber)
18323 COPYELEMENT_SAVE(stateTimer)
18324 COPYELEMENT_SAVE(internalState)
18325 COPYELEMENT_SAVE(weaponTarget) /* position for firing weapon at */
18326 COPYELEMENT_SAVE(obstruction)
18327 COPYELEMENT_SAVE(wanderData)
18328 COPYELEMENT_SAVE(IAmCrouched)
18329 COPYELEMENT_SAVE(lastroundhit)
18330 COPYELEMENT_SAVE(GibbFactor)
18331 COPYELEMENT_SAVE(Wounds)
18332
18333 COPYELEMENT_SAVE(incidentFlag)
18334 COPYELEMENT_SAVE(incidentTimer)
18335
18336 COPYELEMENT_SAVE(weapon_variable)
18337 COPYELEMENT_SAVE(weapon_variable2)
18338 COPYELEMENT_SAVE(clipammo)
18339 COPYELEMENT_SAVE(roundsForThisTarget)
18340
18341 COPYELEMENT_SAVE(Female)
18342 COPYELEMENT_SAVE(Android)
18343 COPYELEMENT_SAVE(Skill)
18344 COPYELEMENT_SAVE(Courage)
18345 COPYELEMENT_SAVE(Voice)
18346 COPYELEMENT_SAVE(VoicePitch)
18347
18348 COPYELEMENT_SAVE(FiringAnim)
18349 COPYELEMENT_SAVE(Expression)
18350 COPYELEMENT_SAVE(Target_Expression)
18351 COPYELEMENT_SAVE(Blink)
18352 COPYELEMENT_SAVE(SpotFlag)
18353
18354 //save ai module pointers
18355 block->lastmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->lastmodule);
18356 block->destinationmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->destinationmodule);
18357 block->missionmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->missionmodule);
18358 block->fearmodule_index = GetIndexFromAIModulePointer(marineStatusPointer->fearmodule);
18359
18360 //save target
18361 COPY_NAME(block->Target_SBname,marineStatusPointer->Target_SBname);
18362
18363 //save the marine's generator name
18364 if(marineStatusPointer->generator_sbptr)
18365 {
18366 COPY_NAME(block->Generator_SBname,marineStatusPointer->generator_sbptr->SBname);
18367 }
18368 else
18369 {
18370 COPY_NAME(block->Generator_SBname,Null_Name);
18371 }
18372
18373 //save marine's weapon
18374 if(marineStatusPointer->My_Weapon)
18375 block->weapon_id = marineStatusPointer->My_Weapon->id;
18376 else
18377 block->weapon_id = -1;
18378
18379 //copy strategy block stuff
18380 block->dynamics = *sbPtr->DynPtr;
18381 block->dynamics.CollisionReportPtr=0;
18382
18383 block->integrity = sbPtr->integrity;
18384 block->SBDamageBlock = sbPtr->SBDamageBlock;
18385
18386 //save the hierarchy
18387 SaveHierarchy(&marineStatusPointer->HModelController);
18388
18389 Save_SoundState(&marineStatusPointer->soundHandle);
18390 Save_SoundState(&marineStatusPointer->soundHandle2);
18391
18392 }
18393
18394
18395
18396 /*----------------------------**
18397 ** And now the squad state... **
18398 **----------------------------*/
18399
18400
18401 typedef struct marine_squad_save_block
18402 {
18403 SAVE_BLOCK_HEADER header;
18404
18405 int alertStatus;
18406 int responseLevel;
18407 int alertPriority;
18408
18409 int Squad_Suspicion;
18410 VECTORCH squad_suspect_point;
18411
18412 /* Now some stats. */
18413 int RespondingMarines;
18414 int Alt_RespondingMarines;
18415
18416 int NearUnpanickedMarines;
18417 int Alt_NearUnpanickedMarines;
18418
18419 int NearPanickedMarines;
18420 int Alt_NearPanickedMarines;
18421
18422 int NearBurningMarines;
18423 int Alt_NearBurningMarines;
18424
18425 int Squad_Delta_Morale;
18426 int Nextframe_Squad_Delta_Morale;
18427
18428 int alertZone_index;
18429
18430 }MARINE_SQUAD_SAVE_BLOCK;
18431
18432 #undef SAVELOAD_BEHAV
18433 //defines for load/save macros
18434 #define SAVELOAD_BEHAV (&NpcSquad)
18435
18436
18437 void LoadMarineSquadState(SAVE_BLOCK_HEADER* header)
18438 {
18439 MARINE_SQUAD_SAVE_BLOCK *block = (MARINE_SQUAD_SAVE_BLOCK*) header;
18440
18441 //check the size of the save block
18442 if(header->size!=sizeof(*block)) return;
18443
18444 //copy stuff
18445
18446 COPYELEMENT_LOAD(alertStatus)
18447 COPYELEMENT_LOAD(responseLevel)
18448 COPYELEMENT_LOAD(alertPriority)
18449 COPYELEMENT_LOAD(Squad_Suspicion)
18450 COPYELEMENT_LOAD(squad_suspect_point)
18451 COPYELEMENT_LOAD(RespondingMarines)
18452 COPYELEMENT_LOAD(Alt_RespondingMarines)
18453 COPYELEMENT_LOAD(NearUnpanickedMarines)
18454 COPYELEMENT_LOAD(Alt_NearUnpanickedMarines)
18455 COPYELEMENT_LOAD(NearPanickedMarines)
18456 COPYELEMENT_LOAD(Alt_NearPanickedMarines)
18457 COPYELEMENT_LOAD(NearBurningMarines)
18458 COPYELEMENT_LOAD(Alt_NearBurningMarines)
18459 COPYELEMENT_LOAD(Squad_Delta_Morale)
18460 COPYELEMENT_LOAD(Nextframe_Squad_Delta_Morale)
18461
18462 //and an aimodule
18463 NpcSquad.alertZone = GetPointerFromAIModuleIndex(block->alertZone_index);
18464
18465 }
18466
18467 void SaveMarineSquadState()
18468 {
18469 MARINE_SQUAD_SAVE_BLOCK * block;
18470
18471 GET_SAVE_BLOCK_POINTER(block);
18472
18473 //fill in the header
18474 block->header.type = SaveBlock_MarineSquad;
18475 block->header.size = sizeof(*block);
18476
18477 //copy stuff
18478
18479 COPYELEMENT_SAVE(alertStatus)
18480 COPYELEMENT_SAVE(responseLevel)
18481 COPYELEMENT_SAVE(alertPriority)
18482 COPYELEMENT_SAVE(Squad_Suspicion)
18483 COPYELEMENT_SAVE(squad_suspect_point)
18484 COPYELEMENT_SAVE(RespondingMarines)
18485 COPYELEMENT_SAVE(Alt_RespondingMarines)
18486 COPYELEMENT_SAVE(NearUnpanickedMarines)
18487 COPYELEMENT_SAVE(Alt_NearUnpanickedMarines)
18488 COPYELEMENT_SAVE(NearPanickedMarines)
18489 COPYELEMENT_SAVE(Alt_NearPanickedMarines)
18490 COPYELEMENT_SAVE(NearBurningMarines)
18491 COPYELEMENT_SAVE(Alt_NearBurningMarines)
18492 COPYELEMENT_SAVE(Squad_Delta_Morale)
18493 COPYELEMENT_SAVE(Nextframe_Squad_Delta_Morale)
18494
18495 //and an aimodule
18496 block->alertZone_index = GetIndexFromAIModulePointer(NpcSquad.alertZone);
18497 }
18498
18499 static STATE_RETURN_CONDITION Execute_MNS_DischargeTwoPistols(STRATEGYBLOCK *sbPtr)
18500 {
18501 MARINE_STATUS_BLOCK *marineStatusPointer;
18502 VECTORCH orientationDirn,relPos,relPos2;
18503 int correctlyOrientated,range;
18504 int mod,hitroll;
18505
18506 LOCALASSERT(sbPtr);
18507 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
18508 LOCALASSERT(marineStatusPointer);
18509
18510 LOCALASSERT(marineStatusPointer->My_Weapon->id==MNPCW_TwoPistols);
18511
18512 /* zero velocity */
18513 LOCALASSERT(sbPtr->DynPtr);
18514 sbPtr->DynPtr->LinVelocity.vx = 0;
18515 sbPtr->DynPtr->LinVelocity.vy = 0;
18516 sbPtr->DynPtr->LinVelocity.vz = 0;
18517
18518 if(!MarineCanSeeTarget(sbPtr))
18519 {
18520 /* Remove the gunflash */
18521 if(marineStatusPointer->myGunFlash)
18522 {
18523 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18524 marineStatusPointer->myGunFlash = NULL;
18525 }
18526 /* .... and stop the sound */
18527 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18528 Sound_Stop(marineStatusPointer->soundHandle);
18529 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18530 }
18531 return(SRC_Request_Wait);
18532 }
18533
18534 if (marineStatusPointer->clipammo==0) {
18535 /* Remove the gunflash */
18536 if(marineStatusPointer->myGunFlash)
18537 {
18538 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18539 marineStatusPointer->myGunFlash = NULL;
18540 }
18541 return(SRC_Request_Reload);
18542 }
18543
18544 #if MARINE_STATE_PRINT
18545 textprint("Firing pistol... ");
18546 #endif
18547
18548 /* Here we must have a target. Renew suspicion for new arrivals. */
18549 if (NpcSquad.Squad_Suspicion==0) {
18550 PointAlert(2,&marineStatusPointer->weaponTarget);
18551 }
18552
18553 /* first of all, validate this state: if the target suddenly becomes cloaked, then
18554 we should switch immediately to wait state.*/
18555
18556 //if ((marineStatusPointer->HModelController.keyframe_flags)
18557 // ||(marineStatusPointer->HModelController.Playing==0)) {
18558
18559 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
18560 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
18561 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
18562
18563 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
18564 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
18565 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
18566
18567 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
18568
18569 if (marineStatusPointer->volleySize==0) {
18570
18571 //marineStatusPointer->HModelController.Playing=0;
18572 //marineStatusPointer->HModelController.sequence_timer=0;
18573
18574 /* Only terminate if you haven't fired yet... */
18575 if(!MarineCanSeeTarget(sbPtr))
18576 {
18577 #if 1
18578 /* ... and remove the gunflash */
18579 if(marineStatusPointer->myGunFlash)
18580 {
18581 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18582 marineStatusPointer->myGunFlash = NULL;
18583 }
18584 #endif
18585
18586 /* .... and stop the sound */
18587 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18588 Sound_Stop(marineStatusPointer->soundHandle);
18589 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18590 }
18591
18592 #if MARINE_STATE_PRINT
18593 textprint("Returning no target.\n");
18594 #endif
18595 return(SRC_Request_Wait);
18596 }
18597
18598 GLOBALASSERT(marineStatusPointer->Target);
18599 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
18600 /* Fix weapon target! */
18601 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
18602 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
18603 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18604 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
18605 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18606 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
18607 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18608 }
18609
18610 /* orientate to firing point first */
18611 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
18612 orientationDirn.vy = 0;
18613 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
18614 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
18615
18616 /* we are not correctly orientated to the target: this could happen because we have
18617 just entered this state, or the target has moved during firing*/
18618 //if((!correctlyOrientated)||(marineStatusPointer->HModelController.Tweening==Controller_Tweening)) {
18619 if (!correctlyOrientated) {
18620
18621 #if 1
18622 /* stop visual and audio cues: technically, we're not firing at this moment */
18623 if(marineStatusPointer->myGunFlash)
18624 {
18625 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18626 marineStatusPointer->myGunFlash = NULL;
18627 }
18628 #endif
18629 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18630 Sound_Stop(marineStatusPointer->soundHandle);
18631 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18632 }
18633 #if MARINE_STATE_PRINT
18634 textprint("Turning to face.\n");
18635 #endif
18636 return(SRC_No_Change);
18637 }
18638
18639 /* If you are correctly oriented, you can now fire! */
18640
18641 marineStatusPointer->volleySize++;
18642 marineStatusPointer->HModelController.Playing=1;
18643 if (marineStatusPointer->clipammo>0) {
18644 marineStatusPointer->clipammo--;
18645 }
18646 marineStatusPointer->roundsForThisTarget++;
18647
18648 /* Alternate gun flash. */
18649 if (strcmp(marineStatusPointer->My_Gunflash_Section->sempai->Section_Name,"dum flash")==0) {
18650 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum L flash");
18651 } else {
18652 marineStatusPointer->My_Gunflash_Section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum flash");
18653 }
18654
18655 /* look after the gun flash */
18656 if(marineStatusPointer->myGunFlash) MaintainMarineGunFlash(sbPtr);
18657 else CreateMarineGunFlash(sbPtr);
18658
18659 /* look after the sound */
18660 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
18661 else
18662 {
18663 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"d",&(sbPtr->DynPtr->Position));
18664 Sound_Play(marineStatusPointer->My_Weapon->LoopSound,"del",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
18665 }
18666
18667 /* Now hit the target with one bullet. */
18668
18669 mod=SpeedRangeMods(&relPos,&relPos2);
18670
18671 hitroll=marineStatusPointer->Skill; /* Marine skill... */
18672 if (marineStatusPointer->Target==Player->ObStrategyBlock) {
18673 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
18674 LOCALASSERT(playerStatusPtr);
18675 if ( (AvP.PlayerType==I_Alien)
18676 ||((AvP.PlayerType==I_Predator)&&(playerStatusPtr->cloakOn==1))) {
18677 /* Vs the player, lighting effects on aliens and cloaked preds. */
18678 hitroll=MUL_FIXED(hitroll,((CurrentLightAtPlayer>>1)+32767));
18679 }
18680 }
18681 hitroll-=mod;
18682 hitroll+=marineStatusPointer->My_Weapon->Accuracy;
18683
18684 {
18685
18686 /* Handle Damage. */
18687 if ((FastRandom()&65535)<hitroll) {
18688 /* DO DAMAGE TO TARGET HERE */
18689
18690 VECTORCH rel_pos,attack_dir;
18691 int dist;
18692 VECTORCH shotvector;
18693
18694 shotvector.vx=0;
18695 shotvector.vy=0;
18696 shotvector.vz=65535;
18697 RotateVector(&shotvector,&marineStatusPointer->My_Gunflash_Section->SecMat);
18698
18699 rel_pos.vx=marineStatusPointer->Target->DynPtr->Position.vx-sbPtr->DynPtr->Position.vx;
18700 rel_pos.vy=marineStatusPointer->Target->DynPtr->Position.vy-sbPtr->DynPtr->Position.vy;
18701 rel_pos.vz=marineStatusPointer->Target->DynPtr->Position.vz-sbPtr->DynPtr->Position.vz;
18702
18703 dist=Approximate3dMagnitude(&rel_pos);
18704
18705 if (VerifyHitShot(sbPtr,marineStatusPointer->Target,&marineStatusPointer->My_Gunflash_Section->World_Offset,&shotvector, marineStatusPointer->My_Weapon->Ammo_Type, 1,dist)) {
18706
18707 GetDirectionOfAttack(marineStatusPointer->Target,&rel_pos,&attack_dir);
18708 /* Get hit location? */
18709
18710 marineStatusPointer->lasthitsection=HitLocationRoll(marineStatusPointer->Target,sbPtr);
18711
18712 if (marineStatusPointer->lasthitsection) {
18713 CauseDamageToHModel(marineStatusPointer->lasthitsection->my_controller, marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED, marineStatusPointer->lasthitsection,&attack_dir,NULL,0);
18714 } else {
18715 CauseDamageToObject(marineStatusPointer->Target,&TemplateAmmo[marineStatusPointer->My_Weapon->Ammo_Type].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
18716 }
18717 }
18718 } else {
18719 GLOBALASSERT(marineStatusPointer->My_Gunflash_Section);
18720 ProjectNPCShot(sbPtr, marineStatusPointer->Target, &marineStatusPointer->My_Gunflash_Section->World_Offset,&marineStatusPointer->My_Gunflash_Section->SecMat, marineStatusPointer->My_Weapon->Ammo_Type, 1);
18721 }
18722
18723 /* Did we get him? */
18724 if ((NPC_IsDead(marineStatusPointer->Target))&&(marineStatusPointer->My_Weapon->ARealMarine)) {
18725 /* Only real marines taunt. */
18726 if ((marineStatusPointer->roundsForThisTarget==1)||(MarineRetreatsInTheFaceOfDanger(sbPtr))) {
18727 if (Marine_GetNewTarget(&sbPtr->DynPtr->Position,sbPtr)==NULL) {
18728 /* Huzzah! */
18729 if(marineStatusPointer->myGunFlash)
18730 {
18731 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18732 marineStatusPointer->myGunFlash = NULL;
18733 }
18734 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18735 Sound_Stop(marineStatusPointer->soundHandle);
18736 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18737 }
18738 marineStatusPointer->lastroundhit=0;
18739 marineStatusPointer->lasthitsection=NULL;
18740 return(SRC_Request_Taunt);
18741 }
18742 }
18743 }
18744 }
18745 } else {
18746 /* Remove the gunflash */
18747 if(marineStatusPointer->myGunFlash)
18748 {
18749 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18750 marineStatusPointer->myGunFlash = NULL;
18751 }
18752 /* .... and stop the sound */
18753 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18754 Sound_Stop(marineStatusPointer->soundHandle);
18755 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18756 }
18757 }
18758
18759 marineStatusPointer->stateTimer -= (NormalFrameTime);
18760
18761 /* You must have fired already. */
18762
18763 if(marineStatusPointer->stateTimer > 0) {
18764 #if MARINE_STATE_PRINT
18765 textprint("Returning continue at range %d.\n",range);
18766 #endif
18767 return(SRC_No_Change);
18768 }
18769
18770 if ((range < MARINE_CLOSE_APPROACH_DISTANCE)||(marineStatusPointer->Android)
18771 //||(marineStatusPointer->volleySize<marineStatusPointer->My_Weapon->MinimumBurstSize))
18772 )
18773 {
18774 /* renew firing, as we are still too close to approach */
18775 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
18776 marineStatusPointer->volleySize = 0;
18777 GLOBALASSERT(marineStatusPointer->Target);
18778 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
18779 #if MARINE_STATE_PRINT
18780 textprint("Returning too close renewal at range %d.\n",range);
18781 #endif
18782 if (marineStatusPointer->Android==0) {
18783 // marineStatusPointer->Courage-=(ONE_FIXED>>3);
18784 }
18785 return(SRC_No_Change);
18786 }
18787 else
18788 {
18789 /* we are far enough away, so return to approach */
18790
18791 #if MARINE_STATE_PRINT
18792 textprint("Returning too far termination at range %d.\n",range);
18793 #endif
18794 /* Remove the gunflash */
18795 if(marineStatusPointer->myGunFlash)
18796 {
18797 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18798 marineStatusPointer->myGunFlash = NULL;
18799 }
18800 marineStatusPointer->volleySize = 0;
18801 return(SRC_Request_Approach);
18802 }
18803 return(SRC_No_Change);
18804 }
18805
18806 static STATE_RETURN_CONDITION Execute_MNS_DischargeSkeeter(STRATEGYBLOCK *sbPtr)
18807 {
18808 MARINE_STATUS_BLOCK *marineStatusPointer;
18809 VECTORCH orientationDirn,relPos,relPos2;
18810 int correctlyOrientated,range;
18811
18812 LOCALASSERT(sbPtr);
18813 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
18814 LOCALASSERT(marineStatusPointer);
18815
18816 #if MARINE_STATE_PRINT
18817 textprint("Firing Skeeter... ");
18818 #endif
18819
18820 /* zero velocity */
18821 LOCALASSERT(sbPtr->DynPtr);
18822 sbPtr->DynPtr->LinVelocity.vx = 0;
18823 sbPtr->DynPtr->LinVelocity.vy = 0;
18824 sbPtr->DynPtr->LinVelocity.vz = 0;
18825
18826 /* If a skeeter launcher has started firing, he can't stop! */
18827
18828 if (marineStatusPointer->clipammo==0) {
18829 /* Reload here. */
18830 return(SRC_Request_Reload);
18831 }
18832
18833 if (marineStatusPointer->Target) {
18834 /* Here we must have a target. Renew suspicion for new arrivals. */
18835 if (NpcSquad.Squad_Suspicion==0) {
18836 PointAlert(2,&marineStatusPointer->weaponTarget);
18837 }
18838 }
18839
18840 if (marineStatusPointer->stateTimer==marineStatusPointer->My_Weapon->FiringTime) {
18841
18842 /* First cycle. */
18843 if (marineStatusPointer->HModelController.Tweening==Controller_NoTweening) {
18844 marineStatusPointer->HModelController.Playing=0;
18845 }
18846
18847 /* Only terminate if you haven't begun firing yet... */
18848
18849 if (marineStatusPointer->Target==NULL) {
18850 #if MARINE_STATE_PRINT
18851 textprint("Returning no target.\n");
18852 #endif
18853 return(SRC_Request_Wait);
18854 }
18855
18856 if(!MarineCanSeeTarget(sbPtr))
18857 {
18858 #if 1
18859 /* ... and remove the gunflash */
18860 if(marineStatusPointer->myGunFlash)
18861 {
18862 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18863 marineStatusPointer->myGunFlash = NULL;
18864 }
18865 #endif
18866
18867 /* .... and stop the sound */
18868 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18869 Sound_Stop(marineStatusPointer->soundHandle);
18870 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18871 }
18872
18873 #if MARINE_STATE_PRINT
18874 textprint("Returning no target.\n");
18875 #endif
18876 return(SRC_Request_Wait);
18877 }
18878
18879 GLOBALASSERT(marineStatusPointer->Target);
18880 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
18881 /* Fix weapon target! */
18882 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
18883 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
18884 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18885 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
18886 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18887 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
18888 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18889 }
18890
18891 /* orientate to firing point first */
18892 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
18893 orientationDirn.vy = 0;
18894 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
18895 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
18896
18897 /* Consider range. */
18898
18899 relPos.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(sbPtr->DynPtr->Position.vx);
18900 relPos.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(sbPtr->DynPtr->Position.vy);
18901 relPos.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(sbPtr->DynPtr->Position.vz);
18902
18903 relPos2.vx=(marineStatusPointer->Target->DynPtr->Position.vx)-(marineStatusPointer->Target->DynPtr->PrevPosition.vx);
18904 relPos2.vy=(marineStatusPointer->Target->DynPtr->Position.vy)-(marineStatusPointer->Target->DynPtr->PrevPosition.vy);
18905 relPos2.vz=(marineStatusPointer->Target->DynPtr->Position.vz)-(marineStatusPointer->Target->DynPtr->PrevPosition.vz);
18906
18907 range=VectorDistance((&marineStatusPointer->Target->DynPtr->Position),(&sbPtr->DynPtr->Position));
18908
18909 /* Are they, by some chance, really close? */
18910 if (range<marineStatusPointer->My_Weapon->MinRange) {
18911 /* Even a complete idiot wouldn't fire this thing by reflex. */
18912 return(SRC_Request_PullPistol);
18913 }
18914
18915 if (correctlyOrientated) {
18916 /* If you are correctly oriented, you can now fire! */
18917 marineStatusPointer->HModelController.Playing=1;
18918 marineStatusPointer->HModelController.sequence_timer=0;
18919 marineStatusPointer->stateTimer-=NormalFrameTime;
18920
18921 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18922 Sound_Stop(marineStatusPointer->soundHandle);
18923 }
18924 if(marineStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) {
18925 Sound_Play(marineStatusPointer->My_Weapon->StartSound,"de",&(sbPtr->DynPtr->Position),&(marineStatusPointer->soundHandle));
18926 }
18927 }
18928 return(SRC_No_Change);
18929 } else if (marineStatusPointer->stateTimer>0) {
18930
18931 /* We must be in the build up. */
18932 if (marineStatusPointer->Target) {
18933 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
18934 /* Fix weapon target! */
18935 if (marineStatusPointer->My_Weapon->TargetCallibrationShift) {
18936 marineStatusPointer->weaponTarget.vx-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11,
18937 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18938 marineStatusPointer->weaponTarget.vy-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12,
18939 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18940 marineStatusPointer->weaponTarget.vz-=MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13,
18941 marineStatusPointer->My_Weapon->TargetCallibrationShift);
18942 }
18943
18944 /* orientate to firing point first */
18945 orientationDirn.vx = marineStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx;
18946 orientationDirn.vy = 0;
18947 orientationDirn.vz = marineStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz;
18948 correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE,NULL);
18949 } else {
18950 /* Tough! */
18951 correctlyOrientated = 1;
18952 }
18953
18954 /* look after the gun flash */
18955 if(marineStatusPointer->myGunFlash) {
18956 MaintainMarineGunFlash(sbPtr);
18957 } else {
18958 CreateMarineGunFlash(sbPtr);
18959 }
18960
18961 /* look after the sound */
18962 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18963 Sound_Update3d(marineStatusPointer->soundHandle,&(sbPtr->DynPtr->Position));
18964 }
18965
18966 marineStatusPointer->stateTimer -= NormalFrameTime;
18967
18968 #if MARINE_STATE_PRINT
18969 textprint("Turning to face.\n");
18970 #endif
18971 return(SRC_No_Change);
18972
18973 } else {
18974 /* Now fire a skeeter. */
18975
18976 /* Remove the gunflash */
18977 if(marineStatusPointer->myGunFlash)
18978 {
18979 RemoveNPCGunFlashEffect(marineStatusPointer->myGunFlash);
18980 marineStatusPointer->myGunFlash = NULL;
18981 }
18982 /* .... and stop the sound */
18983 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
18984 Sound_Stop(marineStatusPointer->soundHandle);
18985 Sound_Play(marineStatusPointer->My_Weapon->EndSound,"d",&(sbPtr->DynPtr->Position));
18986 }
18987
18988 {
18989 SECTION_DATA *rocket_section;
18990
18991 rocket_section=GetThisSectionData(marineStatusPointer->HModelController.section_data,"dum flash");
18992
18993 LOCALASSERT(rocket_section);
18994
18995 CreateFrisbeeKernel(&rocket_section->World_Offset, &rocket_section->SecMat,0);
18996
18997 if (marineStatusPointer->clipammo>0) {
18998 marineStatusPointer->clipammo--;
18999 }
19000 }
19001
19002 /* You must have fired already. */
19003
19004 if(range < MARINE_CLOSE_APPROACH_DISTANCE)
19005 {
19006 /* renew firing, as we are still too close to approach */
19007 marineStatusPointer->stateTimer = marineStatusPointer->My_Weapon->FiringTime;
19008 marineStatusPointer->volleySize = 0;
19009 GLOBALASSERT(marineStatusPointer->Target);
19010 NPCGetTargetPosition(&(marineStatusPointer->weaponTarget),marineStatusPointer->Target);
19011 #if MARINE_STATE_PRINT
19012 textprint("Returning too close renewal at range %d.\n",range);
19013 #endif
19014 return(SRC_No_Change);
19015 }
19016 else
19017 {
19018 /* we are far enough away, so return to approach */
19019
19020 #if MARINE_STATE_PRINT
19021 textprint("Returning too far termination at range %d.\n",range);
19022 #endif
19023 return(SRC_Request_Approach);
19024 }
19025
19026 }
19027
19028 return(SRC_No_Change);
19029 }
19030
19031 static STATE_RETURN_CONDITION Execute_MNS_AcidAvoidance(STRATEGYBLOCK *sbPtr)
19032 {
19033 MARINE_STATUS_BLOCK *marineStatusPointer;
19034 DYNAMICSBLOCK *dynPtr;
19035 VECTORCH velocityDirection = {0,0,0};
19036
19037 /* Your mission: to advance out of the acid. */
19038
19039 LOCALASSERT(sbPtr);
19040 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
19041 dynPtr = sbPtr->DynPtr;
19042 LOCALASSERT(marineStatusPointer);
19043 LOCALASSERT(dynPtr);
19044
19045 /* Where are we going? */
19046
19047 marineStatusPointer->stateTimer-=NormalFrameTime;
19048 if (marineStatusPointer->stateTimer<0) {
19049 return(SRC_Request_Approach);
19050 }
19051
19052 /* Ok: should have a current target at this stage... */
19053 NPCGetMovementDirection(sbPtr, &velocityDirection, &(marineStatusPointer->wanderData.worldPosition),&marineStatusPointer->waypointManager);
19054 NPCSetVelocity(sbPtr, &velocityDirection, marineStatusPointer->nearSpeed);
19055 HandleMovingAnimations(sbPtr);
19056
19057 if (New_NPC_IsObstructed(sbPtr,&marineStatusPointer->avoidanceManager)) {
19058 /* Go to all new avoidance. */
19059 return(SRC_Request_Avoidance);
19060 }
19061 return(SRC_No_Change);
19062
19063 }
19064
19065 void Marine_Activate_AcidAvoidance_State(STRATEGYBLOCK *sbPtr, VECTORCH *incidence) {
19066
19067 MARINE_STATUS_BLOCK *marineStatusPointer;
19068
19069 LOCALASSERT(sbPtr);
19070 marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
19071 LOCALASSERT(marineStatusPointer);
19072
19073 marineStatusPointer->gotapoint=0;
19074
19075 NPC_InitMovementData(&(marineStatusPointer->moveData));
19076 NPC_InitWanderData(&(marineStatusPointer->wanderData));
19077 InitWaypointManager(&marineStatusPointer->waypointManager);
19078 marineStatusPointer->volleySize = 0;
19079 marineStatusPointer->lastState=marineStatusPointer->behaviourState;
19080 marineStatusPointer->behaviourState = MBS_AcidAvoidance;
19081 marineStatusPointer->stateTimer = ONE_FIXED;
19082
19083 /* Get a destination. */
19084 {
19085 VECTORCH dest;
19086 if (incidence) {
19087 dest=*incidence;
19088 } else {
19089 /* Boo. */
19090 dest.vx=sbPtr->DynPtr->OrientMat.mat11;
19091 dest.vy=sbPtr->DynPtr->OrientMat.mat12;
19092 dest.vy=sbPtr->DynPtr->OrientMat.mat13;
19093 }
19094 AlignVelocityToGravity(sbPtr,&dest);
19095 if (Approximate3dMagnitude(&dest)==0) {
19096 /* Boo. */
19097 dest.vx=sbPtr->DynPtr->OrientMat.mat11;
19098 dest.vy=sbPtr->DynPtr->OrientMat.mat12;
19099 dest.vy=sbPtr->DynPtr->OrientMat.mat13;
19100 }
19101 marineStatusPointer->wanderData.worldPosition=sbPtr->DynPtr->Position;
19102
19103 marineStatusPointer->wanderData.worldPosition.vx+=(dest.vx>>6);
19104 marineStatusPointer->wanderData.worldPosition.vy+=(dest.vy>>6);
19105 marineStatusPointer->wanderData.worldPosition.vz+=(dest.vz>>6);
19106
19107 }
19108
19109 /* Not sure we need an expression for this one. */
19110 #if 0
19111 Marine_QueueNeutralExpression(sbPtr);
19112 #endif
19113
19114 HandleMovingAnimations(sbPtr);
19115
19116 }
19117