| | 1 | /*------------------------Patrick 6/11/96----------------------------- |
| | 2 | Source file for alien AI behaviour functions.... |
| | 3 | --------------------------------------------------------------------*/ |
| | 4 | #include "system.h" |
| | 5 | #include "prototyp.h" |
| | 6 | #include "stratdef.h" |
| | 7 | #include "bh_types.h" |
| | 8 | #include "bh_far.h" |
| | 9 | #include "generator.h" |
| | 10 | #include "npc_alien.h" |
| | 11 | #include "npc_marine.h" |
| | 12 | #include "weapons.h" |
| | 13 | #include "pheromon.h" |
| | 14 | #include "psndplat.h" |
| | 15 | #include "extents.h" |
| | 16 | #include "pldghost.h" |
| | 17 | #include "bh_types.h" |
| | 18 | #include "corpse.h" |
| | 19 | #include "npc_dummy.h" |
| | 20 | #include "scream.h" |
| | 21 | #include "userprofile.h" |
| | 22 | #include "pfarlocs.h" |
| | 23 | #include "targeting.h" |
| | 24 | #include "los.h" |
| | 25 | #include "bh_light.h" |
| | 26 | #include <assert.h> |
| | 27 | #include <stdio.h> |
| | 28 | |
| | 29 | #define ALIEN_CURVETOPLAYERDIST 8000 |
| | 30 | |
| | 31 | extern uint8_t Null_Name[8]; |
| | 32 | |
| | 33 | extern int NearAliens; |
| | 34 | extern int FarAliens; |
| | 35 | extern int ShowHiveState; |
| | 36 | |
| | 37 | const SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char *); |
| | 38 | extern int LightIntensityAtPoint(VECTORCH *pointPtr); |
| | 39 | AIMODULE *FarNPC_GetTargetAIModuleForRetreat(STRATEGYBLOCK *sbPtr); |
| | 40 | extern void EnableBehaviourType(STRATEGYBLOCK* sbptr, void *bhdata); |
| | 41 | |
| | 42 | extern ATTACK_DATA Alien_Special_Gripping_Attack; |
| | 43 | |
| | 44 | static int GetAlienSpeedFactor_ForSequence(STRATEGYBLOCK *sbPtr, HMODEL_SEQUENCE_TYPES sequence_type, int subsequence) |
| | 45 | { |
| | 46 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 47 | |
| | 48 | int factortype = -1; |
| | 49 | |
| | 50 | switch (sequence_type) |
| | 51 | { |
| | 52 | case HMSQT_AlienRun: |
| | 53 | switch ((ALIENRUN_SUBSEQUENCES)subsequence) |
| | 54 | { |
| | 55 | case ARSS_Standard: |
| | 56 | case ARSS_Attack_Swipe: |
| | 57 | factortype = 2; |
| | 58 | break; |
| | 59 | case ARSS_Jump: |
| | 60 | factortype = 1; |
| | 61 | break; |
| | 62 | case ARSS_Dies: |
| | 63 | factortype = 0; |
| | 64 | break; |
| | 65 | default: |
| | 66 | assert(0); |
| | 67 | } |
| | 68 | break; |
| | 69 | case HMSQT_AlienCrawl: |
| | 70 | switch ((ALIENCRAWL_SUBSEQUENCES)subsequence) |
| | 71 | { |
| | 72 | case ACSS_Standard: |
| | 73 | case ACSS_Crawl_Hurt: |
| | 74 | case ACSS_Scamper: |
| | 75 | factortype = 2; |
| | 76 | break; |
| | 77 | case ACSS_Attack_Bite: |
| | 78 | case ACSS_Attack_Tail: |
| | 79 | factortype = 1; |
| | 80 | break; |
| | 81 | case ACSS_Dies: |
| | 82 | case ACSS_Pain_Fall_Fwd: |
| | 83 | case ACSS_Pain_Fall_Back: |
| | 84 | case ACSS_Pain_Fall_Left: |
| | 85 | case ACSS_Pain_Fall_Right: |
| | 86 | case ACSS_Boom_Fall_Fwd: |
| | 87 | case ACSS_Boom_Fall_Back: |
| | 88 | case ACSS_Boom_Fall_Left: |
| | 89 | case ACSS_Boom_Fall_Right: |
| | 90 | factortype = 0; |
| | 91 | break; |
| | 92 | default: |
| | 93 | assert(0); |
| | 94 | } |
| | 95 | break; |
| | 96 | case HMSQT_AlienStand: |
| | 97 | switch ((ALIENSTAND_SUBSEQUENCES)subsequence) |
| | 98 | { |
| | 99 | case ASSS_Taunt: |
| | 100 | case ASSS_Taunt2: |
| | 101 | case ASSS_Taunt3: |
| | 102 | case ASSS_Fear: |
| | 103 | case ASSS_Standard: |
| | 104 | case ASSS_FidgetA: |
| | 105 | case ASSS_FidgetB: |
| | 106 | case ASSS_Attack_Right_Swipe_In: |
| | 107 | case ASSS_Attack_Left_Swipe_In: |
| | 108 | case ASSS_Attack_Both_In: |
| | 109 | case ASSS_Attack_Both_Down: |
| | 110 | case ASSS_Attack_Bite: |
| | 111 | case ASSS_Attack_Tail: |
| | 112 | case ASSS_Attack_Low_Left_Swipe: |
| | 113 | case ASSS_Attack_Low_Right_Swipe: |
| | 114 | case ASSS_Feed: |
| | 115 | case ASSS_Unfurl: |
| | 116 | case ASSS_Dormant: |
| | 117 | factortype = 1; |
| | 118 | break; |
| | 119 | case ASSS_Dies: |
| | 120 | case ASSS_Pain_Fall_Fwd: |
| | 121 | case ASSS_Pain_Fall_Back: |
| | 122 | case ASSS_Pain_Fall_Left: |
| | 123 | case ASSS_Pain_Fall_Right: |
| | 124 | case ASSS_Boom_Fall_Fwd: |
| | 125 | case ASSS_Boom_Fall_Back: |
| | 126 | case ASSS_Boom_Fall_Left: |
| | 127 | case ASSS_Boom_Fall_Right: |
| | 128 | case ASSS_Spin_Clockwise: |
| | 129 | case ASSS_Spin_Anticlockwise: |
| | 130 | case ASSS_BurningDeath: |
| | 131 | factortype = 0; |
| | 132 | break; |
| | 133 | default: |
| | 134 | assert(0); |
| | 135 | } |
| | 136 | break; |
| | 137 | case HMSQT_AlienCrouch: |
| | 138 | switch ((ALIENCROUCH_SUBSEQUENCES)subsequence) |
| | 139 | { |
| | 140 | case ACrSS_Standard: |
| | 141 | factortype = 2; |
| | 142 | break; |
| | 143 | case ACrSS_Attack_Bite: |
| | 144 | case ACrSS_Attack_Tail: |
| | 145 | case ACrSS_Attack_Swipe: |
| | 146 | case ACrSS_Pounce: |
| | 147 | case ACrSS_Taunt: |
| | 148 | factortype = 1; |
| | 149 | break; |
| | 150 | case ACrSS_Dies: |
| | 151 | case ACrSS_Dies_Thrash: |
| | 152 | factortype = 0; |
| | 153 | break; |
| | 154 | default: |
| | 155 | assert(0); |
| | 156 | } |
| | 157 | break; |
| | 158 | case HMSQT_Hugger: |
| | 159 | default: |
| | 160 | /* Nooooo! */ |
| | 161 | assert(0); |
| | 162 | break; |
| | 163 | } |
| | 164 | |
| | 165 | assert(factortype != -1); |
| | 166 | |
| | 167 | switch(factortype) |
| | 168 | { |
| | 169 | case 0: |
| | 170 | return ONE_FIXED; |
| | 171 | break; |
| | 172 | case 1: |
| | 173 | { |
| | 174 | /* Affected by alien type. */ |
| | 175 | |
| | 176 | switch (alienStatusPointer->Type) |
| | 177 | { |
| | 178 | case Standard: |
| | 179 | return ONE_FIXED; |
| | 180 | case Predalien: |
| | 181 | return PREDALIEN_SPEED_FACTOR; |
| | 182 | case Praetorian: |
| | 183 | return PRAETORIAN_SPEED_FACTOR; |
| | 184 | default: |
| | 185 | assert(0); |
| | 186 | break; |
| | 187 | } |
| | 188 | } |
| | 189 | break; |
| | 190 | case 2: |
| | 191 | { |
| | 192 | /* More complex. Affected by alien type and health. */ |
| | 193 | const NPC_DATA *NpcData; |
| | 194 | int prefactor; |
| | 195 | |
| | 196 | switch (alienStatusPointer->Type) |
| | 197 | { |
| | 198 | case Standard: |
| | 199 | default: |
| | 200 | NpcData = &NpcDataList[I_NPC_Alien]; |
| | 201 | prefactor = ONE_FIXED; |
| | 202 | break; |
| | 203 | case Predalien: |
| | 204 | NpcData = &NpcDataList[I_NPC_PredatorAlien]; |
| | 205 | prefactor = PREDALIEN_SPEED_FACTOR; |
| | 206 | break; |
| | 207 | case Praetorian: |
| | 208 | NpcData = &NpcDataList[I_NPC_PraetorianGuard]; |
| | 209 | prefactor = PRAETORIAN_SPEED_FACTOR; |
| | 210 | } |
| | 211 | |
| | 212 | int factor = sbPtr->DamageBlock.Health / NpcData->StartingStats.Health; |
| | 213 | /* ONE_FIXED shift already included. */ |
| | 214 | assert(factor <= ONE_FIXED); |
| | 215 | |
| | 216 | factor += ONE_FIXED; |
| | 217 | factor >>= 1; |
| | 218 | |
| | 219 | /* Wounding effects. */ |
| | 220 | if (alienStatusPointer->Wounds & (section_flag_left_leg | section_flag_right_leg)) |
| | 221 | { |
| | 222 | /* Missing a leg. */ |
| | 223 | factor -= (ONE_FIXED/3); |
| | 224 | } |
| | 225 | else if ((alienStatusPointer->Wounds & section_flag_left_foot) && (alienStatusPointer->Wounds & section_flag_right_foot)) |
| | 226 | { |
| | 227 | /* Missing both feet. */ |
| | 228 | factor -= (ONE_FIXED>>2); |
| | 229 | } |
| | 230 | else if ((alienStatusPointer->Wounds & section_flag_left_foot) || (alienStatusPointer->Wounds & section_flag_right_foot)) |
| | 231 | { |
| | 232 | /* Missing one foot. */ |
| | 233 | factor -= (ONE_FIXED>>3); |
| | 234 | } |
| | 235 | |
| | 236 | if (factor < (ONE_FIXED >> 3)) |
| | 237 | factor = (ONE_FIXED >> 3); |
| | 238 | |
| | 239 | if (prefactor != ONE_FIXED) |
| | 240 | factor = MUL_FIXED(prefactor,factor); |
| | 241 | |
| | 242 | return factor; |
| | 243 | } |
| | 244 | break; |
| | 245 | default: |
| | 246 | assert(0); |
| | 247 | } |
| | 248 | |
| | 249 | return 0; |
| | 250 | } |
| | 251 | |
| | 252 | static void RecomputeAlienSpeed(STRATEGYBLOCK *sbPtr) |
| | 253 | { |
| | 254 | int basespeed; |
| | 255 | |
| | 256 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 257 | |
| | 258 | /* Change max speed. */ |
| | 259 | int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard); |
| | 260 | |
| | 261 | switch (alienStatusPointer->Type) |
| | 262 | { |
| | 263 | case Standard: |
| | 264 | default: |
| | 265 | basespeed = ALIEN_FORWARDVELOCITY; |
| | 266 | break; |
| | 267 | case Predalien: |
| | 268 | basespeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, PREDALIEN_SPEED_FACTOR); |
| | 269 | break; |
| | 270 | case Praetorian: |
| | 271 | if (alienStatusPointer->IAmCrouched) |
| | 272 | basespeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, MUL_FIXED(PRAETORIAN_CRAWLSPEED_FACTOR, PRAETORIAN_SPEED_FACTOR)); |
| | 273 | else |
| | 274 | basespeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR, PRAETORIAN_SPEED_FACTOR)); |
| | 275 | } |
| | 276 | |
| | 277 | alienStatusPointer->MaxSpeed = MUL_FIXED(factor, basespeed); |
| | 278 | } |
| | 279 | |
| | 280 | /* Patrick 27/6/97 ********************************* |
| | 281 | Some support functions for the alien: |
| | 282 | Hopefully, these are fairly obvious... |
| | 283 | ****************************************************/ |
| | 284 | static void SetAlienShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr, int type, int subtype, int length, int tweeningtime) |
| | 285 | { |
| | 286 | ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 287 | assert(length != 0); |
| | 288 | |
| | 289 | if ((alienStatus->HModelController.Sequence_Type == type) && (subtype == alienStatus->HModelController.Sub_Sequence)) |
| | 290 | return; |
| | 291 | |
| | 292 | alienStatus->last_anim_length = length; |
| | 293 | printf("sec %d sub %d\n", alienStatus->HModelController.Sequence_Type, alienStatus->HModelController.Sub_Sequence); |
| | 294 | puts("CHANGING SEC"); //jadda |
| | 295 | |
| | 296 | if (alienStatus->last_anim_length == -1) |
| | 297 | alienStatus->last_anim_length = ONE_FIXED; /* Stops divisions by zero. */ |
| | 298 | |
| | 299 | /* Consider wounding. */ |
| | 300 | { |
| | 301 | int factor = GetAlienSpeedFactor_ForSequence(sbPtr, type, subtype); |
| | 302 | |
| | 303 | if (factor != ONE_FIXED) |
| | 304 | length = DIV_FIXED(length, factor); |
| | 305 | } |
| | 306 | |
| | 307 | if (tweeningtime <= 0) |
| | 308 | InitHModelSequence(&alienStatus->HModelController, (int)type, subtype, length); |
| | 309 | else |
| | 310 | InitHModelTweening(&alienStatus->HModelController, tweeningtime, (int)type, subtype, length, 1); |
| | 311 | |
| | 312 | if(NetworkPeer == AvP.PlayMode) |
| | 313 | AddNetMsg_AlienAISeqChange(sbPtr, type, subtype, length, tweeningtime); |
| | 314 | |
| | 315 | alienStatus->HModelController.Playing = 1; |
| | 316 | RecomputeAlienSpeed(sbPtr); |
| | 317 | } |
| | 318 | |
| | 319 | static int AlienShouldBeCrawling(STRATEGYBLOCK *sbPtr) |
| | 320 | { |
| | 321 | ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 322 | |
| | 323 | if(sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT) |
| | 324 | return 1; |
| | 325 | |
| | 326 | /* Stand if you've lost both arm sections. */ |
| | 327 | if ((alienStatus->Wounds & section_flag_left_arm) && (alienStatus->Wounds & section_flag_right_arm)) |
| | 328 | return 0; /* This just looks silly. */ |
| | 329 | |
| | 330 | if(sbPtr->DynPtr->OrientMat.mat22 < 63000) |
| | 331 | return 1; |
| | 332 | |
| | 333 | if (AlienIsEncouragedToCrawl() && alienStatus->EnableWaypoints) |
| | 334 | return 1; |
| | 335 | |
| | 336 | if (alienStatus->incidentFlag) |
| | 337 | { |
| | 338 | switch(alienStatus->Type) |
| | 339 | { |
| | 340 | case Standard: |
| | 341 | default: |
| | 342 | alienStatus->PreferToCrouch = (FastRandom() % 65535) > 36384; |
| | 343 | break; |
| | 344 | case Predalien: |
| | 345 | alienStatus->PreferToCrouch = 0; |
| | 346 | break; |
| | 347 | case Praetorian: |
| | 348 | if ((FastRandom() % 65535) < 16384) |
| | 349 | alienStatus->PreferToCrouch = ~alienStatus->PreferToCrouch; |
| | 350 | } |
| | 351 | } |
| | 352 | |
| | 353 | return alienStatus->PreferToCrouch; |
| | 354 | } |
| | 355 | |
| | 356 | static void AlienHandleMovingAnimation(STRATEGYBLOCK *sbPtr) |
| | 357 | { |
| | 358 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 359 | |
| | 360 | if(alienStatusPointer->CanStand) |
| | 361 | { |
| | 362 | /* Make sure we're playing a 'moving' sequence, if we're actually moving. */ |
| | 363 | |
| | 364 | VECTORCH offset; |
| | 365 | offset.vx = sbPtr->DynPtr->Position.vx - sbPtr->DynPtr->PrevPosition.vx; |
| | 366 | offset.vy = sbPtr->DynPtr->Position.vy - sbPtr->DynPtr->PrevPosition.vy; |
| | 367 | offset.vz = sbPtr->DynPtr->Position.vz - sbPtr->DynPtr->PrevPosition.vz; |
| | 368 | |
| | 369 | alienStatusPointer->IAmCrouched = AlienShouldBeCrawling(sbPtr); |
| | 370 | |
| | 371 | /* ...compute speed factor... */ |
| | 372 | int speed = Magnitude(&offset); |
| | 373 | |
| | 374 | if (speed < (MUL_FIXED(NormalFrameTime, 100))) |
| | 375 | { |
| | 376 | /* Not moving much, are we? */ |
| | 377 | /* Make sure we're playing a 'standing still' sequence. */ |
| | 378 | |
| | 379 | if (alienStatusPointer->IAmCrouched) |
| | 380 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrouch, ACrSS_Standard, -1, (ONE_FIXED >> 3)); |
| | 381 | else |
| | 382 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienStand, ASSS_Standard, -1, (ONE_FIXED >> 3)); |
| | 383 | } |
| | 384 | else |
| | 385 | { |
| | 386 | speed = DIV_FIXED(speed, NormalFrameTime); |
| | 387 | /* Right, now play the correct sort of sequence. */ |
| | 388 | |
| | 389 | if(alienStatusPointer->IAmCrouched) |
| | 390 | { |
| | 391 | if( ((Standard == alienStatusPointer->Type) && (sbPtr->DynPtr->OrientMat.mat22 < 63000)) || (Predalien ==
alienStatusPointer->Type)) |
| | 392 | { |
| | 393 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Standard, ONE_FIXED >> 2, (ONE_FIXED >> 2)); |
| | 394 | } |
| | 395 | else |
| | 396 | { |
| | 397 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Scamper, ONE_FIXED >> 2, (ONE_FIXED >> 2)); |
| | 398 | } |
| | 399 | } |
| | 400 | else |
| | 401 | { |
| | 402 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Standard, ONE_FIXED >> 1, (ONE_FIXED >> 2)); |
| | 403 | } |
| | 404 | } |
| | 405 | } |
| | 406 | else |
| | 407 | { |
| | 408 | alienStatusPointer->IAmCrouched = 1; |
| | 409 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Crawl_Hurt, ONE_FIXED >> 1, (ONE_FIXED >> 2)); |
| | 410 | } |
| | 411 | } |
| | 412 | |
| | 413 | static int Alien_Special_Pounce_Condition(STRATEGYBLOCK *sbPtr) |
| | 414 | { |
| | 415 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 416 | |
| | 417 | if (sbPtr->containingModule->m_aimodule->m_waypoints == NULL) |
| | 418 | { |
| | 419 | /* If in an unwaypointed module... */ |
| | 420 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 421 | |
| | 422 | if ((alienStatusPointer->Target->DynPtr->Position.vy - dynPtr->Position.vy) < -2000) |
| | 423 | return 1; // And the target is directly above us... |
| | 424 | } |
| | 425 | |
| | 426 | return 0; |
| | 427 | } |
| | 428 | |
| | 429 | static void StartAlienAttackSequence(STRATEGYBLOCK *sbPtr) |
| | 430 | { |
| | 431 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 432 | |
| | 433 | /* |
| | 434 | DYNAMICSBLOCK *objectDynPtr = sbPtr->DynPtr; |
| | 435 | ATTACK_DATA *thisAttack; |
| | 436 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Attack_Swipe, -1, 1); |
| | 437 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Pounce, -1, 1); |
| | 438 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Bite, -1, 1); |
| | 439 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Left_Swipe_In, -1, 1); |
| | 440 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Right_Swipe_In, -1, 1); |
| | 441 | |
| | 442 | |
| | 443 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Tail, -1, 1); // not
predalien |
| | 444 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Both_Down, -1, 1); // not
pratorian |
| | 445 | |
| | 446 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Attack_Bite, -1, 1); // only
standard alien and pratorian bad |
| | 447 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrouch, (int)ACrSS_Attack_Tail, -1, 1); // only
predalien and standard bad |
| | 448 | |
| | 449 | int left_arm_disabled = ((alienStatusPointer->Wounds & section_flag_left_arm) || (alienStatusPointer->Wounds & section_flag_left_hand)); |
| | 450 | int right_arm_disabled = ((alienStatusPointer->Wounds & section_flag_right_arm) || (alienStatusPointer->Wounds & section_flag_right_hand)); |
| | 451 | int have_both_arms = !left_arm_disabled && !right_arm_disabled; |
| | 452 | |
| | 453 | //if(alienStatusPointer->IAmCrouched) { } |
| | 454 | |
| | 455 | switch(alienStatusPointer->Type) |
| | 456 | { |
| | 457 | case Standard: |
| | 458 | { |
| | 459 | if(0) |
| | 460 | if(DynamicObjectIsMoving(alienStatusPointer->Target->DynPtr)) |
| | 461 | { |
| | 462 | if(alienStatusPointer->IAmCrouched) |
| | 463 | { |
| | 464 | alienStatusPointer->IAmCrouched = 0; |
| | 465 | } |
| | 466 | else |
| | 467 | { |
| | 468 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienRun, (int)ARSS_Attack_Swipe, -1, 1); |
| | 469 | } |
| | 470 | } |
| | 471 | else |
| | 472 | { |
| | 473 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienCrawl, (int)ACSS_Attack_Swipe, -1, 1); |
| | 474 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Low_Left_Swipe, -1, 1); |
| | 475 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Low_Right_Swipe, -1,
1); |
| | 476 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Attack_Both_In, -1, 1); |
| | 477 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand, (int)ASSS_Feed, -1, 1); // only standard
eat dead corsp on ground |
| | 478 | } |
| | 479 | } |
| | 480 | break; |
| | 481 | case Predalien: |
| | 482 | { |
| | 483 | } |
| | 484 | break; |
| | 485 | case Praetorian: |
| | 486 | { |
| | 487 | |
| | 488 | } |
| | 489 | } |
| | 490 | |
| | 491 | //} |
| | 492 | //return; |
| | 493 | if (!alienStatusPointer->Type && 0) |
| | 494 | { |
| | 495 | int collidingWithTarget = 0; |
| | 496 | |
| | 497 | // Test for gripping attack! |
| | 498 | { |
| | 499 | struct collisionreport *nextReport = sbPtr->DynPtr->CollisionReportPtr; |
| | 500 | |
| | 501 | while(nextReport) |
| | 502 | { |
| | 503 | if(nextReport->ObstacleSBPtr) |
| | 504 | { |
| | 505 | if (nextReport->ObstacleSBPtr == alienStatusPointer->Target) |
| | 506 | collidingWithTarget = 1; |
| | 507 | } |
| | 508 | |
| | 509 | nextReport = nextReport->NextCollisionReportPtr; |
| | 510 | } |
| | 511 | } |
| | 512 | |
| | 513 | if(collidingWithTarget && HModelSequence_Exists(&alienStatusPointer->HModelController, Alien_Special_Gripping_Attack.Sequence_Type,
Alien_Special_Gripping_Attack.Sub_Sequence)) |
| | 514 | { |
| | 515 | VECTORCH offset,mypos; |
| | 516 | GetTargetingPointOfObject_Far(alienStatusPointer->Target, &offset); |
| | 517 | GetTargetingPointOfObject_Far(sbPtr, &mypos); |
| | 518 | offset.vx -= mypos.vx; |
| | 519 | offset.vy -= mypos.vy; |
| | 520 | offset.vz -= mypos.vz; |
| | 521 | Normalise(&offset); |
| | 522 | |
| | 523 | if (sbPtr->DynPtr->UseStandardGravity) |
| | 524 | { |
| | 525 | sbPtr->DynPtr->GravityDirection.vx = 0; |
| | 526 | sbPtr->DynPtr->GravityDirection.vy = 65536; |
| | 527 | sbPtr->DynPtr->GravityDirection.vz = 0; |
| | 528 | } |
| | 529 | |
| | 530 | if ((DotProduct(&offset,&sbPtr->DynPtr->GravityDirection) > 16962) && collidingWithTarget) |
| | 531 | thisAttack = &Alien_Special_Gripping_Attack; // 75 degs... |
| | 532 | else |
| | 533 | thisAttack = GetAlienAttackSequence(&alienStatusPointer->HModelController, alienStatusPointer->Wounds,
alienStatusPointer->IAmCrouched); |
| | 534 | } |
| | 535 | else if(DynamicObjectIsMoving(objectDynPtr)) |
| | 536 | { |
| | 537 | //InitHModelSequence(&alienStatusPointer->HModelController,(int)HMSQT_AlienRun, (int)ARSS_Attack_Swipe, ONE_FIXED/2); |
| | 538 | thisAttack = GetAlienAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, alienStatusPointer->IAmCrouched); |
| | 539 | } |
| | 540 | else |
| | 541 | thisAttack = GetAlienAttackSequence(&alienStatusPointer->HModelController, alienStatusPointer->Wounds,
alienStatusPointer->IAmCrouched); |
| | 542 | } |
| | 543 | else |
| | 544 | { |
| | 545 | thisAttack = GetAlienAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, alienStatusPointer->IAmCrouched); |
| | 546 | } |
| | 547 | */ |
| | 548 | ATTACK_DATA *thisAttack = GetAlienAttackSequence(&alienStatusPointer->HModelController,alienStatusPointer->Wounds,
alienStatusPointer->IAmCrouched); |
| | 549 | SetAlienShapeAnimSequence_Core(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime); |
| | 550 | |
| | 551 | alienStatusPointer->current_attack = thisAttack; |
| | 552 | } |
| | 553 | |
| | 554 | static void AlienRandomHiss(STRATEGYBLOCK *sbPtr) |
| | 555 | { |
| | 556 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 557 | |
| | 558 | if (alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX) |
| | 559 | { |
| | 560 | PlayAlienSound((int)alienStatusPointer->Type, ASC_Scream_General, 0, &alienStatusPointer->sound_mouth, &sbPtr->DynPtr->Position); |
| | 561 | |
| | 562 | if(NetworkPeer == AvP.PlayMode) |
| | 563 | AddNetMsg_SpotAlienSound((int)ASC_Scream_General, (int)alienStatusPointer->Type, 0, &sbPtr->DynPtr->Position); |
| | 564 | } |
| | 565 | } |
| | 566 | |
| | 567 | static int GoToJump(STRATEGYBLOCK *sbPtr) |
| | 568 | { |
| | 569 | int speed; |
| | 570 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 571 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 572 | |
| | 573 | /* Must be upright. */ |
| | 574 | if((dynPtr->OrientMat.mat22 < 63000) || !alienStatusPointer->CanStand) |
| | 575 | return 0; |
| | 576 | |
| | 577 | /* Should be able to jump now! */ |
| | 578 | |
| | 579 | dynPtr->LinImpulse.vx = 0; |
| | 580 | dynPtr->LinImpulse.vy = -10000; |
| | 581 | dynPtr->LinImpulse.vz = 20000; |
| | 582 | |
| | 583 | RotateVector(&dynPtr->LinImpulse, &dynPtr->OrientMat); |
| | 584 | Normalise(&dynPtr->LinImpulse); |
| | 585 | |
| | 586 | switch (alienStatusPointer->Type) |
| | 587 | { |
| | 588 | case Standard: |
| | 589 | default: |
| | 590 | speed = ALIEN_JUMP_SPEED; |
| | 591 | break; |
| | 592 | case Predalien: |
| | 593 | speed = PREDALIEN_JUMP_SPEED; |
| | 594 | break; |
| | 595 | case Praetorian: |
| | 596 | speed = PRAETORIAN_JUMP_SPEED; |
| | 597 | } |
| | 598 | |
| | 599 | int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard); |
| | 600 | speed = MUL_FIXED(speed, factor); |
| | 601 | |
| | 602 | dynPtr->LinImpulse.vx = MUL_FIXED(speed, dynPtr->LinImpulse.vx); |
| | 603 | dynPtr->LinImpulse.vy = MUL_FIXED(speed, dynPtr->LinImpulse.vy); |
| | 604 | dynPtr->LinImpulse.vz = MUL_FIXED(speed, dynPtr->LinImpulse.vz); |
| | 605 | |
| | 606 | alienStatusPointer->BehaviourState = ABS_Jump; |
| | 607 | alienStatusPointer->StateTimer = 0; |
| | 608 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Jump, ONE_FIXED >> 1, (ONE_FIXED >> 2)); |
| | 609 | |
| | 610 | return 1; |
| | 611 | } |
| | 612 | |
| | 613 | static int AlienIsAbleToClimb(STRATEGYBLOCK *sbPtr) |
| | 614 | { |
| | 615 | ALIEN_STATUS_BLOCK *alienStatus = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 616 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 617 | |
| | 618 | return (alienStatus->CanClimb && alienStatus->IAmCrouched); |
| | 619 | |
| | 620 | if (!alienStatus->CanClimb || !alienStatus->IAmCrouched) |
| | 621 | return 0; |
| | 622 | |
| | 623 | { |
| | 624 | struct collisionreport *CollisionReportPtr = dynPtr->CollisionReportPtr; |
| | 625 | |
| | 626 | while(CollisionReportPtr) |
| | 627 | { |
| | 628 | if(CollisionReportPtr->ObstacleSBPtr) |
| | 629 | { |
| | 630 | STRATEGYBLOCK* hit_sbptr = CollisionReportPtr->ObstacleSBPtr; |
| | 631 | |
| | 632 | switch(hit_sbptr->type) |
| | 633 | { |
| | 634 | case I_BehaviourInanimateObject: |
| | 635 | case I_BehaviourPlatform: |
| | 636 | case I_BehaviourVideoScreen: |
| | 637 | case I_BehaviourGrapplingHook: |
| | 638 | //case I_BehaviourPlacedLight: |
| | 639 | return 1; |
| | 640 | case I_BehaviourMarine: |
| | 641 | case I_BehaviourMarinePlayer: |
| | 642 | case I_BehaviourPredatorPlayer: |
| | 643 | case I_BehaviourPredator: |
| | 644 | case I_BehaviourPlacedLight: |
| | 645 | CauseDamageToObject(hit_sbptr, &damage_profiles[FALLINGDAMAGE], (100*NormalFrameTime), NULL); |
| | 646 | case I_BehaviourAlien: |
| | 647 | case I_BehaviourAlienPlayer: |
| | 648 | case I_BehaviourFaceHugger: |
| | 649 | case I_BehaviourXenoborg: |
| | 650 | case I_BehaviourQueenAlien: |
| | 651 | return 0; |
| | 652 | default: |
| | 653 | break; |
| | 654 | } |
| | 655 | return 0; |
| | 656 | } |
| | 657 | else |
| | 658 | return 1; |
| | 659 | |
| | 660 | CollisionReportPtr = CollisionReportPtr->NextCollisionReportPtr; |
| | 661 | } |
| | 662 | } |
| | 663 | |
| | 664 | return 0; |
| | 665 | } |
| | 666 | |
| | 667 | static int StartAlienTaunt(STRATEGYBLOCK *sbPtr) |
| | 668 | { |
| | 669 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 670 | |
| | 671 | if(alienStatusPointer->IAmCrouched) |
| | 672 | { |
| | 673 | if(Standard != alienStatusPointer->Type) |
| | 674 | return 0; /* No sequence - can't do it. */ |
| | 675 | |
| | 676 | SetAlienShapeAnimSequence_Core(sbPtr, (int)HMSQT_AlienCrouch, ACrSS_Taunt, -1, (ONE_FIXED >> 3)); |
| | 677 | } |
| | 678 | else |
| | 679 | { |
| | 680 | int sub_sequence = ASSS_Taunt; |
| | 681 | |
| | 682 | if(Standard == alienStatusPointer->Type) |
| | 683 | { |
| | 684 | switch(FastRandom() % 3) |
| | 685 | { |
| | 686 | case 0: |
| | 687 | default: |
| | 688 | break; |
| | 689 | case 1: |
| | 690 | sub_sequence = ASSS_Taunt2; |
| | 691 | break; |
| | 692 | case 2: |
| | 693 | sub_sequence = ASSS_Taunt3; |
| | 694 | } |
| | 695 | } |
| | 696 | |
| | 697 | /* The things I do for transparent code... */ |
| | 698 | |
| | 699 | SetAlienShapeAnimSequence_Core(sbPtr, (int)HMSQT_AlienStand, sub_sequence, -1, (ONE_FIXED >> 3)); |
| | 700 | } |
| | 701 | |
| | 702 | alienStatusPointer->HModelController.Looped = 0; |
| | 703 | alienStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 704 | alienStatusPointer->BehaviourState = ABS_Taunting; |
| | 705 | alienStatusPointer->StateTimer = 0; |
| | 706 | |
| | 707 | AlienRandomHiss(sbPtr); |
| | 708 | /* |
| | 709 | if (alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX) |
| | 710 | { |
| | 711 | PlayAlienSound((int)alienStatusPointer->Type, ASC_Taunt, 0, &alienStatusPointer->sound_mouth, &sbPtr->DynPtr->Position); |
| | 712 | |
| | 713 | if(NetworkPeer == AvP.PlayMode) |
| | 714 | AddNetMsg_SpotAlienSound((int)ASC_Taunt, (int)alienStatusPointer->Type, 0, &sbPtr->DynPtr->Position); |
| | 715 | } |
| | 716 | */ |
| | 717 | |
| | 718 | return 1; |
| | 719 | } |
| | 720 | |
| | 721 | static int TargetIsFiringFlamethrowerAtAlien(STRATEGYBLOCK *sbPtr, int distance_to_target) |
| | 722 | { |
| | 723 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 724 | |
| | 725 | /* First, let's see what the target is. */ |
| | 726 | switch(alienStatusPointer->Target->type) |
| | 727 | { |
| | 728 | case I_BehaviourMarinePlayer: |
| | 729 | { |
| | 730 | /* Is the player firing a flamethrower? */ |
| | 731 | |
| | 732 | if ((PlayerStatus.SelectedWeapon->WeaponIDNumber == WEAPON_FLAMETHROWER) && (PlayerStatus.WeaponState == WEAPONSTATE_FIRING_PRIMARY)) |
| | 733 | //if ((PlayerStatus.SelectedWeapon->WeaponIDNumber == WEAPON_FLAMETHROWER) && (PlayerStatus.weapon.HModelControlBlock->Sub_Sequence ==
MHSS_Standard_Fire)) |
| | 734 | break; |
| | 735 | } |
| | 736 | return 0; |
| | 737 | case I_BehaviourMarine: |
| | 738 | { |
| | 739 | assert(sbPtr); |
| | 740 | MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(alienStatusPointer->Target->dataptr); |
| | 741 | assert(marineStatusPointer); |
| | 742 | |
| | 743 | switch(marineStatusPointer->My_Weapon->id) |
| | 744 | { |
| | 745 | case MNPCW_Flamethrower: |
| | 746 | case MNPCW_MFlamer: |
| | 747 | if (marineStatusPointer->behaviourState != MBS_Firing) |
| | 748 | return 0; |
| | 749 | break; |
| | 750 | default: |
| | 751 | return 0; |
| | 752 | } |
| | 753 | } |
| | 754 | default: |
| | 755 | { |
| | 756 | /* Gotta insert a case for netghosts. */ |
| | 757 | return 0; |
| | 758 | } |
| | 759 | } |
| | 760 | |
| | 761 | /* Next, let's see if the alien and the target are both in the other's front arc. */ |
| | 762 | |
| | 763 | { |
| | 764 | VECTORCH sourcepos,targetpos,offset; |
| | 765 | MATRIXCH WtoL = sbPtr->DynPtr->OrientMat; |
| | 766 | GetTargetingPointOfObject_Far(sbPtr, &sourcepos); |
| | 767 | GetTargetingPointOfObject_Far(alienStatusPointer->Target, &targetpos); |
| | 768 | |
| | 769 | offset.vx = sourcepos.vx - targetpos.vx; |
| | 770 | offset.vy = sourcepos.vy - targetpos.vy; |
| | 771 | offset.vz = sourcepos.vz - targetpos.vz; |
| | 772 | |
| | 773 | TransposeMatrixCH(&WtoL); |
| | 774 | RotateVector(&offset,&WtoL); |
| | 775 | |
| | 776 | if ( (offset.vz <0) |
| | 777 | && (offset.vz < offset.vx) |
| | 778 | && (offset.vz < -offset.vx) |
| | 779 | && (offset.vz < offset.vy) |
| | 780 | && (offset.vz < -offset.vy) ) |
| | 781 | { |
| | 782 | /* 90 horizontal, 90 vertical... continue. */ |
| | 783 | } |
| | 784 | else |
| | 785 | { |
| | 786 | return 0; |
| | 787 | } |
| | 788 | |
| | 789 | /* Now test it for the other way round. */ |
| | 790 | |
| | 791 | WtoL = alienStatusPointer->Target->DynPtr->OrientMat; |
| | 792 | GetTargetingPointOfObject_Far(alienStatusPointer->Target,&sourcepos); |
| | 793 | GetTargetingPointOfObject_Far(sbPtr,&targetpos); |
| | 794 | |
| | 795 | offset.vx = sourcepos.vx - targetpos.vx; |
| | 796 | offset.vy = sourcepos.vy - targetpos.vy; |
| | 797 | offset.vz = sourcepos.vz - targetpos.vz; |
| | 798 | |
| | 799 | TransposeMatrixCH(&WtoL); |
| | 800 | RotateVector(&offset, &WtoL); |
| | 801 | |
| | 802 | if ( (offset.vz < 0) |
| | 803 | && (offset.vz < offset.vx) |
| | 804 | && (offset.vz < -offset.vx) |
| | 805 | && (offset.vz < offset.vy) |
| | 806 | && (offset.vz < -offset.vy) ) |
| | 807 | { |
| | 808 | |
| | 809 | /* 90 horizontal, 90 vertical... continue. */ |
| | 810 | } |
| | 811 | else |
| | 812 | { |
| | 813 | return 0; |
| | 814 | } |
| | 815 | } |
| | 816 | |
| | 817 | //int range = VectorDistance(&alienStatusPointer->Target->DynPtr->Position, &sbPtr->DynPtr->Position); |
| | 818 | //printf("range %d\n", range); |
| | 819 | |
| | 820 | if (distance_to_target > 18000) |
| | 821 | { |
| | 822 | return StartAlienTaunt(sbPtr); |
| | 823 | } |
| | 824 | else |
| | 825 | { |
| | 826 | NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0}; |
| | 827 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 828 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 829 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 830 | alienStatusPointer->StateTimer = NPC_AVOIDTIME/2; |
| | 831 | } |
| | 832 | |
| | 833 | /* If here, then it must be true! */ |
| | 834 | return 1; |
| | 835 | } |
| | 836 | |
| | 837 | static ATTACK_DATA *AlienIsAbleToPounce(STRATEGYBLOCK *sbPtr) |
| | 838 | { |
| | 839 | VECTORCH targetPoint; |
| | 840 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 841 | |
| | 842 | /* Also not if you're badly hurt. */ |
| | 843 | { |
| | 844 | int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard); |
| | 845 | |
| | 846 | if (factor < ((ONE_FIXED*3)/4)) |
| | 847 | return NULL; |
| | 848 | } |
| | 849 | |
| | 850 | if (NULL != alienStatusPointer->Target->DisplayBlock) |
| | 851 | { |
| | 852 | GetTargetingPointOfObject(alienStatusPointer->Target->DisplayBlock, &targetPoint); |
| | 853 | |
| | 854 | /* Do we have a clear line of sight? */ |
| | 855 | |
| | 856 | if (IsThisObjectVisibleFromThisPosition_WithIgnore(sbPtr->DisplayBlock, alienStatusPointer->Target->DisplayBlock, &targetPoint)) |
| | 857 | { |
| | 858 | /* Finally, test the sequence. */ |
| | 859 | ATTACK_DATA *thisAttack = GetAlienPounceAttack(&alienStatusPointer->HModelController,alienStatusPointer->Wounds,
alienStatusPointer->IAmCrouched); |
| | 860 | |
| | 861 | if ((thisAttack == NULL) && !alienStatusPointer->IAmCrouched) |
| | 862 | { |
| | 863 | /* Try again crouched. Pook. */ |
| | 864 | thisAttack = GetAlienPounceAttack(&alienStatusPointer->HModelController,alienStatusPointer->Wounds, 1); |
| | 865 | } |
| | 866 | return thisAttack; |
| | 867 | } |
| | 868 | } |
| | 869 | |
| | 870 | return NULL; |
| | 871 | } |
| | 872 | |
| | 873 | static int StartAlienPounce(STRATEGYBLOCK *sbPtr) |
| | 874 | { |
| | 875 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 876 | |
| | 877 | if((sbPtr->DynPtr->OrientMat.mat22 < 63000) || (sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT)) |
| | 878 | { |
| | 879 | // First rule. Must be on a flat floor, And not in an airduct. |
| | 880 | } |
| | 881 | else if(alienStatusPointer->CanStand && sbPtr->DynPtr->IsInContactWithFloor) |
| | 882 | { |
| | 883 | ATTACK_DATA *thisAttack = AlienIsAbleToPounce(sbPtr); |
| | 884 | |
| | 885 | if (NULL != thisAttack) |
| | 886 | { |
| | 887 | SetAlienShapeAnimSequence_Core(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime); |
| | 888 | |
| | 889 | alienStatusPointer->HModelController.Looped = 0; |
| | 890 | alienStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 891 | alienStatusPointer->current_attack = thisAttack; |
| | 892 | alienStatusPointer->BehaviourState = ABS_Pounce; |
| | 893 | alienStatusPointer->StateTimer = 0; |
| | 894 | return 1; |
| | 895 | } |
| | 896 | } |
| | 897 | |
| | 898 | return 0; |
| | 899 | } |
| | 900 | |
| | 901 | static enum AMMO_ID GetAttackDamageType(STRATEGYBLOCK *sbPtr, int flagnum) |
| | 902 | { |
| | 903 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 904 | |
| | 905 | if (alienStatusPointer->current_attack == NULL) |
| | 906 | return AMMO_NONE; |
| | 907 | |
| | 908 | /* Fix praetorian damage here! */ |
| | 909 | |
| | 910 | switch (alienStatusPointer->Type) |
| | 911 | { |
| | 912 | case Standard: |
| | 913 | default: |
| | 914 | /* No change. */ |
| | 915 | return (alienStatusPointer->current_attack->flag_damage[flagnum]); |
| | 916 | case Predalien: |
| | 917 | { |
| | 918 | switch (alienStatusPointer->current_attack->flag_damage[flagnum]) |
| | 919 | { |
| | 920 | case AMMO_ALIEN_CLAW: |
| | 921 | default: |
| | 922 | return AMMO_NPC_PREDALIEN_CLAW; |
| | 923 | case AMMO_ALIEN_TAIL: |
| | 924 | return AMMO_NPC_PREDALIEN_TAIL; |
| | 925 | case AMMO_NPC_ALIEN_BITE: |
| | 926 | return AMMO_NPC_PREDALIEN_BITE; |
| | 927 | } |
| | 928 | } |
| | 929 | case Praetorian: |
| | 930 | { |
| | 931 | switch (alienStatusPointer->current_attack->flag_damage[flagnum]) |
| | 932 | { |
| | 933 | case AMMO_ALIEN_CLAW: |
| | 934 | default: |
| | 935 | return AMMO_NPC_PRAETORIAN_CLAW; |
| | 936 | case AMMO_ALIEN_TAIL: |
| | 937 | return AMMO_NPC_PRAETORIAN_TAIL; |
| | 938 | case AMMO_NPC_ALIEN_BITE: |
| | 939 | return AMMO_NPC_PRAETORIAN_BITE; |
| | 940 | } |
| | 941 | } |
| | 942 | } |
| | 943 | } |
| | 944 | |
| | 945 | static void AlienNearDamageShell(STRATEGYBLOCK *sbPtr) |
| | 946 | { |
| | 947 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 948 | |
| | 949 | /* Damage shell! */ |
| | 950 | int workingflags = alienStatusPointer->HModelController.keyframe_flags >> 1; |
| | 951 | |
| | 952 | int a=0; |
| | 953 | for (; a < NUM_ATTACKFLAGS; a++) |
| | 954 | { |
| | 955 | if (workingflags & 1) |
| | 956 | { |
| | 957 | /* Oops, check range first. */ |
| | 958 | VECTORCH rel_pos, attack_dir; |
| | 959 | rel_pos.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 960 | rel_pos.vy = alienStatusPointer->Target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy; |
| | 961 | rel_pos.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 962 | GetDirectionOfAttack(alienStatusPointer->Target, &rel_pos, &attack_dir); |
| | 963 | |
| | 964 | if (alienStatusPointer->Target->DisplayBlock && alienStatusPointer->Target->DisplayBlock->HModelControlBlock) |
| | 965 | HtoHDamageToHModel(alienStatusPointer->Target, &TemplateAmmo[GetAttackDamageType(sbPtr, a)].MaxDamage, ONE_FIXED, sbPtr,
&attack_dir); |
| | 966 | else |
| | 967 | CauseDamageToObject(alienStatusPointer->Target, &TemplateAmmo[GetAttackDamageType(sbPtr, a)].MaxDamage, ONE_FIXED, &attack_dir); |
| | 968 | } |
| | 969 | |
| | 970 | /* Prepare next flag. */ |
| | 971 | workingflags >>= 1; |
| | 972 | } |
| | 973 | } |
| | 974 | |
| | 975 | static AIMODULE *FarNPC_GetTargetAIModuleForGlobalHunt(STRATEGYBLOCK *sbPtr) |
| | 976 | { |
| | 977 | unsigned int highestSmell = 0; |
| | 978 | AIMODULE* targetModule = NULL; |
| | 979 | |
| | 980 | AIMODULE **AdjModuleRefPtr = sbPtr->containingModule->m_aimodule->m_link_ptrs; |
| | 981 | |
| | 982 | /* check that there is a list of adjacent modules, and that it is not |
| | 983 | empty (ie points to zero) */ |
| | 984 | |
| | 985 | if(AdjModuleRefPtr) |
| | 986 | { |
| | 987 | while(*AdjModuleRefPtr != 0) |
| | 988 | { |
| | 989 | /* get the index */ |
| | 990 | int AdjModuleIndex = (*AdjModuleRefPtr)->m_index; |
| | 991 | |
| | 992 | /* if this adjacent module's smell value is higher than |
| | 993 | the current 'highest smell' record the new module as the |
| | 994 | target. */ |
| | 995 | |
| | 996 | if(PherAls_ReadBuf[AdjModuleIndex] > highestSmell) |
| | 997 | { |
| | 998 | highestSmell = PherAls_ReadBuf[AdjModuleIndex]; |
| | 999 | targetModule = *AdjModuleRefPtr; |
| | 1000 | } |
| | 1001 | /* next adjacent module reference pointer */ |
| | 1002 | AdjModuleRefPtr++; |
| | 1003 | } |
| | 1004 | } |
| | 1005 | |
| | 1006 | if (highestSmell < PherAls_ReadBuf[sbPtr->containingModule->m_aimodule->m_index]) |
| | 1007 | return (sbPtr->containingModule->m_aimodule); |
| | 1008 | else |
| | 1009 | return (targetModule); |
| | 1010 | } |
| | 1011 | |
| | 1012 | static void CheckPounceIntegrity(STRATEGYBLOCK *sbPtr) |
| | 1013 | { |
| | 1014 | VECTORCH targetPoint; |
| | 1015 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1016 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 1017 | |
| | 1018 | if (alienStatusPointer->Target == NULL) |
| | 1019 | { |
| | 1020 | /* Attack what? */ |
| | 1021 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 1022 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 1023 | return; |
| | 1024 | } |
| | 1025 | |
| | 1026 | if ((alienStatusPointer->Target->DisplayBlock == NULL) || ((alienStatusPointer->Target->DynPtr->Position.vy -
sbPtr->DynPtr->Position.vy) > 1000)) |
| | 1027 | { |
| | 1028 | /* Yuck. Target is far, or too far below you. */ |
| | 1029 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 1030 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 1031 | |
| | 1032 | alienStatusPointer->StateTimer = 0; |
| | 1033 | alienStatusPointer->CurveTimeOut = 0; |
| | 1034 | return; |
| | 1035 | } |
| | 1036 | |
| | 1037 | GetTargetingPointOfObject(alienStatusPointer->Target->DisplayBlock, &targetPoint); |
| | 1038 | |
| | 1039 | /* Do we have a clear line of sight? */ |
| | 1040 | |
| | 1041 | if (!IsThisObjectVisibleFromThisPosition_WithIgnore(sbPtr->DisplayBlock, alienStatusPointer->Target->DisplayBlock, &targetPoint)) |
| | 1042 | { |
| | 1043 | /* Can't see! */ |
| | 1044 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 1045 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 1046 | |
| | 1047 | alienStatusPointer->StateTimer = 0; |
| | 1048 | alienStatusPointer->CurveTimeOut = 0; |
| | 1049 | return; |
| | 1050 | } |
| | 1051 | |
| | 1052 | /* Orientate towards player, just to make sure we're facing */ |
| | 1053 | { |
| | 1054 | VECTORCH orientationDirn; |
| | 1055 | orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 1056 | orientationDirn.vy = 0; |
| | 1057 | orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 1058 | |
| | 1059 | if (!NPCOrientateToVector(sbPtr, &orientationDirn,NPC_TURNRATE)) |
| | 1060 | { |
| | 1061 | /* Still not right. Be careful. */ |
| | 1062 | alienStatusPointer->HModelController.StopAfterTweening = 1; |
| | 1063 | } |
| | 1064 | else |
| | 1065 | { |
| | 1066 | /* Okay for the moment. */ |
| | 1067 | alienStatusPointer->HModelController.StopAfterTweening = 0; |
| | 1068 | } |
| | 1069 | } |
| | 1070 | |
| | 1071 | /* change back to approach?: don't need to directly test if we should go to wander, as |
| | 1072 | approach state will do this... */ |
| | 1073 | { |
| | 1074 | int distance_to_target = VectorDistance(&dynPtr->Position, &alienStatusPointer->Target->DynPtr->Position); |
| | 1075 | |
| | 1076 | if(distance_to_target > ALIEN_POUNCE_MAXRANGE) |
| | 1077 | { |
| | 1078 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 1079 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 1080 | |
| | 1081 | alienStatusPointer->StateTimer = 0; |
| | 1082 | alienStatusPointer->CurveTimeOut = 0; |
| | 1083 | return; |
| | 1084 | } |
| | 1085 | } |
| | 1086 | |
| | 1087 | /* Are we still able to pounce? */ |
| | 1088 | |
| | 1089 | /* Not if you've lost any leg sections. */ |
| | 1090 | if ( (alienStatusPointer->Wounds & (section_flag_left_leg | section_flag_right_leg)) |
| | 1091 | /* Also not if you've lost both feet. */ |
| | 1092 | || ((alienStatusPointer->Wounds & section_flag_left_foot) && (alienStatusPointer->Wounds & section_flag_right_foot)) ) |
| | 1093 | { |
| | 1094 | /* Can't stand either. Fall over. */ |
| | 1095 | /* That implies going back to approach, btw. */ |
| | 1096 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 1097 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 1098 | |
| | 1099 | alienStatusPointer->StateTimer = 0; |
| | 1100 | alienStatusPointer->CurveTimeOut = 0; |
| | 1101 | } |
| | 1102 | } |
| | 1103 | |
| | 1104 | static void ApplyPounceImpulse(STRATEGYBLOCK *sbPtr) |
| | 1105 | { |
| | 1106 | VECTORCH pounceVector,targetPoint; |
| | 1107 | int speed; |
| | 1108 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1109 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 1110 | |
| | 1111 | GetTargetingPointOfObject(alienStatusPointer->Target->DisplayBlock,&targetPoint); |
| | 1112 | |
| | 1113 | int dist = VectorDistance(&dynPtr->Position, &targetPoint); |
| | 1114 | |
| | 1115 | /* Apply a correction based on range. */ |
| | 1116 | targetPoint.vy -= dist >> 3; |
| | 1117 | |
| | 1118 | pounceVector.vx = targetPoint.vx - dynPtr->Position.vx; |
| | 1119 | pounceVector.vy = targetPoint.vy - dynPtr->Position.vy; |
| | 1120 | pounceVector.vz = targetPoint.vz - dynPtr->Position.vz; |
| | 1121 | |
| | 1122 | Normalise(&pounceVector); |
| | 1123 | /* Must jump at least a little bit upwards. */ |
| | 1124 | if (pounceVector.vy > -10000) |
| | 1125 | pounceVector.vy = -10000; |
| | 1126 | |
| | 1127 | switch (alienStatusPointer->Type) |
| | 1128 | { |
| | 1129 | case Standard: |
| | 1130 | default: |
| | 1131 | speed = ALIEN_JUMP_SPEED; |
| | 1132 | break; |
| | 1133 | case Predalien: |
| | 1134 | speed = PREDALIEN_JUMP_SPEED; |
| | 1135 | break; |
| | 1136 | case Praetorian: |
| | 1137 | speed = PRAETORIAN_JUMP_SPEED; |
| | 1138 | } |
| | 1139 | |
| | 1140 | int factor = GetAlienSpeedFactor_ForSequence(sbPtr, HMSQT_AlienRun, (int)ARSS_Standard); |
| | 1141 | speed = MUL_FIXED(speed, factor); |
| | 1142 | |
| | 1143 | pounceVector.vx = MUL_FIXED(speed,pounceVector.vx); |
| | 1144 | pounceVector.vy = MUL_FIXED(speed,pounceVector.vy); |
| | 1145 | pounceVector.vz = MUL_FIXED(speed,pounceVector.vz); |
| | 1146 | |
| | 1147 | sbPtr->DynPtr->LinImpulse = pounceVector; |
| | 1148 | } |
| | 1149 | |
| | 1150 | static int make_new_alien(STRATEGYBLOCK *sbPtr, ALIEN_TYPE type_of_alien, ALIEN_BHSTATE starting_state, STRATEGYBLOCK *Generator) |
| | 1151 | { |
| | 1152 | sbPtr->dataptr = malloc(sizeof(ALIEN_STATUS_BLOCK)); |
| | 1153 | sbPtr->maintainVisibility = 1; |
| | 1154 | sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL); |
| | 1155 | |
| | 1156 | if(NULL == sbPtr->dataptr) |
| | 1157 | { |
| | 1158 | RemoveBehaviourStrategy(sbPtr); |
| | 1159 | return 0; |
| | 1160 | } |
| | 1161 | |
| | 1162 | ALIEN_STATUS_BLOCK *new_alien = (ALIEN_STATUS_BLOCK *)sbPtr->dataptr; |
| | 1163 | |
| | 1164 | new_alien->HModelController.Deltas = NULL; |
| | 1165 | new_alien->HModelController.Root_Section = NULL; |
| | 1166 | new_alien->HModelController.section_data = NULL; |
| | 1167 | new_alien->Type = type_of_alien; |
| | 1168 | new_alien->BehaviourState = starting_state; |
| | 1169 | new_alien->GibbFactor = 0; |
| | 1170 | new_alien->MaxSpeed = 0; |
| | 1171 | new_alien->Wounds = 0; |
| | 1172 | new_alien->last_anim_length = ONE_FIXED; |
| | 1173 | new_alien->incidentFlag = 0; |
| | 1174 | new_alien->incidentTimer = 0; |
| | 1175 | new_alien->CurveRadius = 0; |
| | 1176 | new_alien->CurveLength = 0; |
| | 1177 | new_alien->CurveTimeOut = 0; |
| | 1178 | new_alien->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 1179 | new_alien->IAmCrouched = 0; |
| | 1180 | new_alien->CurrentLightAtAlien = 0; |
| | 1181 | new_alien->EnableWaypoints = 0; |
| | 1182 | new_alien->PreferToCrouch = 0; |
| | 1183 | new_alien->aliensIgniterId = 0; //Which player in a multiplayer game toasted this poor beast? |
| | 1184 | new_alien->soundOnFire = SOUND_NOACTIVEINDEX; |
| | 1185 | new_alien->sound_mouth = SOUND_NOACTIVEINDEX; |
| | 1186 | new_alien->unconscious = 0; |
| | 1187 | new_alien->CanStand = 1; |
| | 1188 | new_alien->CanClimb = 1; |
| | 1189 | new_alien->current_attack = NULL; |
| | 1190 | new_alien->huntingModule = NULL; |
| | 1191 | new_alien->Target = NULL; |
| | 1192 | |
| | 1193 | COPY_NAME(new_alien->Target_SBname, Null_Name); |
| | 1194 | |
| | 1195 | { |
| | 1196 | int i = 0; |
| | 1197 | for(; i < SB_NAME_LENGTH; i++) |
| | 1198 | new_alien->death_target_ID[i] = 0; |
| | 1199 | } |
| | 1200 | new_alien->death_target_sbptr = NULL; |
| | 1201 | new_alien->generator_sbptr = Generator; |
| | 1202 | |
| | 1203 | { |
| | 1204 | const NPC_DATA *NpcData; |
| | 1205 | const SECTION *root_section; |
| | 1206 | |
| | 1207 | switch (new_alien->Type) |
| | 1208 | { |
| | 1209 | case 0: |
| | 1210 | default: |
| | 1211 | NpcData = &NpcDataList[I_NPC_Alien]; |
| | 1212 | new_alien->MaxSpeed = ALIEN_FORWARDVELOCITY; |
| | 1213 | new_alien->EnableWaypoints = (FastRandom() & 7); |
| | 1214 | sbPtr->DynPtr->Mass = ALIEN_MASS; |
| | 1215 | root_section = GetNamedHierarchyFromLibrary("hnpcalien", "alien"); |
| | 1216 | break; |
| | 1217 | case 1: |
| | 1218 | NpcData = &NpcDataList[I_NPC_PredatorAlien]; |
| | 1219 | new_alien->MaxSpeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, PREDALIEN_SPEED_FACTOR); |
| | 1220 | new_alien->EnableWaypoints = 1; |
| | 1221 | sbPtr->DynPtr->Mass = PREDALIEN_MASS; |
| | 1222 | root_section = GetNamedHierarchyFromLibrary("hnpcpred_alien", "TEMPLATE"); |
| | 1223 | break; |
| | 1224 | case 2: |
| | 1225 | NpcData = &NpcDataList[I_NPC_PraetorianGuard]; |
| | 1226 | new_alien->MaxSpeed = MUL_FIXED(ALIEN_FORWARDVELOCITY, MUL_FIXED(PRAETORIAN_WALKSPEED_FACTOR, PRAETORIAN_SPEED_FACTOR)); |
| | 1227 | sbPtr->DynPtr->Mass = PRAETORIAN_MASS; |
| | 1228 | new_alien->EnableWaypoints = 0; |
| | 1229 | root_section = GetNamedHierarchyFromLibrary("hnpcpretorian", "Template"); |
| | 1230 | new_alien->CanClimb = 0; // Praetorian Guard can't climb. Sorry. |
| | 1231 | } |
| | 1232 | |
| | 1233 | new_alien->EnableWaypoints = 0; // jadda |
| | 1234 | sbPtr->DamageBlock = NpcData->StartingStats; |
| | 1235 | sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT; |
| | 1236 | sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT; |
| | 1237 | |
| | 1238 | if (!root_section || !sbPtr->containingModule) |
| | 1239 | { |
| | 1240 | RemoveBehaviourStrategy(sbPtr); |
| | 1241 | return 0; |
| | 1242 | } |
| | 1243 | |
| | 1244 | Create_HModel(&new_alien->HModelController, root_section); |
| | 1245 | } |
| | 1246 | |
| | 1247 | NPC_InitMovementData(&new_alien->moveData); |
| | 1248 | NPC_InitWanderData(&new_alien->wanderData); |
| | 1249 | Initialise_AvoidanceManager(&new_alien->avoidanceManager); |
| | 1250 | InitWaypointManager(&new_alien->waypointManager); |
| | 1251 | |
| | 1252 | if(ABS_Dormant == new_alien->BehaviourState) |
| | 1253 | InitHModelSequence(&new_alien->HModelController, HMSQT_AlienStand, ASSS_Dormant, -1); |
| | 1254 | else |
| | 1255 | InitHModelSequence(&new_alien->HModelController, 0, 0, ONE_FIXED); |
| | 1256 | |
| | 1257 | new_alien->HModelController.Playing = 0; |
| | 1258 | |
| | 1259 | if (CHEATMODE_SLUGTRAIL == UserProfile.active_bonus) |
| | 1260 | { |
| | 1261 | /* Blow off a leg? */ |
| | 1262 | SECTION_DATA *leg = GetThisSectionData(new_alien->HModelController.section_data, "left thigh"); |
| | 1263 | |
| | 1264 | if (leg) |
| | 1265 | { |
| | 1266 | Prune_HModel_Virtual(leg); |
| | 1267 | new_alien->Wounds = section_flag_left_leg | section_flag_left_foot; |
| | 1268 | new_alien->CanStand = 0; |
| | 1269 | sbPtr->DamageBlock.Health -= (20 << ONE_FIXED_SHIFT); |
| | 1270 | } |
| | 1271 | } |
| | 1272 | |
| | 1273 | if (HModelSequence_Exists(&new_alien->HModelController, (int)HMSQT_AlienStand, (int)ASSS_Hit_Right)) |
| | 1274 | { |
| | 1275 | DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_alien->HModelController, "HitDelta", (int)HMSQT_AlienStand, (int)ASSS_Hit_Right, -1); |
| | 1276 | assert(delta); |
| | 1277 | delta->Playing = 0; |
| | 1278 | } |
| | 1279 | |
| | 1280 | ProveHModel_Far(&new_alien->HModelController, sbPtr); |
| | 1281 | |
| | 1282 | return 1; |
| | 1283 | } |
| | 1284 | |
| | 1285 | void CreateAlienBot(VECTORCH *Position, int type) |
| | 1286 | { |
| | 1287 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourAlien); |
| | 1288 | |
| | 1289 | if(!sbPtr) |
| | 1290 | return; |
| | 1291 | |
| | 1292 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 1293 | |
| | 1294 | if(sbPtr->DynPtr) |
| | 1295 | { |
| | 1296 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 1297 | AssignNewSBName(sbPtr); |
| | 1298 | dynPtr->PrevPosition = dynPtr->Position = *Position; |
| | 1299 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 1300 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 1301 | sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; |
| | 1302 | make_new_alien(sbPtr, type, ABS_Hunt, NULL); |
| | 1303 | } |
| | 1304 | else |
| | 1305 | { |
| | 1306 | RemoveBehaviourStrategy(sbPtr); |
| | 1307 | } |
| | 1308 | } |
| | 1309 | |
| | 1310 | void CastAlienBot(int type) |
| | 1311 | { |
| | 1312 | #define BOTRANGE 2000 |
| | 1313 | |
| | 1314 | VECTORCH position; |
| | 1315 | position = PlayerStatus.sbptr->DynPtr->Position; |
| | 1316 | position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE); |
| | 1317 | position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE); |
| | 1318 | position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE); |
| | 1319 | |
| | 1320 | CreateAlienBot(&position, type); |
| | 1321 | } |
| | 1322 | |
| | 1323 | /*----------------------Patrick 15/11/96----------------------------- |
| | 1324 | This function is called by the alien generators, to dynamically |
| | 1325 | create a new alien, during the game. The alien is initialised |
| | 1326 | as invisible. |
| | 1327 | |
| | 1328 | 1. create a new strategy block (no diplay block) |
| | 1329 | 2. attach a dynamics block |
| | 1330 | 3. attach an alien data block |
| | 1331 | 4. initialise for far behaviour |
| | 1332 | |
| | 1333 | NB the strategyblock passed here is a reference to the generator sb |
| | 1334 | --------------------------------------------------------------------*/ |
| | 1335 | void CreateAlienDynamic(STRATEGYBLOCK *Generator, ALIEN_TYPE type_of_alien) |
| | 1336 | { |
| | 1337 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourAlien); |
| | 1338 | |
| | 1339 | if(NULL != sbPtr) |
| | 1340 | { |
| | 1341 | DYNAMICSBLOCK *dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 1342 | |
| | 1343 | if(NULL != dynPtr) |
| | 1344 | { |
| | 1345 | sbPtr->DynPtr = dynPtr; |
| | 1346 | AssignNewSBName(sbPtr); |
| | 1347 | dynPtr->PrevPosition = dynPtr->Position = ((GENERATOR_BLOCK* )Generator->dataptr)->Position; |
| | 1348 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 1349 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 1350 | sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; |
| | 1351 | make_new_alien(sbPtr, type_of_alien, ABS_Hunt, Generator); |
| | 1352 | |
| | 1353 | /* assert alien is starting as invisible */ |
| | 1354 | assert(!ModuleCurrVisArray[sbPtr->containingModule->m_index]); |
| | 1355 | } |
| | 1356 | else |
| | 1357 | { |
| | 1358 | RemoveBehaviourStrategy(sbPtr); |
| | 1359 | } |
| | 1360 | } |
| | 1361 | } |
| | 1362 | |
| | 1363 | void MakeAlienFar(STRATEGYBLOCK *sbPtr) |
| | 1364 | { |
| | 1365 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1366 | DestroyActiveObject(&sbPtr->DisplayBlock); |
| | 1367 | |
| | 1368 | if(alienStatusPointer->soundOnFire != SOUND_NOACTIVEINDEX) |
| | 1369 | Sound_Stop(alienStatusPointer->soundOnFire); |
| | 1370 | |
| | 1371 | if(alienStatusPointer->sound_mouth != SOUND_NOACTIVEINDEX) |
| | 1372 | Sound_Stop(alienStatusPointer->sound_mouth); |
| | 1373 | |
| | 1374 | switch(alienStatusPointer->BehaviourState) |
| | 1375 | { |
| | 1376 | case ABS_Dormant: |
| | 1377 | case ABS_Awakening: |
| | 1378 | break; |
| | 1379 | default: |
| | 1380 | alienStatusPointer->BehaviourState = alienStatusPointer->Target ? ABS_Hunt : ABS_Wander; |
| | 1381 | } |
| | 1382 | |
| | 1383 | NPC_InitWanderData(&alienStatusPointer->wanderData); |
| | 1384 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 1385 | alienStatusPointer->current_attack = NULL; |
| | 1386 | } |
| | 1387 | |
| | 1388 | /*----------------------Patrick 7/11/96----------------------------- |
| | 1389 | This function is used to initialise a riff-loaded in alien. |
| | 1390 | -------------------------------------------------------------------*/ |
| | 1391 | void InitAlienBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) |
| | 1392 | { |
| | 1393 | TOOLS_DATA_ALIEN *toolsData = (TOOLS_DATA_ALIEN *)bhdata; |
| | 1394 | int i; |
| | 1395 | |
| | 1396 | /* |
| | 1397 | NB it is necessary that placed aliens are initialised without a |
| | 1398 | displayblock, otherwise far aliens will be re-initialised by |
| | 1399 | MakeAlienFar() to a hunting state instead of a wait state....*/ |
| | 1400 | |
| | 1401 | assert(!sbPtr->DisplayBlock); |
| | 1402 | |
| | 1403 | if(SinglePlayer == AvP.PlayMode) |
| | 1404 | { |
| | 1405 | for(i=0; i < SB_NAME_LENGTH; i++) |
| | 1406 | sbPtr->SBname[i] = toolsData->nameID[i]; |
| | 1407 | } |
| | 1408 | else |
| | 1409 | { |
| | 1410 | //in a network game , generate a new sb name (so that it gets a reasonably low value) |
| | 1411 | AssignNewSBName(sbPtr); |
| | 1412 | } |
| | 1413 | |
| | 1414 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 1415 | |
| | 1416 | if(sbPtr->DynPtr) |
| | 1417 | { |
| | 1418 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 1419 | dynPtr->PrevPosition = dynPtr->Position = toolsData->position; |
| | 1420 | dynPtr->OrientEuler = toolsData->starteuler; |
| | 1421 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 1422 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 1423 | sbPtr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; |
| | 1424 | |
| | 1425 | if(make_new_alien(sbPtr, toolsData->type, ((toolsData->start_inactive) ? ABS_Dormant : ABS_Wait), NULL)) |
| | 1426 | { |
| | 1427 | ALIEN_STATUS_BLOCK * alienStatus = (ALIEN_STATUS_BLOCK *)sbPtr->dataptr; |
| | 1428 | |
| | 1429 | for(i=0; i < SB_NAME_LENGTH; i++) |
| | 1430 | alienStatus->death_target_ID[i] = toolsData->death_target_ID[i]; |
| | 1431 | } |
| | 1432 | } |
| | 1433 | else |
| | 1434 | { |
| | 1435 | RemoveBehaviourStrategy(sbPtr); |
| | 1436 | } |
| | 1437 | } |
| | 1438 | |
| | 1439 | static int PlayerIsDeadAndNoLivingNetghosts() |
| | 1440 | { |
| | 1441 | if(SinglePlayer == AvP.PlayMode) |
| | 1442 | { |
| | 1443 | //just need to check for the only player we have |
| | 1444 | return !PlayerStatus.Alive || Observer; |
| | 1445 | } |
| | 1446 | else |
| | 1447 | { |
| | 1448 | int sbIndex = 0; |
| | 1449 | //first check the host player |
| | 1450 | |
| | 1451 | if(PlayerStatus.Alive || Observer) |
| | 1452 | return 0; |
| | 1453 | |
| | 1454 | /* go through the strategy blocks looking for players*/ |
| | 1455 | for(; sbIndex < NumActiveStBlocks; sbIndex++) |
| | 1456 | { |
| | 1457 | STRATEGYBLOCK *playerSbPtr = ActiveStBlockList[sbIndex]; |
| | 1458 | |
| | 1459 | if(playerSbPtr->type == I_BehaviourNetGhost) |
| | 1460 | { |
| | 1461 | NETGHOSTDATABLOCK *ghostData = (NETGHOSTDATABLOCK *)playerSbPtr->dataptr; |
| | 1462 | |
| | 1463 | switch(ghostData->type) |
| | 1464 | { |
| | 1465 | case I_BehaviourMarinePlayer: |
| | 1466 | case I_BehaviourPredatorPlayer: |
| | 1467 | //found a netghost of a player |
| | 1468 | return 0; |
| | 1469 | default: |
| | 1470 | break; |
| | 1471 | } |
| | 1472 | } |
| | 1473 | } |
| | 1474 | } |
| | 1475 | |
| | 1476 | //Dead, all dead. |
| | 1477 | return 1; |
| | 1478 | } |
| | 1479 | |
| | 1480 | static int Alien_TargetFilter(STRATEGYBLOCK *candidate, const ALIEN_STATUS_BLOCK *alienStatusPointer) |
| | 1481 | { |
| | 1482 | switch (candidate->type) |
| | 1483 | { |
| | 1484 | case I_BehaviourFlare: |
| | 1485 | return (!alienStatusPointer->Wounds && !(FastRandom() & 3)); // this could be a trap from marine bot or marine player |
| | 1486 | case I_BehaviourMarine: |
| | 1487 | case I_BehaviourMarinePlayer: |
| | 1488 | case I_BehaviourPredatorPlayer: |
| | 1489 | case I_BehaviourPredator: |
| | 1490 | case I_BehaviourAutoGun: |
| | 1491 | //case I_BehaviourAlien: |
| | 1492 | case I_BehaviourCorpse: |
| | 1493 | return 1; |
| | 1494 | case I_BehaviourPlacedLight: |
| | 1495 | { |
| | 1496 | break; |
| | 1497 | if(Standard == alienStatusPointer->Type) |
| | 1498 | { |
| | 1499 | if(!candidate->maintainVisibility) |
| | 1500 | { |
| | 1501 | return 0; |
| | 1502 | } |
| | 1503 | else |
| | 1504 | { |
| | 1505 | PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = (PLACED_LIGHT_BEHAV_BLOCK*)candidate->dataptr; |
| | 1506 | |
| | 1507 | if(!candidate->maintainVisibility || candidate->DamageBlock.Indestructable) // valid anyway? |
| | 1508 | return 0; |
| | 1509 | else if(FastRandom() & 5) |
| | 1510 | return ((Light_State_Broken != pl_bhv->state) && (Light_OnOff_Off != pl_bhv->on_off_state)); |
| | 1511 | } |
| | 1512 | } |
| | 1513 | else |
| | 1514 | { |
| | 1515 | return 0; |
| | 1516 | } |
| | 1517 | } |
| | 1518 | case I_BehaviourNetGhost: |
| | 1519 | { |
| | 1520 | NETGHOSTDATABLOCK *dataptr = candidate->dataptr; |
| | 1521 | |
| | 1522 | switch (dataptr->type) |
| | 1523 | { |
| | 1524 | case I_BehaviourMarinePlayer: |
| | 1525 | case I_BehaviourPredatorPlayer: |
| | 1526 | return 1; |
| | 1527 | default: |
| | 1528 | return 0; |
| | 1529 | } |
| | 1530 | } |
| | 1531 | default: |
| | 1532 | return 0; |
| | 1533 | } |
| | 1534 | return 0; |
| | 1535 | } |
| | 1536 | |
| | 1537 | struct alien_targets |
| | 1538 | { |
| | 1539 | int distance; |
| | 1540 | STRATEGYBLOCK * target; |
| | 1541 | }; |
| | 1542 | |
| | 1543 | static int AlienHasPathToTarget(STRATEGYBLOCK *sbPtr) |
| | 1544 | { |
| | 1545 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1546 | |
| | 1547 | return (alienStatusPointer->Target != NULL) ? ( NULL != GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule,
alienStatusPointer->Target->containingModule->m_aimodule, 4, 1, 1)) : 0; |
| | 1548 | //return (alienStatusPointer->Target != NULL) ? ( NULL != GetNextModuleForLink_Core(sbPtr->containingModule->m_aimodule,
alienStatusPointer->Target->containingModule->m_aimodule, 7, 0, 1)) : 0; |
| | 1549 | } |
| | 1550 | |
| | 1551 | static int sort_targets(const void *void_a, const void *void_b) |
| | 1552 | { |
| | 1553 | const struct alien_targets * a = void_a; |
| | 1554 | const struct alien_targets * b = void_b; |
| | 1555 | |
| | 1556 | return (a->distance < b->distance) ? -1 : (a->distance > b->distance); |
| | 1557 | } |
| | 1558 | |
| | 1559 | static STRATEGYBLOCK *Alien_GetNewTarget(const STRATEGYBLOCK *sbptr) |
| | 1560 | { |
| | 1561 | struct alien_targets Targets[5] = { {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL} }; |
| | 1562 | int neardist = ONE_FIXED; |
| | 1563 | STRATEGYBLOCK *nearest = NULL; |
| | 1564 | //MODULE *dmod = ModuleFromPosition(&sbptr->DynPtr->Position, PlayerStatus.sbptr->containingModule); |
| | 1565 | //MODULE *dmod = ModuleFromPosition(&sbptr->DynPtr->Position, NULL); |
| | 1566 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbptr->dataptr); |
| | 1567 | int a; |
| | 1568 | int i = 0; |
| | 1569 | int wraps = 0; |
| | 1570 | const VECTORCH *alienpos = &sbptr->DynPtr->Position; |
| | 1571 | |
| | 1572 | for (a = 0; a < NumActiveStBlocks; a++) |
| | 1573 | { |
| | 1574 | STRATEGYBLOCK *candidate = ActiveStBlockList[a]; |
| | 1575 | |
| | 1576 | if (Alien_TargetFilter(candidate, alienStatusPointer)) |
| | 1577 | { |
| | 1578 | VECTORCH offset; |
| | 1579 | |
| | 1580 | offset.vx = alienpos->vx - candidate->DynPtr->Position.vx; |
| | 1581 | offset.vy = alienpos->vy - candidate->DynPtr->Position.vy; |
| | 1582 | offset.vz = alienpos->vz - candidate->DynPtr->Position.vz; |
| | 1583 | |
| | 1584 | int dist = Approximate3dMagnitude(&offset); |
| | 1585 | |
| | 1586 | if (dist < neardist) |
| | 1587 | { |
| | 1588 | //if (!NPC_IsDead(candidate) && AlienHasPathToTarget(sbptr) && IsModuleVisibleFromModule(dmod, candidate->containingModule)) |
| | 1589 | if (!NPC_IsDead(candidate))// && IsModuleVisibleFromModule(dmod, candidate->containingModule)) |
| | 1590 | { |
| | 1591 | nearest = candidate; |
| | 1592 | neardist = dist; |
| | 1593 | |
| | 1594 | if(4 == i) |
| | 1595 | { |
| | 1596 | i = 0; |
| | 1597 | wraps = 1; |
| | 1598 | } |
| | 1599 | |
| | 1600 | Targets[i].target = candidate; |
| | 1601 | Targets[i].distance = dist; |
| | 1602 | i++; |
| | 1603 | } |
| | 1604 | } |
| | 1605 | } |
| | 1606 | } |
| | 1607 | |
| | 1608 | |
| | 1609 | return nearest; |
| | 1610 | if(nearest) |
| | 1611 | { |
| | 1612 | int numberofnear_marines = 0; |
| | 1613 | int numberofnear_aliens = 0; |
| | 1614 | int numberofnear_predators = 0; |
| | 1615 | int hiding_in_waiting = 0; |
| | 1616 | |
| | 1617 | if (!alienStatusPointer->CurrentLightAtAlien) |
| | 1618 | hiding_in_waiting = !DynamicObjectIsMoving(sbptr->DynPtr); |
| | 1619 | |
| | 1620 | switch (nearest->type) |
| | 1621 | { |
| | 1622 | case I_BehaviourMarine: |
| | 1623 | case I_BehaviourMarinePlayer: |
| | 1624 | case I_BehaviourPredator: |
| | 1625 | case I_BehaviourPredatorPlayer: |
| | 1626 | { |
| | 1627 | if(neardist < ALIEN_POUNCE_MAXRANGE) |
| | 1628 | { |
| | 1629 | if (alienStatusPointer->Wounds && (alienStatusPointer->Type == Standard)) |
| | 1630 | { |
| | 1631 | alienStatusPointer->BehaviourState = ABS_Retreat; |
| | 1632 | return NULL; |
| | 1633 | } |
| | 1634 | |
| | 1635 | return nearest; |
| | 1636 | } |
| | 1637 | } |
| | 1638 | default: |
| | 1639 | break; |
| | 1640 | } |
| | 1641 | |
| | 1642 | if (wraps) |
| | 1643 | i = 5; |
| | 1644 | |
| | 1645 | qsort(Targets, 5, sizeof(struct alien_targets), sort_targets); |
| | 1646 | |
| | 1647 | for (a = 0; a < i; a++) |
| | 1648 | { |
| | 1649 | if(NULL == Targets[a].target || (Targets[a].target == nearest)) |
| | 1650 | continue; |
| | 1651 | |
| | 1652 | //printf("TARGETS type %d distance %d\n", Targets[a].target->type, Targets[a].distance); |
| | 1653 | |
| | 1654 | //if (alienStatusPointer->Wounds) |
| | 1655 | STRATEGYBLOCK *target = Targets[a].target; |
| | 1656 | |
| | 1657 | switch(target->type) |
| | 1658 | { |
| | 1659 | case I_BehaviourMarine: |
| | 1660 | case I_BehaviourMarinePlayer: |
| | 1661 | numberofnear_marines++; |
| | 1662 | |
| | 1663 | if (Targets[a].distance < ALIEN_POUNCE_MAXRANGE) |
| | 1664 | { |
| | 1665 | //if(hiding_in_waiting) |
| | 1666 | return Targets[a].target; |
| | 1667 | } |
| | 1668 | break; |
| | 1669 | case I_BehaviourPredatorPlayer: |
| | 1670 | case I_BehaviourPredator: |
| | 1671 | numberofnear_predators++; |
| | 1672 | |
| | 1673 | if (Targets[a].distance < ALIEN_POUNCE_MAXRANGE) |
| | 1674 | { |
| | 1675 | //if(hiding_in_waiting) |
| | 1676 | return Targets[a].target; |
| | 1677 | } |
| | 1678 | break; |
| | 1679 | case I_BehaviourPlacedLight: |
| | 1680 | if(alienStatusPointer->CurrentLightAtAlien || alienStatusPointer->Wounds) |
| | 1681 | return Targets[a].target; |
| | 1682 | break; |
| | 1683 | case I_BehaviourFlare: |
| | 1684 | { |
| | 1685 | if (!alienStatusPointer->Wounds && !(FastRandom() & 3)) // this could be a trap from marine bot or marine player |
| | 1686 | { |
| | 1687 | alienStatusPointer->IAmCrouched = 0; |
| | 1688 | return Targets[a].target; |
| | 1689 | } |
| | 1690 | } |
| | 1691 | break; |
| | 1692 | case I_BehaviourAlien: |
| | 1693 | { |
| | 1694 | ALIEN_STATUS_BLOCK *alien_friend = (ALIEN_STATUS_BLOCK *)(target->dataptr); |
| | 1695 | numberofnear_aliens++; |
| | 1696 | |
| | 1697 | if(numberofnear_aliens > 3) // we have a cluster of aliens let's give alien cluster a target |
| | 1698 | { |
| | 1699 | STRATEGYBLOCK *chossen_target = NULL; |
| | 1700 | neardist = ONE_FIXED; |
| | 1701 | int x = 0; |
| | 1702 | for (; x < NumActiveStBlocks; x++) |
| | 1703 | { |
| | 1704 | STRATEGYBLOCK *candidate = ActiveStBlockList[x]; |
| | 1705 | |
| | 1706 | if ((candidate != sbptr) && candidate->DynPtr) |
| | 1707 | { |
| | 1708 | switch (candidate->type) |
| | 1709 | { |
| | 1710 | case I_BehaviourMarinePlayer: |
| | 1711 | case I_BehaviourPredatorPlayer: |
| | 1712 | case I_BehaviourMarine: |
| | 1713 | case I_BehaviourPredator: |
| | 1714 | { |
| | 1715 | VECTORCH offset; |
| | 1716 | |
| | 1717 | offset.vx = alienpos->vx - candidate->DynPtr->Position.vx; |
| | 1718 | offset.vy = alienpos->vy - candidate->DynPtr->Position.vy; |
| | 1719 | offset.vz = alienpos->vz - candidate->DynPtr->Position.vz; |
| | 1720 | |
| | 1721 | int dist = Approximate3dMagnitude(&offset); |
| | 1722 | |
| | 1723 | if (dist < neardist) |
| | 1724 | { |
| | 1725 | if (!NPC_IsDead(candidate))// && IsModuleVisibleFromModule(dmod, candidate->containingModule)) |
| | 1726 | { |
| | 1727 | chossen_target = candidate; |
| | 1728 | neardist = dist; |
| | 1729 | } |
| | 1730 | } |
| | 1731 | } |
| | 1732 | default: |
| | 1733 | break; |
| | 1734 | } |
| | 1735 | } |
| | 1736 | } |
| | 1737 | |
| | 1738 | if(chossen_target) |
| | 1739 | { |
| | 1740 | x=0; |
| | 1741 | for (; x < i; x++) |
| | 1742 | { |
| | 1743 | ALIEN_STATUS_BLOCK *alien_friend = (ALIEN_STATUS_BLOCK *)(Targets[x].target->dataptr); |
| | 1744 | alien_friend->Target = chossen_target; |
| | 1745 | //Targets[i].target |
| | 1746 | } |
| | 1747 | puts("realsing cluster"); |
| | 1748 | } |
| | 1749 | |
| | 1750 | return nearest; |
| | 1751 | } |
| | 1752 | |
| | 1753 | //if(Targets[a].target->DynPtr->OrientMat.mat22 < 63000) |
| | 1754 | if (!alien_friend->CurrentLightAtAlien && (NULL == alien_friend->Target)) |
| | 1755 | //if (NULL == alien_friend->Target) |
| | 1756 | { |
| | 1757 | // let's join up |
| | 1758 | puts("let's join up"); |
| | 1759 | return Targets[a].target; |
| | 1760 | } |
| | 1761 | |
| | 1762 | if (alien_friend->Target) |
| | 1763 | { |
| | 1764 | switch (alien_friend->Target->type) |
| | 1765 | { |
| | 1766 | case I_BehaviourMarinePlayer: |
| | 1767 | case I_BehaviourPredatorPlayer: |
| | 1768 | case I_BehaviourPredator: |
| | 1769 | case I_BehaviourAutoGun: |
| | 1770 | return Targets[a].target; |
| | 1771 | default: |
| | 1772 | break; |
| | 1773 | } |
| | 1774 | } |
| | 1775 | } |
| | 1776 | default: |
| | 1777 | break; |
| | 1778 | } |
| | 1779 | } |
| | 1780 | |
| | 1781 | if(1 == numberofnear_aliens) |
| | 1782 | { |
| | 1783 | if((numberofnear_marines > 2) || numberofnear_predators) |
| | 1784 | { |
| | 1785 | alienStatusPointer->BehaviourState = ABS_Retreat; |
| | 1786 | return NULL; |
| | 1787 | } |
| | 1788 | } |
| | 1789 | else if (numberofnear_aliens > 2) |
| | 1790 | { |
| | 1791 | //if(I_BehaviourPlacedLight == nearest->type) |
| | 1792 | a = 0; |
| | 1793 | for (; a < i; a++) |
| | 1794 | { |
| | 1795 | switch(Targets[a].target->type) |
| | 1796 | { |
| | 1797 | case I_BehaviourPlacedLight: |
| | 1798 | return Targets[a].target; |
| | 1799 | default: |
| | 1800 | break; |
| | 1801 | } |
| | 1802 | } |
| | 1803 | } |
| | 1804 | else if (numberofnear_predators && (numberofnear_aliens < 2)) |
| | 1805 | { |
| | 1806 | } |
| | 1807 | } |
| | 1808 | |
| | 1809 | return nearest; |
| | 1810 | } |
| | 1811 | |
| | 1812 | /*--------------------Patrick 27/1/97---------------------- |
| | 1813 | This function is used by the various far alien behaviour |
| | 1814 | functions to move an alien NPC: it decides whether and how |
| | 1815 | to move an alien into a given target. |
| | 1816 | |
| | 1817 | 2/7/97 extra bit: |
| | 1818 | If a location fails, we flip the y-orientation of the npc, |
| | 1819 | so that wandering behaviour can find a new path; |
| | 1820 | ----------------------------------------------------------*/ |
| | 1821 | |
| | 1822 | static int ProcessFarAlienTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) |
| | 1823 | { |
| | 1824 | VECTORCH oldPos = sbPtr->DynPtr->Position; |
| | 1825 | |
| | 1826 | /* get the target module's status, and decide what to do */ |
| | 1827 | switch(GetTargetAIModuleStatus(sbPtr, targetModule, 1)) |
| | 1828 | { |
| | 1829 | case NPCTM_NoEntryPoint: |
| | 1830 | { |
| | 1831 | /* do nothing: can't get in. */ |
| | 1832 | FarNpc_FlipAround(sbPtr); |
| | 1833 | //entryPointFailures++; |
| | 1834 | } |
| | 1835 | break; |
| | 1836 | case NPCTM_NormalRoom: |
| | 1837 | case NPCTM_LiftDoorOpen: |
| | 1838 | case NPCTM_ProxDoorOpen: |
| | 1839 | case NPCTM_AirDuct: |
| | 1840 | case NPCTM_SecurityDoorOpen: |
| | 1841 | /* locate to target */ |
| | 1842 | LocateFarNPCInAIModule(sbPtr, targetModule); |
| | 1843 | break; |
| | 1844 | case NPCTM_ProxDoorNotOpen: |
| | 1845 | { |
| | 1846 | MODULE *renderModule = *(targetModule->m_module_ptrs); |
| | 1847 | /* trigger the door, and set timer to quick so we can catch the door when it's open */ |
| | 1848 | ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->dataptr)->alienTrigger = 1; |
| | 1849 | break; |
| | 1850 | } |
| | 1851 | case NPCTM_LiftTeleport: /* do nothing: aliens can't use lifts */ |
| | 1852 | case NPCTM_LiftDoorNotOpen: |
| | 1853 | case NPCTM_SecurityDoorNotOpen: |
| | 1854 | /* do nothing - well, there's nothing we can do, really*/ |
| | 1855 | FarNpc_FlipAround(sbPtr); |
| | 1856 | break; |
| | 1857 | default: |
| | 1858 | { |
| | 1859 | assert(1==0); |
| | 1860 | } |
| | 1861 | } |
| | 1862 | |
| | 1863 | /* Now, deduce how far it's moved... */ |
| | 1864 | oldPos.vx -= sbPtr->DynPtr->Position.vx; |
| | 1865 | oldPos.vy -= sbPtr->DynPtr->Position.vy; |
| | 1866 | oldPos.vz -= sbPtr->DynPtr->Position.vz; |
| | 1867 | |
| | 1868 | { |
| | 1869 | int distance = Approximate3dMagnitude(&oldPos); |
| | 1870 | /* How long? */ |
| | 1871 | |
| | 1872 | return !distance ? ALIEN_FAR_MOVE_TIME : DIV_FIXED(distance, (ALIEN_FORWARDVELOCITY >> 1)); |
| | 1873 | } |
| | 1874 | } |
| | 1875 | |
| | 1876 | void Alien_Awaken(STRATEGYBLOCK *sbPtr) |
| | 1877 | { |
| | 1878 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1879 | |
| | 1880 | alienStatusPointer->BehaviourState = ABS_Awakening; |
| | 1881 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienStand, ASSS_Unfurl, -1, (ONE_FIXED>>2)); |
| | 1882 | alienStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 1883 | } |
| | 1884 | |
| | 1885 | /*----------------------Patrick 7/11/96----------------------------- |
| | 1886 | AI alien behaviour execution shell: |
| | 1887 | |
| | 1888 | 1. patch to trap aliens who's current module is not set (and set it). |
| | 1889 | 2. call the visibility checking function. |
| | 1890 | 3. select either near or far behaviour functions. |
| | 1891 | |
| | 1892 | NB the visibility checking function initialises near/far behaviour and |
| | 1893 | allocates/deallocates displayblock based on changes in visibility |
| | 1894 | for the alien's module. This will, in due course, be invoked by a |
| | 1895 | call back function from the module handler. |
| | 1896 | --------------------------------------------------------------------*/ |
| | 1897 | |
| | 1898 | int AlienIsAwareOfTarget(STRATEGYBLOCK *sbPtr) |
| | 1899 | { |
| | 1900 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1901 | |
| | 1902 | if (alienStatusPointer->Target != NULL) |
| | 1903 | { |
| | 1904 | assert(alienStatusPointer->Target->containingModule); |
| | 1905 | |
| | 1906 | switch(alienStatusPointer->Target->type) |
| | 1907 | { |
| | 1908 | case I_BehaviourMarinePlayer: |
| | 1909 | case I_BehaviourPredatorPlayer: |
| | 1910 | //return PlayerStatus.Alive; |
| | 1911 | default: |
| | 1912 | return IsModuleVisibleFromModule(sbPtr->containingModule, alienStatusPointer->Target->containingModule); |
| | 1913 | } |
| | 1914 | } |
| | 1915 | |
| | 1916 | return 0; |
| | 1917 | } |
| | 1918 | |
| | 1919 | /* |
| | 1920 | if(alienStatusPointer->Type == Standard) |
| | 1921 | { |
| | 1922 | alienStatusPointer->CurrentLightAtAlien = LightIntensityAtPoint(&sbPtr->DynPtr->Position); |
| | 1923 | |
| | 1924 | printf("alienStatusPointer->BehaviourState %d\n", alienStatusPointer->BehaviourState); |
| | 1925 | |
| | 1926 | switch(alienStatusPointer->BehaviourState) |
| | 1927 | { |
| | 1928 | case ABS_Approach: |
| | 1929 | { |
| | 1930 | if (!alienStatusPointer->CurrentLightAtAlien && alienStatusPointer->IAmCrouched &&
(sbPtr->DynPtr->OrientMat.mat22 < 63000)) |
| | 1931 | { |
| | 1932 | switch(alienStatusPointer->Target->type) |
| | 1933 | { |
| | 1934 | case I_BehaviourAlien: |
| | 1935 | { |
| | 1936 | int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position,
&alienStatusPointer->Target->DynPtr->Position); |
| | 1937 | |
| | 1938 | if(distance_to_target < ALIEN_POUNCE_MAXRANGE) |
| | 1939 | { |
| | 1940 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 1941 | } |
| | 1942 | } |
| | 1943 | break; |
| | 1944 | case I_BehaviourPlacedLight: |
| | 1945 | { |
| | 1946 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 1947 | //alienStatusPointer->Target = NULL; |
| | 1948 | } |
| | 1949 | break; |
| | 1950 | default: |
| | 1951 | { |
| | 1952 | int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position,
&alienStatusPointer->Target->DynPtr->Position); |
| | 1953 | int target_previous_distance = VectorDistance(&alienStatusPointer->Target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position); |
| | 1954 | printf("hunt Distance to Target %d\n", distance_to_target); |
| | 1955 | |
| | 1956 | if(target_previous_distance > distance_to_target) |
| | 1957 | { |
| | 1958 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 1959 | } |
| | 1960 | else |
| | 1961 | { |
| | 1962 | if((distance_to_target - target_previous_distance) > ALIEN_POUNCE_MAXRANGE*2) |
| | 1963 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 1964 | else |
| | 1965 | alienStatusPointer->BehaviourState = ((FastRandom() & 65535) > 20000) ? ABS_Approach : ABS_Wait; |
| | 1966 | } |
| | 1967 | } |
| | 1968 | } |
| | 1969 | } |
| | 1970 | } |
| | 1971 | break; |
| | 1972 | case ABS_Wait: |
| | 1973 | { |
| | 1974 | if(alienStatusPointer->CurrentLightAtAlien) |
| | 1975 | { |
| | 1976 | if(alienStatusPointer->Target) |
| | 1977 | { |
| | 1978 | int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position,
&alienStatusPointer->Target->DynPtr->Position); |
| | 1979 | printf("wait Distance to Target %d\n", distance_to_target); |
| | 1980 | |
| | 1981 | if(distance_to_target < ALIEN_ATTACKDISTANCE_MAX) |
| | 1982 | { |
| | 1983 | alienStatusPointer->BehaviourState = ABS_Attack; |
| | 1984 | } |
| | 1985 | else |
| | 1986 | { |
| | 1987 | if ((FastRandom() & 65535) < 24000) |
| | 1988 | { |
| | 1989 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 1990 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 1991 | } |
| | 1992 | else |
| | 1993 | { |
| | 1994 | alienStatusPointer->BehaviourState = ABS_Retreat; |
| | 1995 | } |
| | 1996 | } |
| | 1997 | } |
| | 1998 | else |
| | 1999 | { |
| | 2000 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2001 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 2002 | } |
| | 2003 | } |
| | 2004 | else |
| | 2005 | { |
| | 2006 | int distance_to_target = VectorDistance(&sbPtr->DynPtr->Position, &alienStatusPointer->Target->DynPtr->Position); |
| | 2007 | printf("Distance to Target %d\n", distance_to_target); |
| | 2008 | |
| | 2009 | if (distance_to_target < ALIEN_POUNCE_MAXRANGE) |
| | 2010 | { |
| | 2011 | if(distance_to_target < ALIEN_ATTACKDISTANCE_MAX) |
| | 2012 | { |
| | 2013 | alienStatusPointer->BehaviourState = ABS_Attack; |
| | 2014 | } |
| | 2015 | else |
| | 2016 | { |
| | 2017 | //if ((FastRandom() & 127) < 80) AlienRandomHiss(sbPtr); |
| | 2018 | } |
| | 2019 | } |
| | 2020 | else |
| | 2021 | { |
| | 2022 | int target_previous_distance = VectorDistance(&alienStatusPointer->Target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position); |
| | 2023 | |
| | 2024 | if(target_previous_distance < distance_to_target) |
| | 2025 | { |
| | 2026 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 2027 | } |
| | 2028 | else |
| | 2029 | { |
| | 2030 | alienStatusPointer->BehaviourState = ((FastRandom() & 65535) < 25000) ? ABS_Approach : ABS_Wait; |
| | 2031 | } |
| | 2032 | } |
| | 2033 | } |
| | 2034 | } |
| | 2035 | break; |
| | 2036 | case ABS_Wander: |
| | 2037 | if (!alienStatusPointer->CurrentLightAtAlien && alienStatusPointer->IAmCrouched &&
(sbPtr->DynPtr->OrientMat.mat22 < 63000)) |
| | 2038 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 2039 | default: |
| | 2040 | break; |
| | 2041 | } |
| | 2042 | } |
| | 2043 | */ |
| | 2044 | |
| | 2045 | static void NearAlienBehaviour(STRATEGYBLOCK *sbPtr) |
| | 2046 | { |
| | 2047 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2048 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 2049 | |
| | 2050 | printf("alienStatusPointer->BehaviourState %d %s\n", alienStatusPointer->BehaviourState, (sbPtr->DisplayBlock ? "near" :
"far")); //jadda |
| | 2051 | |
| | 2052 | if(ABS_Wait != alienStatusPointer->BehaviourState) |
| | 2053 | InitWaypointSystem(alienStatusPointer->EnableWaypoints); |
| | 2054 | |
| | 2055 | if (NULL == alienStatusPointer->current_attack) |
| | 2056 | AlienHandleMovingAnimation(sbPtr); |
| | 2057 | |
| | 2058 | switch (alienStatusPointer->BehaviourState) |
| | 2059 | { |
| | 2060 | case ABS_Approach: |
| | 2061 | { |
| | 2062 | VECTORCH targetPos; |
| | 2063 | int can_see_target; |
| | 2064 | |
| | 2065 | if (NULL == alienStatusPointer->Target) |
| | 2066 | { |
| | 2067 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 2068 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 2069 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2070 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2071 | break; |
| | 2072 | } |
| | 2073 | |
| | 2074 | if(NPCCanSeeTarget(sbPtr, alienStatusPointer->Target)) |
| | 2075 | { |
| | 2076 | puts("can see target"); |
| | 2077 | can_see_target = 1; |
| | 2078 | } |
| | 2079 | else |
| | 2080 | { |
| | 2081 | can_see_target = 0; |
| | 2082 | puts("cannot see target"); |
| | 2083 | |
| | 2084 | if(dynPtr->OrientMat.mat22 < 63000) |
| | 2085 | { |
| | 2086 | puts("i am on wall"); |
| | 2087 | } |
| | 2088 | |
| | 2089 | if(!DynamicObjectIsMoving(dynPtr)) |
| | 2090 | { |
| | 2091 | puts("Target is still"); |
| | 2092 | |
| | 2093 | } |
| | 2094 | |
| | 2095 | switch(alienStatusPointer->Target->type) |
| | 2096 | { |
| | 2097 | case I_BehaviourMarine: |
| | 2098 | case I_BehaviourMarinePlayer: |
| | 2099 | default: |
| | 2100 | break; |
| | 2101 | } |
| | 2102 | |
| | 2103 | STRATEGYBLOCK *new_target = Alien_GetNewTarget(sbPtr); |
| | 2104 | |
| | 2105 | if(0) |
| | 2106 | if((NULL != new_target) && (new_target != alienStatusPointer->Target)) |
| | 2107 | { |
| | 2108 | switch (new_target->type) |
| | 2109 | { |
| | 2110 | case I_BehaviourMarine: |
| | 2111 | case I_BehaviourMarinePlayer: |
| | 2112 | case I_BehaviourFlare: |
| | 2113 | alienStatusPointer->Target = new_target; |
| | 2114 | break; |
| | 2115 | case I_BehaviourPlacedLight: |
| | 2116 | { |
| | 2117 | if(Standard == alienStatusPointer->Type) |
| | 2118 | { |
| | 2119 | if(!new_target->maintainVisibility) |
| | 2120 | { |
| | 2121 | } |
| | 2122 | else |
| | 2123 | { |
| | 2124 | PLACED_LIGHT_BEHAV_BLOCK* pl_bhv = (PLACED_LIGHT_BEHAV_BLOCK*)new_target->dataptr; |
| | 2125 | |
| | 2126 | if(!new_target->maintainVisibility || new_target->DamageBlock.Indestructable) // valid anyway? |
| | 2127 | { |
| | 2128 | } |
| | 2129 | else if((Light_State_Broken != pl_bhv->state) && (Light_OnOff_Off != pl_bhv->on_off_state)) |
| | 2130 | { |
| | 2131 | alienStatusPointer->Target = new_target; |
| | 2132 | puts("NEW ligth_lamp TAGET"); |
| | 2133 | } |
| | 2134 | } |
| | 2135 | } |
| | 2136 | } |
| | 2137 | default: |
| | 2138 | break; |
| | 2139 | } |
| | 2140 | } |
| | 2141 | //else puts("BAD TARGEEEEEEEEEEEE"); |
| | 2142 | } |
| | 2143 | |
| | 2144 | if ((alienStatusPointer->Target->DynPtr->Position.vy - dynPtr->Position.vy) < -2000) |
| | 2145 | { |
| | 2146 | puts("SMAE POS"); |
| | 2147 | //sleep(1); |
| | 2148 | //alienStatusPointer->BehaviourState = ABS_Wait; |
| | 2149 | //return; |
| | 2150 | } |
| | 2151 | //if(0) |
| | 2152 | { // test |
| | 2153 | VECTORCH orientationDirn; |
| | 2154 | int correctlyOrientated = 0; |
| | 2155 | orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 2156 | orientationDirn.vy = 0; |
| | 2157 | orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 2158 | correctlyOrientated = NPCOrientateToVector2(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 2159 | |
| | 2160 | //if (correctlyOrientated) |
| | 2161 | { |
| | 2162 | VECTORCH sight_vec; |
| | 2163 | SECTION_DATA *head_sec = GetThisSectionData(alienStatusPointer->HModelController.section_data, "head"); |
| | 2164 | assert(head_sec); |
| | 2165 | |
| | 2166 | sight_vec.vx = sbPtr->DynPtr->OrientMat.mat31; |
| | 2167 | sight_vec.vy = sbPtr->DynPtr->OrientMat.mat32; |
| | 2168 | sight_vec.vz = sbPtr->DynPtr->OrientMat.mat33; |
| | 2169 | |
| | 2170 | FindPolygonInLineOfSight(&sight_vec, &head_sec->World_Offset, 0, sbPtr->DisplayBlock); |
| | 2171 | |
| | 2172 | if(LOS_ObjectHitPtr) |
| | 2173 | { |
| | 2174 | if((NULL == LOS_ObjectHitPtr->ObStrategyBlock) || (LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock &&
LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock->Module)) |
| | 2175 | { |
| | 2176 | if (LOS_Lambda < 1500) |
| | 2177 | { |
| | 2178 | puts("near is modeule"); |
| | 2179 | |
| | 2180 | if(alienStatusPointer->CanClimb) |
| | 2181 | { |
| | 2182 | alienStatusPointer->IAmCrouched = 1; |
| | 2183 | //if(0) |
| | 2184 | { |
| | 2185 | int approachingAirDuct = 0; |
| | 2186 | NPCGetMovementTarget(sbPtr, alienStatusPointer->Target, &targetPos, &approachingAirDuct, 1); |
| | 2187 | |
| | 2188 | /* use standard NPC direction finding... */ |
| | 2189 | VECTORCH velocityDirection = {0,0,0}; |
| | 2190 | |
| | 2191 | NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPos, (alienStatusPointer->EnableWaypoints ?
&alienStatusPointer->waypointManager : NULL)); |
| | 2192 | |
| | 2193 | NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); |
| | 2194 | alienStatusPointer->CurveTimeOut = 0; /* forces curve init next time curving is used */ |
| | 2195 | return; |
| | 2196 | } |
| | 2197 | } |
| | 2198 | } |
| | 2199 | else |
| | 2200 | { |
| | 2201 | puts("far is modeule"); |
| | 2202 | } |
| | 2203 | } |
| | 2204 | if(NULL != LOS_ObjectHitPtr->ObStrategyBlock) |
| | 2205 | { |
| | 2206 | if(alienStatusPointer->Target == LOS_ObjectHitPtr->ObStrategyBlock) |
| | 2207 | { |
| | 2208 | if (LOS_Lambda < ALIEN_POUNCE_STARTMAXRANGE) |
| | 2209 | ; |
| | 2210 | puts("OH YES"); |
| | 2211 | //sleep(1); |
| | 2212 | } |
| | 2213 | |
| | 2214 | } |
| | 2215 | } |
| | 2216 | } |
| | 2217 | } |
| | 2218 | |
| | 2219 | int distance_to_target = VectorDistance(&dynPtr->Position, &alienStatusPointer->Target->DynPtr->Position); |
| | 2220 | int target_previous_distance = VectorDistance(&alienStatusPointer->Target->DynPtr->PrevPosition, &dynPtr->Position); |
| | 2221 | |
| | 2222 | //dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr); |
| | 2223 | |
| | 2224 | /* target acquisition ? */ |
| | 2225 | /* Never curve in a waypoint module, you might hurt yourself. */ |
| | 2226 | if((distance_to_target < ALIEN_CURVETOPLAYERDIST) && (NULL == sbPtr->containingModule->m_aimodule->m_waypoints)) |
| | 2227 | { |
| | 2228 | GetTargetingPointOfObject_Far(alienStatusPointer->Target, &targetPos); |
| | 2229 | |
| | 2230 | //printf("curving alien \n"); |
| | 2231 | /* translate target into alien's local space */ |
| | 2232 | |
| | 2233 | { |
| | 2234 | MATRIXCH toLocalSpaceMatrix = dynPtr->OrientMat; |
| | 2235 | TransposeMatrixCH(&toLocalSpaceMatrix); |
| | 2236 | |
| | 2237 | targetPos.vx -= dynPtr->Position.vx; |
| | 2238 | targetPos.vy -= dynPtr->Position.vy; |
| | 2239 | targetPos.vz -= dynPtr->Position.vz; |
| | 2240 | RotateVector(&targetPos, &toLocalSpaceMatrix); |
| | 2241 | } |
| | 2242 | |
| | 2243 | /* tracking movement */ |
| | 2244 | int distanceToTarget = Magnitude(&targetPos); |
| | 2245 | |
| | 2246 | if (dynPtr->IsInContactWithFloor) |
| | 2247 | { |
| | 2248 | int offset; |
| | 2249 | |
| | 2250 | if (alienStatusPointer->CurveTimeOut <= 0) |
| | 2251 | { |
| | 2252 | alienStatusPointer->CurveLength = distanceToTarget; |
| | 2253 | alienStatusPointer->CurveRadius = ((FastRandom() & 16383) - 8192) * 2; |
| | 2254 | alienStatusPointer->CurveTimeOut= ONE_FIXED * 3; |
| | 2255 | } |
| | 2256 | else |
| | 2257 | alienStatusPointer->CurveTimeOut -= NormalFrameTime; |
| | 2258 | |
| | 2259 | offset = MUL_FIXED(alienStatusPointer->CurveRadius, GetCos((1024*(distanceToTarget)/alienStatusPointer->CurveLength)&4095)); |
| | 2260 | |
| | 2261 | dynPtr->LinVelocity.vx = |
| | 2262 | WideMulNarrowDiv(alienStatusPointer->MaxSpeed, targetPos.vx, distanceToTarget) |
| | 2263 | - |
| | 2264 | WideMulNarrowDiv(offset, targetPos.vz, distanceToTarget); |
| | 2265 | |
| | 2266 | dynPtr->LinVelocity.vz = |
| | 2267 | WideMulNarrowDiv ( alienStatusPointer->MaxSpeed, targetPos.vz, distanceToTarget) |
| | 2268 | + |
| | 2269 | WideMulNarrowDiv ( offset, targetPos.vx, distanceToTarget); |
| | 2270 | |
| | 2271 | if (!dynPtr->UseStandardGravity && (sbPtr->containingModule == PlayerStatus.sbptr->containingModule)) |
| | 2272 | { |
| | 2273 | //VECTORCH velocityDirection=dynPtr->LinVelocity; |
| | 2274 | VECTORCH velocityDirection; |
| | 2275 | GetTargetingPointOfObject_Far(alienStatusPointer->Target, &velocityDirection); |
| | 2276 | velocityDirection.vx -= dynPtr->Position.vx; |
| | 2277 | velocityDirection.vy -= dynPtr->Position.vy; |
| | 2278 | velocityDirection.vz -= dynPtr->Position.vz; |
| | 2279 | |
| | 2280 | Normalise(&velocityDirection); |
| | 2281 | int dot = DotProduct(&dynPtr->GravityDirection, &velocityDirection); |
| | 2282 | |
| | 2283 | if (dot < -60000) |
| | 2284 | { |
| | 2285 | /* patrick 29/7/97: I have added the extra condition of not being in the same module as |
| | 2286 | the player, so that alien does not jump at entry-points */ |
| | 2287 | dynPtr->TimeNotInContactWithFloor = 0; |
| | 2288 | dynPtr->UseStandardGravity = 1; |
| | 2289 | dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx, ALIEN_JUMPVELOCITY); |
| | 2290 | dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy, ALIEN_JUMPVELOCITY); |
| | 2291 | dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz, ALIEN_JUMPVELOCITY); |
| | 2292 | } |
| | 2293 | } |
| | 2294 | |
| | 2295 | RotateVector(&dynPtr->LinVelocity, &dynPtr->OrientMat); |
| | 2296 | |
| | 2297 | /* align to velocity */ |
| | 2298 | NPCOrientateToVector(sbPtr, &dynPtr->LinVelocity, NPC_TURNRATE); |
| | 2299 | } |
| | 2300 | } |
| | 2301 | else |
| | 2302 | { |
| | 2303 | int approachingAirDuct = 0; |
| | 2304 | NPCGetMovementTarget(sbPtr, alienStatusPointer->Target, &targetPos, &approachingAirDuct, 1); |
| | 2305 | |
| | 2306 | /* use standard NPC direction finding... */ |
| | 2307 | VECTORCH velocityDirection = {0,0,0}; |
| | 2308 | |
| | 2309 | NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPos, (alienStatusPointer->EnableWaypoints ?
&alienStatusPointer->waypointManager : NULL)); |
| | 2310 | |
| | 2311 | NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); |
| | 2312 | alienStatusPointer->CurveTimeOut = 0; /* forces curve init next time curving is used */ |
| | 2313 | |
| | 2314 | /* Consider ripping off the wall. */ |
| | 2315 | if (!dynPtr->UseStandardGravity && (distance_to_target < ALIEN_POUNCE_MAXRANGE)) |
| | 2316 | { |
| | 2317 | if (DotProduct(&dynPtr->GravityDirection, &velocityDirection) < -60000) |
| | 2318 | { |
| | 2319 | dynPtr->TimeNotInContactWithFloor = 0; |
| | 2320 | dynPtr->UseStandardGravity = 1; |
| | 2321 | dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->GravityDirection.vx, ALIEN_JUMPVELOCITY); |
| | 2322 | dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->GravityDirection.vy, ALIEN_JUMPVELOCITY); |
| | 2323 | dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->GravityDirection.vz, ALIEN_JUMPVELOCITY); |
| | 2324 | return; |
| | 2325 | } |
| | 2326 | } |
| | 2327 | } |
| | 2328 | |
| | 2329 | /* Hang on, should we be doing this? */ |
| | 2330 | if (!sbPtr->DamageBlock.IsOnFire) |
| | 2331 | { |
| | 2332 | if ((distance_to_target < 30000) && (dynPtr->OrientMat.mat22 >= 63000) && dynPtr->IsInContactWithFloor) |
| | 2333 | { |
| | 2334 | /* 150% flamethrower 'range'. */ |
| | 2335 | if(TargetIsFiringFlamethrowerAtAlien(sbPtr, distance_to_target)) |
| | 2336 | return; |
| | 2337 | } |
| | 2338 | } |
| | 2339 | |
| | 2340 | /* should we change back to attack, maybe? */ |
| | 2341 | if(can_see_target &&(distance_to_target < ALIEN_POUNCE_STARTMAXRANGE)) |
| | 2342 | { |
| | 2343 | if (distance_to_target > ALIEN_POUNCE_MINRANGE) |
| | 2344 | { |
| | 2345 | int EnablePounce = 0; |
| | 2346 | |
| | 2347 | if(alienStatusPointer->incidentFlag) |
| | 2348 | switch(alienStatusPointer->Type) |
| | 2349 | { |
| | 2350 | case Standard: |
| | 2351 | default: |
| | 2352 | EnablePounce = ((FastRandom() % 65535) < 16384); |
| | 2353 | break; |
| | 2354 | case Predalien: |
| | 2355 | EnablePounce = ((FastRandom() % 65535) > 16384); |
| | 2356 | break; |
| | 2357 | case Praetorian: |
| | 2358 | EnablePounce = (alienStatusPointer->PreferToCrouch) ? 1 : ((FastRandom() % 65535) > 16384); |
| | 2359 | } |
| | 2360 | |
| | 2361 | /* Might want to pounce. */ |
| | 2362 | if ((EnablePounce || Alien_Special_Pounce_Condition(sbPtr)) && StartAlienPounce(sbPtr)) |
| | 2363 | { |
| | 2364 | return; // Success. |
| | 2365 | } |
| | 2366 | } |
| | 2367 | else if (distance_to_target < ALIEN_ATTACKDISTANCE_MIN) |
| | 2368 | { |
| | 2369 | alienStatusPointer->BehaviourState = ABS_Attack; |
| | 2370 | return; |
| | 2371 | } |
| | 2372 | } |
| | 2373 | else if (alienStatusPointer->incidentFlag) |
| | 2374 | { |
| | 2375 | switch (alienStatusPointer->Type) |
| | 2376 | { |
| | 2377 | case Standard: |
| | 2378 | default: |
| | 2379 | if (((FastRandom() & 65535) < ALIEN_JUMPINESS) && GoToJump(sbPtr)) // jadda |
| | 2380 | return; // Boop! |
| | 2381 | break; |
| | 2382 | case Predalien: |
| | 2383 | if (((FastRandom() & 65535) < PREDALIEN_JUMPINESS) && GoToJump(sbPtr)) |
| | 2384 | return; // Boop! |
| | 2385 | break; |
| | 2386 | case Praetorian: |
| | 2387 | if (((FastRandom() & 65535) < PRAETORIAN_JUMPINESS) && GoToJump(sbPtr)) |
| | 2388 | return; // Boop! |
| | 2389 | } |
| | 2390 | } |
| | 2391 | |
| | 2392 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 2393 | { |
| | 2394 | STRATEGYBLOCK *destructableObject = NULL; |
| | 2395 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 2396 | |
| | 2397 | NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction, &destructableObject); |
| | 2398 | |
| | 2399 | if(0) |
| | 2400 | if(Standard == alienStatusPointer->Type) |
| | 2401 | alienStatusPointer->EnableWaypoints = 1; |
| | 2402 | //if(0) |
| | 2403 | if(obstruction.environment) |
| | 2404 | { |
| | 2405 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2406 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 2407 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2408 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 2409 | printf("gravite %d\n", dynPtr->UseStandardGravity); |
| | 2410 | sleep(1); |
| | 2411 | return; |
| | 2412 | } |
| | 2413 | else if(obstruction.destructableObject) |
| | 2414 | { |
| | 2415 | assert(destructableObject); |
| | 2416 | CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL); |
| | 2417 | } |
| | 2418 | else if (obstruction.anySingleObstruction && !obstruction.otherCharacter) |
| | 2419 | { |
| | 2420 | /* Try for a nearer target? */ |
| | 2421 | //alienStatusPointer->Target = NULL; |
| | 2422 | puts("bstruction.anySingleObstruction && !obstruction.otherChar"); |
| | 2423 | sleep(1); |
| | 2424 | } |
| | 2425 | } |
| | 2426 | |
| | 2427 | { |
| | 2428 | VECTORCH velocityDirection = dynPtr->LinVelocity; |
| | 2429 | Normalise(&velocityDirection); |
| | 2430 | |
| | 2431 | //if(0) |
| | 2432 | if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &targetPos, &velocityDirection)) |
| | 2433 | { |
| | 2434 | NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0}; |
| | 2435 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2436 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 2437 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2438 | alienStatusPointer->StateTimer = NPC_AVOIDTIME * 2; |
| | 2439 | puts("NPC_CannotReachTarg"); |
| | 2440 | sleep(1); |
| | 2441 | } |
| | 2442 | } |
| | 2443 | } |
| | 2444 | break; |
| | 2445 | case ABS_Attack: |
| | 2446 | { |
| | 2447 | //dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr); |
| | 2448 | |
| | 2449 | /* patrick 13/6/97: a little addition: Orientate towards player, just to make sure we're facing */ |
| | 2450 | if (dynPtr->UseStandardGravity) |
| | 2451 | { |
| | 2452 | if(alienStatusPointer->CanStand) |
| | 2453 | alienStatusPointer->IAmCrouched = 0; |
| | 2454 | |
| | 2455 | VECTORCH orientationDirn; |
| | 2456 | orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 2457 | orientationDirn.vy = 0; |
| | 2458 | orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 2459 | int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 2460 | } |
| | 2461 | else |
| | 2462 | { |
| | 2463 | /* Replace this! */ |
| | 2464 | VECTORCH orientationDirn; |
| | 2465 | orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 2466 | orientationDirn.vy = alienStatusPointer->Target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy; |
| | 2467 | orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 2468 | |
| | 2469 | int dot = -DotProduct(&dynPtr->GravityDirection, &orientationDirn); |
| | 2470 | /* Hold that thought. */ |
| | 2471 | orientationDirn.vx -= MUL_FIXED(dot, dynPtr->GravityDirection.vx); |
| | 2472 | orientationDirn.vy -= MUL_FIXED(dot, dynPtr->GravityDirection.vy); |
| | 2473 | orientationDirn.vz -= MUL_FIXED(dot, dynPtr->GravityDirection.vz); |
| | 2474 | |
| | 2475 | int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 2476 | } |
| | 2477 | |
| | 2478 | int distance_to_target = VectorDistance(&dynPtr->Position, &alienStatusPointer->Target->DynPtr->Position); |
| | 2479 | |
| | 2480 | if(distance_to_target > ALIEN_ATTACKDISTANCE_MAX) |
| | 2481 | { |
| | 2482 | alienStatusPointer->current_attack = NULL; |
| | 2483 | |
| | 2484 | if(alienStatusPointer->Wounds && ((FastRandom() & 127) < 10)) |
| | 2485 | { |
| | 2486 | StartAlienTaunt(sbPtr); |
| | 2487 | } |
| | 2488 | else if((Standard == alienStatusPointer->Type) && dynPtr->UseStandardGravity && alienStatusPointer->CanStand) |
| | 2489 | { |
| | 2490 | //if(DynamicObjectIsMoving(alienStatusPointer->Target->DynPtr)) |
| | 2491 | { |
| | 2492 | //if ((HMSQT_AlienRun != alienStatusPointer->HModelController.Sequence_Type) && (ARSS_Attack_Swipe !=
alienStatusPointer->HModelController.Sub_Sequence)) |
| | 2493 | extern ATTACK_DATA Alien_Attacks[]; |
| | 2494 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienRun, ARSS_Attack_Swipe, ONE_FIXED >> 1, (ONE_FIXED >> 3)); |
| | 2495 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2496 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2497 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2498 | alienStatusPointer->StateTimer = 0; |
| | 2499 | alienStatusPointer->CurveTimeOut = 0; |
| | 2500 | alienStatusPointer->current_attack = &Alien_Attacks[12]; // does not matter unless it's NULL |
| | 2501 | } |
| | 2502 | } |
| | 2503 | else |
| | 2504 | { |
| | 2505 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2506 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2507 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2508 | alienStatusPointer->StateTimer = 0; |
| | 2509 | alienStatusPointer->CurveTimeOut = 0; |
| | 2510 | alienStatusPointer->current_attack = NULL; |
| | 2511 | } |
| | 2512 | } |
| | 2513 | else if (NULL == alienStatusPointer->current_attack) |
| | 2514 | { |
| | 2515 | StartAlienAttackSequence(sbPtr); |
| | 2516 | } |
| | 2517 | else |
| | 2518 | { |
| | 2519 | /* alien can inflict nastiness on the target */ |
| | 2520 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 2521 | AlienNearDamageShell(sbPtr); |
| | 2522 | |
| | 2523 | if (alienStatusPointer->HModelController.keyframe_flags & 1) |
| | 2524 | alienStatusPointer->current_attack = NULL; |
| | 2525 | |
| | 2526 | if ((FastRandom() & 127) < 20) |
| | 2527 | AlienRandomHiss(sbPtr); |
| | 2528 | } |
| | 2529 | } |
| | 2530 | break; |
| | 2531 | case ABS_Pounce: |
| | 2532 | { |
| | 2533 | /* Firstly, are we actually pouncing yet? */ |
| | 2534 | /* StateTimer is a status flag. */ |
| | 2535 | |
| | 2536 | if (!alienStatusPointer->StateTimer) |
| | 2537 | { |
| | 2538 | /* Still tweening? */ |
| | 2539 | if (alienStatusPointer->HModelController.Tweening == Controller_NoTweening) |
| | 2540 | { |
| | 2541 | /* We've finished! Are we facing right? */ |
| | 2542 | VECTORCH orientationDirn; |
| | 2543 | |
| | 2544 | orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 2545 | orientationDirn.vy = 0; |
| | 2546 | orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 2547 | |
| | 2548 | if (NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE)) |
| | 2549 | { |
| | 2550 | /* Okay, pounce! */ |
| | 2551 | |
| | 2552 | ApplyPounceImpulse(sbPtr); |
| | 2553 | |
| | 2554 | alienStatusPointer->HModelController.Playing = 1; |
| | 2555 | alienStatusPointer->StateTimer = 1; |
| | 2556 | } |
| | 2557 | else |
| | 2558 | { |
| | 2559 | /* Still not right! Wait for proper facing. */ |
| | 2560 | alienStatusPointer->HModelController.Playing = 0; |
| | 2561 | CheckPounceIntegrity(sbPtr); |
| | 2562 | } |
| | 2563 | } |
| | 2564 | else |
| | 2565 | { |
| | 2566 | /* Yup, still tweening. Check state validity. */ |
| | 2567 | CheckPounceIntegrity(sbPtr); |
| | 2568 | } |
| | 2569 | } |
| | 2570 | else |
| | 2571 | { |
| | 2572 | struct collisionreport *CollisionReportPtr = dynPtr->CollisionReportPtr; |
| | 2573 | |
| | 2574 | if(CollisionReportPtr) |
| | 2575 | { |
| | 2576 | do |
| | 2577 | { |
| | 2578 | if(CollisionReportPtr->ObstacleSBPtr) |
| | 2579 | { |
| | 2580 | STRATEGYBLOCK* hit_sbptr = CollisionReportPtr->ObstacleSBPtr; |
| | 2581 | |
| | 2582 | switch(hit_sbptr->type) |
| | 2583 | { |
| | 2584 | case I_BehaviourMarine: |
| | 2585 | case I_BehaviourMarinePlayer: |
| | 2586 | case I_BehaviourPredatorPlayer: |
| | 2587 | case I_BehaviourPredator: |
| | 2588 | case I_BehaviourPlacedLight: |
| | 2589 | CauseDamageToObject(hit_sbptr, &damage_profiles[FALLINGDAMAGE], (100*NormalFrameTime), NULL); |
| | 2590 | default: |
| | 2591 | break; |
| | 2592 | } |
| | 2593 | } |
| | 2594 | |
| | 2595 | CollisionReportPtr = CollisionReportPtr->NextCollisionReportPtr; |
| | 2596 | |
| | 2597 | } while(CollisionReportPtr); |
| | 2598 | |
| | 2599 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2600 | alienStatusPointer->BehaviourState = ABS_Attack; |
| | 2601 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2602 | alienStatusPointer->StateTimer = 0; |
| | 2603 | alienStatusPointer->CurveTimeOut = 0; |
| | 2604 | alienStatusPointer->current_attack = NULL; |
| | 2605 | } |
| | 2606 | } |
| | 2607 | } |
| | 2608 | break; |
| | 2609 | case ABS_Jump: |
| | 2610 | { |
| | 2611 | int terminateState = 0; |
| | 2612 | struct collisionreport *CollisionReportPtr = dynPtr->CollisionReportPtr; |
| | 2613 | |
| | 2614 | /* Pretty simple one, this. Just fly through the air, until you hit something. */ |
| | 2615 | |
| | 2616 | if (dynPtr->IsInContactWithFloor || dynPtr->IsInContactWithNearlyFlatFloor) |
| | 2617 | terminateState = 1; |
| | 2618 | |
| | 2619 | if(CollisionReportPtr) |
| | 2620 | { |
| | 2621 | do |
| | 2622 | { |
| | 2623 | if(CollisionReportPtr->ObstacleSBPtr) |
| | 2624 | { |
| | 2625 | STRATEGYBLOCK* hit_sbptr = CollisionReportPtr->ObstacleSBPtr; |
| | 2626 | |
| | 2627 | switch(hit_sbptr->type) |
| | 2628 | { |
| | 2629 | case I_BehaviourMarine: |
| | 2630 | case I_BehaviourMarinePlayer: |
| | 2631 | case I_BehaviourPredatorPlayer: |
| | 2632 | case I_BehaviourPredator: |
| | 2633 | case I_BehaviourPlacedLight: |
| | 2634 | CauseDamageToObject(hit_sbptr, &damage_profiles[FALLINGDAMAGE], (100*NormalFrameTime), NULL); |
| | 2635 | default: |
| | 2636 | break; |
| | 2637 | } |
| | 2638 | } |
| | 2639 | |
| | 2640 | CollisionReportPtr = CollisionReportPtr->NextCollisionReportPtr; |
| | 2641 | |
| | 2642 | } while(CollisionReportPtr); |
| | 2643 | |
| | 2644 | terminateState = 1; |
| | 2645 | } |
| | 2646 | |
| | 2647 | if (terminateState) |
| | 2648 | { |
| | 2649 | /* should be crawling. */ |
| | 2650 | alienStatusPointer->IAmCrouched = 1; |
| | 2651 | //AlienHandleMovingAnimation(sbPtr); |
| | 2652 | |
| | 2653 | //dynPtr->UseStandardGravity = !(alienStatusPointer->CanClimb && (dynPtr->OrientMat.mat22 < 63000)); |
| | 2654 | //dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr); |
| | 2655 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2656 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2657 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2658 | alienStatusPointer->StateTimer = 0; |
| | 2659 | alienStatusPointer->CurveTimeOut = 0; |
| | 2660 | alienStatusPointer->current_attack = NULL; |
| | 2661 | } |
| | 2662 | } |
| | 2663 | break; |
| | 2664 | case ABS_Avoidance: |
| | 2665 | { |
| | 2666 | int terminateState = 0; |
| | 2667 | //dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr); |
| | 2668 | |
| | 2669 | #if ALL_NEW_AVOIDANCE_ALIEN |
| | 2670 | |
| | 2671 | NPCSetVelocity(sbPtr, &alienStatusPointer->avoidanceManager.avoidanceDirection, alienStatusPointer->MaxSpeed); |
| | 2672 | /* Velocity CANNOT be zero, unless deliberately so! */ |
| | 2673 | { |
| | 2674 | if (AllNewAvoidanceKernel(sbPtr,&alienStatusPointer->avoidanceManager) != AvRC_Avoidance) |
| | 2675 | terminateState = 1; |
| | 2676 | } |
| | 2677 | #else |
| | 2678 | /* set velocity */ |
| | 2679 | assert((alienStatusPointer->moveData.avoidanceDirn.vx!=0)|| |
| | 2680 | (alienStatusPointer->moveData.avoidanceDirn.vy!=0)|| |
| | 2681 | (alienStatusPointer->moveData.avoidanceDirn.vz!=0)); |
| | 2682 | |
| | 2683 | NPCSetVelocity(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, alienStatusPointer->MaxSpeed); |
| | 2684 | |
| | 2685 | /* next, decrement state timer */ |
| | 2686 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 2687 | |
| | 2688 | if(alienStatusPointer->StateTimer <= 0) |
| | 2689 | terminateState = 1; |
| | 2690 | |
| | 2691 | /* and check for an impeding collision */ |
| | 2692 | { |
| | 2693 | STRATEGYBLOCK *destructableObject; |
| | 2694 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 2695 | NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction, &destructableObject); |
| | 2696 | |
| | 2697 | if(obstruction.anySingleObstruction) |
| | 2698 | terminateState = 1; // return to approach |
| | 2699 | } |
| | 2700 | #endif |
| | 2701 | |
| | 2702 | if(terminateState) |
| | 2703 | { |
| | 2704 | if(AlienHasPathToTarget(sbPtr)) |
| | 2705 | { |
| | 2706 | /* switch to approach */ |
| | 2707 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2708 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2709 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2710 | alienStatusPointer->StateTimer = 0; |
| | 2711 | |
| | 2712 | /* no sequence change required */ |
| | 2713 | } |
| | 2714 | else if (AlienIsAwareOfTarget(sbPtr)) |
| | 2715 | { |
| | 2716 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 2717 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2718 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 2719 | } |
| | 2720 | else |
| | 2721 | { |
| | 2722 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2723 | NPC_InitWanderData(&alienStatusPointer->wanderData); |
| | 2724 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 2725 | alienStatusPointer->StateTimer = 0; |
| | 2726 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2727 | /* no sequence change required */ |
| | 2728 | } |
| | 2729 | } |
| | 2730 | } |
| | 2731 | break; |
| | 2732 | case ABS_Hunt: |
| | 2733 | { |
| | 2734 | VECTORCH velocityDirection = {0,0,0}; |
| | 2735 | alienStatusPointer->IAmCrouched = 1; |
| | 2736 | //dynPtr->UseStandardGravity = !alienStatusPointer->CanClimb; |
| | 2737 | |
| | 2738 | /* should we change to approach state? */ |
| | 2739 | |
| | 2740 | if(AlienHasPathToTarget(sbPtr)) |
| | 2741 | { |
| | 2742 | /* doesn't require a sequence change */ |
| | 2743 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2744 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2745 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2746 | alienStatusPointer->CurveTimeOut = 0; |
| | 2747 | |
| | 2748 | /* Bloodthirsty, these aliens... */ |
| | 2749 | break; |
| | 2750 | } |
| | 2751 | |
| | 2752 | /* Hunting target aquisition. */ |
| | 2753 | //if (sbPtr->containingModule != alienStatusPointer->my_containing_module) alienStatusPointer->huntingModule = NULL; |
| | 2754 | |
| | 2755 | /* Check again. */ |
| | 2756 | if (alienStatusPointer->huntingModule != NULL) |
| | 2757 | { |
| | 2758 | FARENTRYPOINT *thisEp = GetAIModuleEP(alienStatusPointer->huntingModule,sbPtr->containingModule->m_aimodule); |
| | 2759 | |
| | 2760 | if (!thisEp) |
| | 2761 | alienStatusPointer->huntingModule = NULL; |
| | 2762 | } |
| | 2763 | |
| | 2764 | if (alienStatusPointer->huntingModule == NULL) |
| | 2765 | { |
| | 2766 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForGlobalHunt(sbPtr); |
| | 2767 | |
| | 2768 | if (targetModule == NULL) |
| | 2769 | { |
| | 2770 | /* Better have a handler for this. */ |
| | 2771 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 2772 | alienStatusPointer->CurveTimeOut = 0; |
| | 2773 | //printf("Target module is NULL!\n"); |
| | 2774 | break; |
| | 2775 | } |
| | 2776 | |
| | 2777 | //printf("Target module is %s\n", targetModule->name); |
| | 2778 | //printf("Target AI module for hunt found, %x.\n", (int)targetModule); |
| | 2779 | |
| | 2780 | if (targetModule == sbPtr->containingModule->m_aimodule) |
| | 2781 | { |
| | 2782 | /* We should have arrived - get a new target? */ |
| | 2783 | if (alienStatusPointer->Target == NULL) |
| | 2784 | { |
| | 2785 | /* Oops - nobody about. */ |
| | 2786 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2787 | NPC_InitWanderData(&alienStatusPointer->wanderData); |
| | 2788 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 2789 | alienStatusPointer->CurveTimeOut = 0; |
| | 2790 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2791 | } |
| | 2792 | else |
| | 2793 | { |
| | 2794 | alienStatusPointer->Target = NULL; |
| | 2795 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 2796 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2797 | alienStatusPointer->CurveTimeOut = 0; |
| | 2798 | } |
| | 2799 | return; |
| | 2800 | } |
| | 2801 | |
| | 2802 | alienStatusPointer->huntingModule = targetModule; |
| | 2803 | } |
| | 2804 | |
| | 2805 | { |
| | 2806 | FARENTRYPOINT *thisEp = GetAIModuleEP(alienStatusPointer->huntingModule,sbPtr->containingModule->m_aimodule); |
| | 2807 | |
| | 2808 | if (!thisEp) |
| | 2809 | { |
| | 2810 | printf("This assert is a busted adjacency!\nNo EP between %s and
%s.",(*(alienStatusPointer->huntingModule->m_module_ptrs))->name,sbPtr->containingModule->name); |
| | 2811 | //printf("This assert is a busted adjacency!"); |
| | 2812 | assert(thisEp); |
| | 2813 | } |
| | 2814 | /* If that fired, there's a farped adjacency. */ |
| | 2815 | |
| | 2816 | alienStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 2817 | alienStatusPointer->wanderData.worldPosition.vx += alienStatusPointer->huntingModule->m_world.vx; |
| | 2818 | alienStatusPointer->wanderData.worldPosition.vy += alienStatusPointer->huntingModule->m_world.vy; |
| | 2819 | alienStatusPointer->wanderData.worldPosition.vz += alienStatusPointer->huntingModule->m_world.vz; |
| | 2820 | } |
| | 2821 | |
| | 2822 | /* ok: should have a current target at this stage... */ |
| | 2823 | NPCGetMovementDirection(sbPtr, &velocityDirection,
&alienStatusPointer->wanderData.worldPosition,&alienStatusPointer->waypointManager); |
| | 2824 | NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); |
| | 2825 | |
| | 2826 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 2827 | #if ALL_NEW_AVOIDANCE_ALIEN |
| | 2828 | { |
| | 2829 | if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) |
| | 2830 | { |
| | 2831 | /* Go to all new avoidance. */ |
| | 2832 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2833 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 2834 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2835 | break; |
| | 2836 | } |
| | 2837 | } |
| | 2838 | #else |
| | 2839 | { |
| | 2840 | STRATEGYBLOCK *destructableObject = NULL; |
| | 2841 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 2842 | NPC_IsObstructed(sbPtr,&alienStatusPointer->moveData,&obstruction,&destructableObject); |
| | 2843 | |
| | 2844 | if(obstruction.environment || obstruction.otherCharacter) |
| | 2845 | { |
| | 2846 | /* go to avoidance */ |
| | 2847 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2848 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 2849 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2850 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 2851 | /* no sequence change required */ |
| | 2852 | break; |
| | 2853 | } |
| | 2854 | |
| | 2855 | if(obstruction.destructableObject) |
| | 2856 | { |
| | 2857 | assert(destructableObject); |
| | 2858 | CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL); |
| | 2859 | } |
| | 2860 | } |
| | 2861 | |
| | 2862 | if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &alienStatusPointer->wanderData.worldPosition, &velocityDirection)) |
| | 2863 | { |
| | 2864 | /* go to avoidance */ |
| | 2865 | NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0}; |
| | 2866 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2867 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 2868 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2869 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 2870 | /* no sequence change required */ |
| | 2871 | } |
| | 2872 | #endif |
| | 2873 | } |
| | 2874 | break; |
| | 2875 | case ABS_Wait: |
| | 2876 | { |
| | 2877 | if (!alienStatusPointer->IAmCrouched) |
| | 2878 | { |
| | 2879 | alienStatusPointer->IAmCrouched = 1; |
| | 2880 | alienStatusPointer->StateTimer = ONE_FIXED * 2; |
| | 2881 | } |
| | 2882 | else if(!alienStatusPointer->Wounds) |
| | 2883 | { |
| | 2884 | if(alienStatusPointer->HModelController.Playing) |
| | 2885 | { |
| | 2886 | if(alienStatusPointer->HModelController.Tweening == Controller_NoTweening) |
| | 2887 | sbPtr->DisplayBlock->HModelControlBlock->Playing = 0; |
| | 2888 | |
| | 2889 | //if(alienStatusPointer->StateTimer < 0) |
| | 2890 | sbPtr->DisplayBlock->HModelControlBlock->Playing = 0; |
| | 2891 | { |
| | 2892 | alienStatusPointer->HModelController.Playing = 0;; |
| | 2893 | puts("not player ANIM"); |
| | 2894 | //alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME * 40; |
| | 2895 | } |
| | 2896 | } |
| | 2897 | } |
| | 2898 | /* |
| | 2899 | if(AlienHasPathToTarget(sbPtr)) |
| | 2900 | { |
| | 2901 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2902 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2903 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2904 | |
| | 2905 | alienStatusPointer->CurveTimeOut = 0; |
| | 2906 | alienStatusPointer->StateTimer = 0; |
| | 2907 | |
| | 2908 | return; |
| | 2909 | } |
| | 2910 | else if (AlienIsAwareOfTarget(sbPtr)) |
| | 2911 | { |
| | 2912 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 2913 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 2914 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2915 | } |
| | 2916 | */ |
| | 2917 | /* still waiting: decrement timer */ |
| | 2918 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 2919 | |
| | 2920 | if(alienStatusPointer->StateTimer <= 0) |
| | 2921 | { |
| | 2922 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2923 | NPC_InitWanderData(&alienStatusPointer->wanderData); |
| | 2924 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 2925 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2926 | alienStatusPointer->StateTimer = 0; |
| | 2927 | } |
| | 2928 | } |
| | 2929 | break; |
| | 2930 | case ABS_Wander: |
| | 2931 | { |
| | 2932 | VECTORCH velocityDirection = {0,0,0}; |
| | 2933 | |
| | 2934 | /* Do something else? */ |
| | 2935 | |
| | 2936 | /* should we change to approach state? */ |
| | 2937 | if(AlienHasPathToTarget(sbPtr)) |
| | 2938 | { |
| | 2939 | /* doesn't require a sequence change */ |
| | 2940 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2941 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 2942 | alienStatusPointer->CurveTimeOut = 0; |
| | 2943 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2944 | break; |
| | 2945 | } |
| | 2946 | else if (AlienIsAwareOfTarget(sbPtr)) |
| | 2947 | { |
| | 2948 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 2949 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 2950 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2951 | } |
| | 2952 | |
| | 2953 | /* Try to reaquire target? */ |
| | 2954 | alienStatusPointer->Target = NULL; |
| | 2955 | |
| | 2956 | if(alienStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2957 | { |
| | 2958 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 2959 | NPC_FindAIWanderTarget(sbPtr,&alienStatusPointer->wanderData, &alienStatusPointer->moveData, 1); |
| | 2960 | } |
| | 2961 | else if(alienStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index) |
| | 2962 | { |
| | 2963 | NPC_FindAIWanderTarget(sbPtr, &alienStatusPointer->wanderData, &alienStatusPointer->moveData, 1); |
| | 2964 | } |
| | 2965 | |
| | 2966 | /* if we still haven't got one, go to wait */ |
| | 2967 | if(alienStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2968 | { |
| | 2969 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 2970 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 2971 | } |
| | 2972 | |
| | 2973 | /* ok: should have a current target at this stage... */ |
| | 2974 | NPCGetMovementDirection(sbPtr, &velocityDirection, &alienStatusPointer->wanderData.worldPosition,
&alienStatusPointer->waypointManager); |
| | 2975 | NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); |
| | 2976 | |
| | 2977 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 2978 | |
| | 2979 | #if ALL_NEW_AVOIDANCE_ALIEN |
| | 2980 | { |
| | 2981 | if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) |
| | 2982 | { |
| | 2983 | /* Go to all new avoidance. */ |
| | 2984 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 2985 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 2986 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 2987 | break; |
| | 2988 | } |
| | 2989 | } |
| | 2990 | #else |
| | 2991 | { |
| | 2992 | STRATEGYBLOCK *destructableObject = NULL; |
| | 2993 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 2994 | NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction,&destructableObject); |
| | 2995 | |
| | 2996 | if(obstruction.environment || obstruction.otherCharacter) |
| | 2997 | { |
| | 2998 | /* go to avoidance */ |
| | 2999 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3000 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 3001 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 3002 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 3003 | /* no sequence change required */ |
| | 3004 | break; |
| | 3005 | } |
| | 3006 | |
| | 3007 | if(obstruction.destructableObject) |
| | 3008 | { |
| | 3009 | assert(destructableObject); |
| | 3010 | CauseDamageToObject(destructableObject, &TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED, NULL); |
| | 3011 | } |
| | 3012 | } |
| | 3013 | |
| | 3014 | if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &alienStatusPointer->wanderData.worldPosition, &velocityDirection)) |
| | 3015 | { |
| | 3016 | /* go to avoidance */ |
| | 3017 | NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0}; |
| | 3018 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3019 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 3020 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 3021 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 3022 | /* no sequence change required */ |
| | 3023 | } |
| | 3024 | #endif |
| | 3025 | } |
| | 3026 | break; |
| | 3027 | case ABS_Retreat: |
| | 3028 | { |
| | 3029 | VECTORCH velocityDirection = {0,0,0}; |
| | 3030 | |
| | 3031 | /* should we change to approach state? */ |
| | 3032 | if(AlienIsAwareOfTarget(sbPtr)) |
| | 3033 | { |
| | 3034 | // doesn't require a sequence change |
| | 3035 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3036 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 3037 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3038 | alienStatusPointer->CurveTimeOut = 0; |
| | 3039 | |
| | 3040 | // Bloodthirsty, these aliens... |
| | 3041 | return; |
| | 3042 | } |
| | 3043 | |
| | 3044 | /* Retreat target aquisition. */ |
| | 3045 | { |
| | 3046 | AIMODULE *targetModule = NearNPC_GetTargetAIModuleForRetreat(sbPtr, &(alienStatusPointer->moveData)); |
| | 3047 | |
| | 3048 | /* if (targetModule) |
| | 3049 | { |
| | 3050 | //printf("Target module is %s\n",targetModule->name); |
| | 3051 | //printf("Target AI module found, %x.\n",(int)targetModule); |
| | 3052 | } |
| | 3053 | else |
| | 3054 | { |
| | 3055 | printf("Target module is NULL!\n"); |
| | 3056 | } |
| | 3057 | */ |
| | 3058 | if ((targetModule == sbPtr->containingModule->m_aimodule) || (targetModule == NULL)) |
| | 3059 | { |
| | 3060 | /* Hey, it'll drop through. */ |
| | 3061 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3062 | alienStatusPointer->CurveTimeOut = 0; |
| | 3063 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3064 | return; |
| | 3065 | } |
| | 3066 | |
| | 3067 | assert(targetModule); |
| | 3068 | |
| | 3069 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); |
| | 3070 | |
| | 3071 | if (!thisEp) |
| | 3072 | { |
| | 3073 | //printf("This assert is a busted adjacency!\nNo EP between %s and
%s.",targetModule->name,sbPtr->containingModule->name); |
| | 3074 | printf("This assert is a busted adjacency!"); |
| | 3075 | assert(thisEp); |
| | 3076 | } |
| | 3077 | /* If that fired, there's a farped adjacency. */ |
| | 3078 | |
| | 3079 | alienStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 3080 | alienStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx; |
| | 3081 | alienStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy; |
| | 3082 | alienStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz; |
| | 3083 | } |
| | 3084 | |
| | 3085 | /* ok: should have a current target at this stage... */ |
| | 3086 | NPCGetMovementDirection(sbPtr, &velocityDirection,
&(alienStatusPointer->wanderData.worldPosition),&alienStatusPointer->waypointManager); |
| | 3087 | NPCSetVelocity(sbPtr, &velocityDirection, alienStatusPointer->MaxSpeed); |
| | 3088 | |
| | 3089 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 3090 | #if ALL_NEW_AVOIDANCE_ALIEN |
| | 3091 | { |
| | 3092 | if (New_NPC_IsObstructed(sbPtr,&alienStatusPointer->avoidanceManager)) |
| | 3093 | { |
| | 3094 | /* Go to all new avoidance. */ |
| | 3095 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 3096 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 3097 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3098 | return; |
| | 3099 | } |
| | 3100 | } |
| | 3101 | #else |
| | 3102 | { |
| | 3103 | STRATEGYBLOCK *destructableObject = NULL; |
| | 3104 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 3105 | NPC_IsObstructed(sbPtr, &alienStatusPointer->moveData, &obstruction,&destructableObject); |
| | 3106 | |
| | 3107 | if(obstruction.environment || obstruction.otherCharacter) |
| | 3108 | { |
| | 3109 | /* go to avoidance */ |
| | 3110 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3111 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 3112 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 3113 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 3114 | /* no sequence change required */ |
| | 3115 | return; |
| | 3116 | } |
| | 3117 | |
| | 3118 | if(obstruction.destructableObject) |
| | 3119 | { |
| | 3120 | assert(destructableObject); |
| | 3121 | CauseDamageToObject(destructableObject, &TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED, NULL); |
| | 3122 | } |
| | 3123 | } |
| | 3124 | |
| | 3125 | if(NPC_CannotReachTarget(&alienStatusPointer->moveData, &alienStatusPointer->wanderData.worldPosition, &velocityDirection)) |
| | 3126 | { |
| | 3127 | /* go to avoidance */ |
| | 3128 | NPC_OBSTRUCTIONREPORT obstruction = {1,0,0,0}; |
| | 3129 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3130 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 3131 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 3132 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 3133 | /* no sequence change required */ |
| | 3134 | } |
| | 3135 | #endif |
| | 3136 | } |
| | 3137 | default: |
| | 3138 | break; |
| | 3139 | } |
| | 3140 | } |
| | 3141 | |
| | 3142 | static void FarAlienBehaviour(STRATEGYBLOCK *sbPtr) |
| | 3143 | { |
| | 3144 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3145 | |
| | 3146 | switch(alienStatusPointer->BehaviourState) |
| | 3147 | { |
| | 3148 | case ABS_Hunt: |
| | 3149 | { |
| | 3150 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 3151 | |
| | 3152 | if (alienStatusPointer->Target && (alienStatusPointer->Target->containingModule->m_aimodule ==
sbPtr->containingModule->m_aimodule)) |
| | 3153 | { |
| | 3154 | alienStatusPointer->BehaviourState = ABS_Wait; |
| | 3155 | alienStatusPointer->StateTimer = 0; |
| | 3156 | } |
| | 3157 | else |
| | 3158 | { |
| | 3159 | /* check if far state timer has timed-out. If so, it is time |
| | 3160 | to do something. Otherwise just return. */ |
| | 3161 | if(alienStatusPointer->StateTimer > 0) |
| | 3162 | return; |
| | 3163 | |
| | 3164 | /* check the alien hive, to see itf we've switched to regroup: |
| | 3165 | if so, reset the alien far behaviour state to retreat, with the alien far |
| | 3166 | state timer set to 0, forcing a retreating movement next frame... */ |
| | 3167 | |
| | 3168 | if(NPCHive.currentState == HS_Regroup) |
| | 3169 | { |
| | 3170 | alienStatusPointer->BehaviourState = ABS_Retreat; |
| | 3171 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3172 | return; |
| | 3173 | } |
| | 3174 | |
| | 3175 | if (!AlienIsAwareOfTarget(sbPtr) && (alienStatusPointer->Target == PlayerStatus.sbptr) && NPC_IsDead(PlayerStatus.sbptr)) |
| | 3176 | { |
| | 3177 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 3178 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3179 | } |
| | 3180 | else |
| | 3181 | { |
| | 3182 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 1); |
| | 3183 | |
| | 3184 | /* if there is no target module, it means that the alien is trapped in an |
| | 3185 | unlinked module. In this case, reset the timer and return. */ |
| | 3186 | |
| | 3187 | if(!targetModule) |
| | 3188 | { |
| | 3189 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 3190 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 3191 | alienStatusPointer->CurveTimeOut = 0; |
| | 3192 | } |
| | 3193 | else |
| | 3194 | { |
| | 3195 | alienStatusPointer->StateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule); |
| | 3196 | alienStatusPointer->StateTimer += ONE_FIXED * 3 + ( (FastRandom() & 7) * ONE_FIXED); |
| | 3197 | } |
| | 3198 | } |
| | 3199 | } |
| | 3200 | } |
| | 3201 | break; |
| | 3202 | case ABS_Retreat: |
| | 3203 | { |
| | 3204 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 3205 | |
| | 3206 | /* check if far state timer has timed-out. If so, it is time |
| | 3207 | to do something. Otherwise just return. */ |
| | 3208 | |
| | 3209 | if(alienStatusPointer->StateTimer > 0) |
| | 3210 | return; |
| | 3211 | |
| | 3212 | /* check the alien hive, to see if we've switched to attack: |
| | 3213 | if so, reset the alien far behaviour state to attack, with the alien far |
| | 3214 | state timer set to 0, forcing a movement next frame... |
| | 3215 | NB if we can't attack the player, hunting function will automatically |
| | 3216 | switch to wander */ |
| | 3217 | |
| | 3218 | if(NPCHive.currentState == HS_Attack) |
| | 3219 | { |
| | 3220 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3221 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3222 | return; |
| | 3223 | } |
| | 3224 | |
| | 3225 | /* get the target module... */ |
| | 3226 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForRetreat(sbPtr); |
| | 3227 | |
| | 3228 | /* if there is no target module, reset the timer and return. */ |
| | 3229 | if(!targetModule) |
| | 3230 | { |
| | 3231 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 3232 | return; |
| | 3233 | } |
| | 3234 | |
| | 3235 | /* Examine target, and decide what to do */ |
| | 3236 | assert(AIModuleIsPhysical(targetModule)); |
| | 3237 | |
| | 3238 | alienStatusPointer->StateTimer = ProcessFarAlienTargetModule(sbPtr, targetModule); |
| | 3239 | } |
| | 3240 | break; |
| | 3241 | case ABS_Wander: |
| | 3242 | { |
| | 3243 | /* Decrement the Far state timer */ |
| | 3244 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 3245 | |
| | 3246 | /* check if far state timer has timed-out. If so, it is time to do something. Otherwise just return. */ |
| | 3247 | if(alienStatusPointer->StateTimer > 0) |
| | 3248 | return; |
| | 3249 | |
| | 3250 | /* check for state changes: |
| | 3251 | if hive says retreat, then retreat, regardless of whether or not we can see the player |
| | 3252 | otherwise, if we can see the player, go to hunt */ |
| | 3253 | |
| | 3254 | if(NPCHive.currentState == HS_Regroup) |
| | 3255 | { |
| | 3256 | alienStatusPointer->BehaviourState = ABS_Retreat; |
| | 3257 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3258 | return; |
| | 3259 | } |
| | 3260 | |
| | 3261 | /* see if we want to switch to attack */ |
| | 3262 | if(AlienIsAwareOfTarget(sbPtr)) |
| | 3263 | { |
| | 3264 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3265 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3266 | return; |
| | 3267 | } |
| | 3268 | |
| | 3269 | /* get the target module... */ |
| | 3270 | |
| | 3271 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr, NULL, 1); |
| | 3272 | |
| | 3273 | /* if there is no target module, reset the timer and return. */ |
| | 3274 | alienStatusPointer->StateTimer = (NULL != targetModule) ? ProcessFarAlienTargetModule(sbPtr, targetModule) : ALIEN_FAR_MOVE_TIME; |
| | 3275 | } |
| | 3276 | break; |
| | 3277 | case ABS_Wait: |
| | 3278 | { |
| | 3279 | if (alienStatusPointer->Target && alienStatusPointer->Target->containingModule->m_aimodule !=
sbPtr->containingModule->m_aimodule) |
| | 3280 | { |
| | 3281 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3282 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3283 | } |
| | 3284 | else |
| | 3285 | { |
| | 3286 | /* Decrement the Far state timer */ |
| | 3287 | alienStatusPointer->StateTimer -= NormalFrameTime; |
| | 3288 | |
| | 3289 | /* check if far state timer has timed-out. If so, it is time to do something. Otherwise just return. */ |
| | 3290 | if(alienStatusPointer->StateTimer > 0) |
| | 3291 | return; |
| | 3292 | } |
| | 3293 | } |
| | 3294 | case ABS_Dormant: |
| | 3295 | case ABS_Awakening: |
| | 3296 | break; |
| | 3297 | case ABS_Avoidance: |
| | 3298 | { |
| | 3299 | /* No obstacles in far behaviour. */ |
| | 3300 | Initialise_AvoidanceManager(&alienStatusPointer->avoidanceManager); |
| | 3301 | } |
| | 3302 | // no break |
| | 3303 | default: |
| | 3304 | { |
| | 3305 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3306 | alienStatusPointer->StateTimer = 0; /* forces execution of new state next frame*/ |
| | 3307 | } |
| | 3308 | } |
| | 3309 | |
| | 3310 | /* check here to see if the alien is in a doorway.... |
| | 3311 | If so, and it is a proximity door, make sure it is open. */ |
| | 3312 | { |
| | 3313 | MODULEDOORTYPE doorType = ModuleIsADoor(sbPtr->containingModule); |
| | 3314 | |
| | 3315 | if(doorType == MDT_ProxDoor) |
| | 3316 | ((PROXDOOR_BEHAV_BLOCK *)sbPtr->containingModule->m_sbptr->dataptr)->alienTrigger = 1; |
| | 3317 | } |
| | 3318 | |
| | 3319 | if (ShowHiveState) |
| | 3320 | { |
| | 3321 | MODULE *thisModule = sbPtr->containingModule; |
| | 3322 | printf("This FAR ALIEN is in module %d, %s\n", thisModule->m_index, thisModule->name); |
| | 3323 | } |
| | 3324 | |
| | 3325 | /* make sure that we are inside a module: |
| | 3326 | if this fires it means that a far alien is not inside |
| | 3327 | the module it is supposed to be in */ |
| | 3328 | |
| | 3329 | #if UseLocalAssert |
| | 3330 | { |
| | 3331 | VECTORCH localCoords; |
| | 3332 | MODULE *thisModule = sbPtr->containingModule; |
| | 3333 | |
| | 3334 | assert(thisModule); |
| | 3335 | |
| | 3336 | localCoords = sbPtr->DynPtr->Position; |
| | 3337 | localCoords.vx -= thisModule->m_world.vx; |
| | 3338 | localCoords.vy -= thisModule->m_world.vy; |
| | 3339 | localCoords.vz -= thisModule->m_world.vz; |
| | 3340 | |
| | 3341 | if(!PointIsInModule(thisModule, &localCoords)) |
| | 3342 | { |
| | 3343 | //printf("FAR ALIEN MODULE CONTAINMENT FAILURE \n"); |
| | 3344 | |
| | 3345 | printf("Alien containment failure: alien is in %s, position is %d,%d,%d:\nModule extents are: %d:%d, %d:%d, %d:%d", |
| | 3346 | thisModule->name,localCoords.vx,localCoords.vy,localCoords.vz, |
| | 3347 | thisModule->m_maxx,thisModule->m_minx,thisModule->m_maxy,thisModule->m_miny, |
| | 3348 | thisModule->m_maxz,thisModule->m_minz); |
| | 3349 | |
| | 3350 | assert(1==0); |
| | 3351 | } |
| | 3352 | } |
| | 3353 | #endif |
| | 3354 | |
| | 3355 | // printf("NO ENTRY POINT COUNT %d \n", entryPointFailures); |
| | 3356 | } |
| | 3357 | |
| | 3358 | void AlienBehaviour(STRATEGYBLOCK *sbPtr) |
| | 3359 | { |
| | 3360 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3361 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 3362 | |
| | 3363 | dynPtr->LinVelocity.vx = dynPtr->LinVelocity.vy = dynPtr->LinVelocity.vz = 0; |
| | 3364 | //dynPtr->UseStandardGravity = 1; // don't climb on walls, etc |
| | 3365 | dynPtr->UseStandardGravity = !AlienIsAbleToClimb(sbPtr); |
| | 3366 | |
| | 3367 | if(alienStatusPointer->unconscious) |
| | 3368 | { |
| | 3369 | alienStatusPointer->Target = alienStatusPointer->current_attack = NULL; |
| | 3370 | |
| | 3371 | if(alienStatusPointer->unconscious < 0) |
| | 3372 | { |
| | 3373 | alienStatusPointer->IAmCrouched = 1; |
| | 3374 | |
| | 3375 | if (HMSQT_AlienCrouch == alienStatusPointer->HModelController.Sequence_Type) |
| | 3376 | { |
| | 3377 | alienStatusPointer->unconscious = 0; |
| | 3378 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3379 | } |
| | 3380 | else |
| | 3381 | { |
| | 3382 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrouch, ACrSS_Standard, -1, (ONE_FIXED>>3)); |
| | 3383 | return; |
| | 3384 | } |
| | 3385 | } |
| | 3386 | else |
| | 3387 | { |
| | 3388 | alienStatusPointer->unconscious -= NormalFrameTime; |
| | 3389 | return; |
| | 3390 | } |
| | 3391 | } |
| | 3392 | |
| | 3393 | /* Unset incident flag. */ |
| | 3394 | alienStatusPointer->incidentFlag = 0; |
| | 3395 | alienStatusPointer->incidentTimer -= NormalFrameTime; |
| | 3396 | |
| | 3397 | if (alienStatusPointer->incidentTimer < 0) |
| | 3398 | { |
| | 3399 | alienStatusPointer->incidentFlag = 1; |
| | 3400 | alienStatusPointer->incidentTimer = 32767 + (FastRandom() & 65535); |
| | 3401 | } |
| | 3402 | |
| | 3403 | if (sbPtr->DamageBlock.IsOnFire) |
| | 3404 | { |
| | 3405 | if(alienStatusPointer->soundOnFire != SOUND_NOACTIVEINDEX) |
| | 3406 | Sound_Update3d(alienStatusPointer->soundOnFire, &sbPtr->DynPtr->Position); |
| | 3407 | else |
| | 3408 | Sound_Play(SID_FIRE, "dle", &sbPtr->DynPtr->Position, &alienStatusPointer->soundOnFire); |
| | 3409 | |
| | 3410 | //for multiplayer games it is necessary to say who is doing this damage |
| | 3411 | //(that would be the person who set the alien on fire in the first place) |
| | 3412 | { |
| | 3413 | /* |
| | 3414 | extern int myNetworkKillerId; |
| | 3415 | extern int AVPDPNetID; |
| | 3416 | myNetworkKillerId = alienStatusPointer->aliensIgniterId; |
| | 3417 | myNetworkKillerId = AVPDPNetID; |
| | 3418 | */ |
| | 3419 | } |
| | 3420 | |
| | 3421 | if (alienStatusPointer->incidentFlag && ((FastRandom() & 65535) < 32767)) |
| | 3422 | { |
| | 3423 | sbPtr->DamageBlock.IsOnFire = 0; |
| | 3424 | Sound_Stop(alienStatusPointer->soundOnFire); |
| | 3425 | } |
| | 3426 | else |
| | 3427 | { |
| | 3428 | int speed = Approximate3dMagnitude(&sbPtr->DynPtr->LinVelocity); |
| | 3429 | /* Go out? */ |
| | 3430 | |
| | 3431 | if (speed > 22000) |
| | 3432 | { |
| | 3433 | /* Jumping alien. */ |
| | 3434 | sbPtr->DamageBlock.IsOnFire -= NormalFrameTime * 6; |
| | 3435 | } |
| | 3436 | else if (speed > 15000) |
| | 3437 | { |
| | 3438 | /* Running alien. */ |
| | 3439 | sbPtr->DamageBlock.IsOnFire -= NormalFrameTime << 2; |
| | 3440 | } |
| | 3441 | else |
| | 3442 | { |
| | 3443 | /* Normal bloke. */ |
| | 3444 | sbPtr->DamageBlock.IsOnFire -= NormalFrameTime; |
| | 3445 | } |
| | 3446 | |
| | 3447 | if (sbPtr->DamageBlock.IsOnFire <= 0) |
| | 3448 | { |
| | 3449 | sbPtr->DamageBlock.IsOnFire = 0; |
| | 3450 | Sound_Stop(alienStatusPointer->soundOnFire); |
| | 3451 | } |
| | 3452 | } |
| | 3453 | } |
| | 3454 | |
| | 3455 | //printf("alienStatusPointer->BehaviourState %d %s\n", alienStatusPointer->BehaviourState, (sbPtr->DisplayBlock ? "near" :
"far")); //jadda |
| | 3456 | //if(alienStatusPointer->Target != NULL) printf("has TARGET %d\n", alienStatusPointer->Target->type); |
| | 3457 | //if(alienStatusPointer->current_attack != NULL) puts("nooooo nULL"); |
| | 3458 | //if(dynPtr->UseStandardGravity) puts("STANDARG GVRAVITY nULL"); else puts("NOT STANDARG GVRAVITY nULL"); |
| | 3459 | |
| | 3460 | switch(alienStatusPointer->BehaviourState) |
| | 3461 | { |
| | 3462 | case ABS_Awakening: |
| | 3463 | { |
| | 3464 | /* wait until near state timer runs out, then wander: |
| | 3465 | alternatively, if we can attack the player, go straight to approach */ |
| | 3466 | |
| | 3467 | if (!sbPtr->DisplayBlock) |
| | 3468 | ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr); |
| | 3469 | |
| | 3470 | if ((alienStatusPointer->HModelController.Tweening == Controller_NoTweening) && (alienStatusPointer->HModelController.sequence_timer
== (ONE_FIXED-1))) |
| | 3471 | { |
| | 3472 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3473 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 3474 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3475 | alienStatusPointer->CurveTimeOut = 0; |
| | 3476 | alienStatusPointer->StateTimer = 0; |
| | 3477 | } |
| | 3478 | } |
| | 3479 | return; |
| | 3480 | case ABS_Dormant: |
| | 3481 | { |
| | 3482 | /* wait until near state timer runs out, then wander: |
| | 3483 | alternatively, if we can attack the player, go straight to approach */ |
| | 3484 | |
| | 3485 | /* Also used for FAR! */ |
| | 3486 | |
| | 3487 | if (!sbPtr->DisplayBlock) |
| | 3488 | { |
| | 3489 | if (alienStatusPointer->HModelController.Playing) |
| | 3490 | { |
| | 3491 | /* Try to call this as little as possible. */ |
| | 3492 | ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr); |
| | 3493 | |
| | 3494 | if (!alienStatusPointer->HModelController.Tweening) |
| | 3495 | alienStatusPointer->HModelController.Playing = 0; |
| | 3496 | } |
| | 3497 | } |
| | 3498 | else |
| | 3499 | { |
| | 3500 | alienStatusPointer->HModelController.Playing = 1; |
| | 3501 | } |
| | 3502 | |
| | 3503 | /* Brushing Test. */ |
| | 3504 | { |
| | 3505 | struct collisionreport *nextReport = sbPtr->DynPtr->CollisionReportPtr; |
| | 3506 | |
| | 3507 | while(nextReport) |
| | 3508 | { |
| | 3509 | if(nextReport->ObstacleSBPtr) |
| | 3510 | { |
| | 3511 | switch(nextReport->ObstacleSBPtr->type) |
| | 3512 | { |
| | 3513 | case I_BehaviourAlienPlayer: |
| | 3514 | case I_BehaviourMarinePlayer: |
| | 3515 | case I_BehaviourMarine: |
| | 3516 | case I_BehaviourPredatorPlayer: |
| | 3517 | case I_BehaviourNetGhost: |
| | 3518 | case I_BehaviourXenoborg: |
| | 3519 | case I_BehaviourQueenAlien: |
| | 3520 | case I_BehaviourFaceHugger: |
| | 3521 | Alien_Awaken(sbPtr); |
| | 3522 | default: |
| | 3523 | break; |
| | 3524 | } |
| | 3525 | } |
| | 3526 | |
| | 3527 | nextReport = nextReport->NextCollisionReportPtr; |
| | 3528 | } |
| | 3529 | } |
| | 3530 | } |
| | 3531 | return; |
| | 3532 | case ABS_Taunting: |
| | 3533 | { |
| | 3534 | if (!sbPtr->DisplayBlock) |
| | 3535 | { |
| | 3536 | ProveHModel_Far(&alienStatusPointer->HModelController,sbPtr); |
| | 3537 | } |
| | 3538 | else |
| | 3539 | { |
| | 3540 | /* Orientate towards target, to avoid looking stupid */ |
| | 3541 | if (alienStatusPointer->Target) |
| | 3542 | { |
| | 3543 | VECTORCH orientationDirn; |
| | 3544 | orientationDirn.vx = alienStatusPointer->Target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 3545 | orientationDirn.vy = 0; |
| | 3546 | orientationDirn.vz = alienStatusPointer->Target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 3547 | NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 3548 | } |
| | 3549 | } |
| | 3550 | |
| | 3551 | if (HModelAnimation_IsFinished(&alienStatusPointer->HModelController)) |
| | 3552 | { |
| | 3553 | /* Exit state somehow. */ |
| | 3554 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3555 | |
| | 3556 | if (NULL != alienStatusPointer->Target) |
| | 3557 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 3558 | else |
| | 3559 | alienStatusPointer->BehaviourState = sbPtr->DisplayBlock ? ABS_Approach : ABS_Hunt; |
| | 3560 | } |
| | 3561 | } |
| | 3562 | return; |
| | 3563 | default: |
| | 3564 | { |
| | 3565 | if (NULL != alienStatusPointer->Target) |
| | 3566 | { |
| | 3567 | //if(NPC_IsDead(alienStatusPointer->Target) || !NAME_ISEQUAL(alienStatusPointer->Target->SBname, alienStatusPointer->Target_SBname)
|| !AlienHasPathToTarget(sbPtr)) |
| | 3568 | if(NPC_IsDead(alienStatusPointer->Target) || !NAME_ISEQUAL(alienStatusPointer->Target->SBname, alienStatusPointer->Target_SBname)) |
| | 3569 | { |
| | 3570 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3571 | alienStatusPointer->Target = alienStatusPointer->current_attack = NULL; |
| | 3572 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 3573 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3574 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3575 | } |
| | 3576 | } |
| | 3577 | |
| | 3578 | if (sbPtr->DisplayBlock || alienStatusPointer->incidentFlag) |
| | 3579 | { |
| | 3580 | if (alienStatusPointer->Target == NULL) |
| | 3581 | { |
| | 3582 | alienStatusPointer->current_attack = NULL; |
| | 3583 | alienStatusPointer->Target = Alien_GetNewTarget(sbPtr); |
| | 3584 | |
| | 3585 | if (alienStatusPointer->Target != NULL) |
| | 3586 | { |
| | 3587 | COPY_NAME(alienStatusPointer->Target_SBname, alienStatusPointer->Target->SBname); |
| | 3588 | |
| | 3589 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 3590 | alienStatusPointer->StateTimer = 0; |
| | 3591 | alienStatusPointer->BehaviourState = ABS_Approach; |
| | 3592 | } |
| | 3593 | else |
| | 3594 | { |
| | 3595 | //printf("Alien found no target!\n"); |
| | 3596 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 1); |
| | 3597 | |
| | 3598 | if (!targetModule || PlayerIsDeadAndNoLivingNetghosts()) |
| | 3599 | { |
| | 3600 | if (alienStatusPointer->BehaviourState != ABS_Wander) |
| | 3601 | { |
| | 3602 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 3603 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 3604 | alienStatusPointer->StateTimer = 0; |
| | 3605 | alienStatusPointer->BehaviourState = ABS_Wander; |
| | 3606 | } |
| | 3607 | } |
| | 3608 | else if (alienStatusPointer->BehaviourState != ABS_Hunt) |
| | 3609 | { |
| | 3610 | alienStatusPointer->BehaviourState = ABS_Hunt; |
| | 3611 | |
| | 3612 | if (sbPtr->DisplayBlock) |
| | 3613 | { |
| | 3614 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3615 | alienStatusPointer->StateTimer = ALIEN_NEARWAITTIME; |
| | 3616 | } |
| | 3617 | else |
| | 3618 | { |
| | 3619 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 3620 | } |
| | 3621 | } |
| | 3622 | } |
| | 3623 | } |
| | 3624 | } |
| | 3625 | } |
| | 3626 | } |
| | 3627 | |
| | 3628 | if(sbPtr->DisplayBlock) |
| | 3629 | { |
| | 3630 | NearAliens++; |
| | 3631 | //printf("Near %s alien is in module %d, %s\n", descriptor, sbPtr->containingModule->m_index, sbPtr->containingModule->name); |
| | 3632 | NearAlienBehaviour(sbPtr); |
| | 3633 | } |
| | 3634 | else |
| | 3635 | { |
| | 3636 | //printf("Far Alien in module %s \n", sbPtr->containingModule->name); |
| | 3637 | FarAliens++; |
| | 3638 | FarAlienBehaviour(sbPtr); |
| | 3639 | } |
| | 3640 | |
| | 3641 | /* Update delta playing flag. */ |
| | 3642 | { |
| | 3643 | DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&alienStatusPointer->HModelController, "HitDelta"); |
| | 3644 | |
| | 3645 | if (hitdelta && DeltaAnimation_IsFinished(hitdelta)) |
| | 3646 | hitdelta->Playing = 0; |
| | 3647 | } |
| | 3648 | |
| | 3649 | HModel_Regen(&alienStatusPointer->HModelController, 4 * ONE_FIXED ); |
| | 3650 | } |
| | 3651 | |
| | 3652 | /*----------------------Patrick 7/11/96----------------------------- |
| | 3653 | This pair of functions handle the alien visibility switching.... |
| | 3654 | Note that the ai-pheromone system is maintained by these functions. |
| | 3655 | --------------------------------------------------------------------*/ |
| | 3656 | void MakeAlienNear(STRATEGYBLOCK *sbPtr) |
| | 3657 | { |
| | 3658 | /* first of all, see how many aliens are currently near: if there are too many, |
| | 3659 | destroy this alien, and try to force a generator to make a replacement */ |
| | 3660 | |
| | 3661 | if(NumGeneratorNPCsVisible() >= MAX_VISIBLEGENERATORNPCS) |
| | 3662 | { |
| | 3663 | sbPtr->please_destroy_me = 1; |
| | 3664 | ForceAGenerator(); |
| | 3665 | } |
| | 3666 | |
| | 3667 | DISPLAYBLOCK *dPtr = CreateActiveObject(); |
| | 3668 | |
| | 3669 | if(NULL != dPtr) |
| | 3670 | { |
| | 3671 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3672 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 3673 | sbPtr->DisplayBlock = dPtr; |
| | 3674 | dPtr->ObStrategyBlock = sbPtr; |
| | 3675 | |
| | 3676 | /* also need to initialise positional information in the new display block, |
| | 3677 | from the existing dynamics block. |
| | 3678 | NB this necessary because this function is (usually) called between the |
| | 3679 | dynamics and rendering systems so it is not initialised by the dynamics |
| | 3680 | system the first frame it is drawn. */ |
| | 3681 | dPtr->ObWorld = dynPtr->Position; |
| | 3682 | dPtr->ObEuler = dynPtr->OrientEuler; |
| | 3683 | dPtr->ObMat = dynPtr->OrientMat; |
| | 3684 | |
| | 3685 | dPtr->HModelControlBlock = &alienStatusPointer->HModelController; |
| | 3686 | ProveHModel(dPtr->HModelControlBlock, dPtr); |
| | 3687 | |
| | 3688 | /* init state timers */ |
| | 3689 | alienStatusPointer->StateTimer = 0; |
| | 3690 | alienStatusPointer->StateTimer = ALIEN_FAR_MOVE_TIME; |
| | 3691 | alienStatusPointer->CurveRadius = alienStatusPointer->CurveLength = alienStatusPointer->CurveTimeOut = 0; |
| | 3692 | InitWaypointManager(&alienStatusPointer->waypointManager); |
| | 3693 | dPtr->HModelControlBlock->Playing = 1; |
| | 3694 | } |
| | 3695 | } |
| | 3696 | |
| | 3697 | extern DEATH_DATA Alien_Deaths[]; |
| | 3698 | |
| | 3699 | /* patrick 29/7/97 ----------------------------------- |
| | 3700 | This function to be called only from behaviour |
| | 3701 | -- ChrisF 1/4/98 What a stupid idea. This function --- |
| | 3702 | -- to be called only from AlienIsDamaged. ------------ |
| | 3703 | ------------------------------------------------------*/ |
| | 3704 | static void KillAlien(STRATEGYBLOCK *sbPtr, int wounds, const DAMAGE_PROFILE *damage, VECTORCH *incoming) |
| | 3705 | { |
| | 3706 | DEATH_DATA *this_death = NULL; |
| | 3707 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3708 | HIT_FACING facing = { 0,0,0,0 }; |
| | 3709 | |
| | 3710 | if (incoming) |
| | 3711 | { |
| | 3712 | if (incoming->vz > 0) |
| | 3713 | facing.Back = 1; |
| | 3714 | else |
| | 3715 | facing.Front = 1; |
| | 3716 | |
| | 3717 | if (incoming->vx > 0) |
| | 3718 | facing.Right = 1; |
| | 3719 | else |
| | 3720 | facing.Left = 1; |
| | 3721 | } |
| | 3722 | |
| | 3723 | /*If alien has a death target ,send a request*/ |
| | 3724 | if(alienStatusPointer->death_target_sbptr) |
| | 3725 | RequestState(alienStatusPointer->death_target_sbptr, 1, 0); |
| | 3726 | |
| | 3727 | int deathtype = 0; |
| | 3728 | int electrical = damage->Electrical; |
| | 3729 | |
| | 3730 | switch(damage->Id) |
| | 3731 | { |
| | 3732 | case EXPLOSIONFIRE_BLAST: |
| | 3733 | case AMMO_FRAGMENTATION_GRENADE: |
| | 3734 | alienStatusPointer->GibbFactor = (alienStatusPointer->Type == Standard) ? ONE_FIXED >> 1 : ONE_FIXED >> 3; |
| | 3735 | Extreme_Gibbing(sbPtr, alienStatusPointer->HModelController.section_data, alienStatusPointer->GibbFactor, incoming); |
| | 3736 | break; |
| | 3737 | case AMMO_FLECHETTE: |
| | 3738 | alienStatusPointer->GibbFactor = ONE_FIXED >> 4; |
| | 3739 | Extreme_Gibbing(sbPtr, alienStatusPointer->HModelController.section_data, alienStatusPointer->GibbFactor, incoming); |
| | 3740 | default: |
| | 3741 | break; |
| | 3742 | } |
| | 3743 | |
| | 3744 | if(alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX) |
| | 3745 | { |
| | 3746 | /* make a sound... if you have a head. */ |
| | 3747 | SECTION_DATA *chest = GetThisSectionData(alienStatusPointer->HModelController.section_data, "chest"); |
| | 3748 | |
| | 3749 | if(NULL != chest) |
| | 3750 | { |
| | 3751 | SECTION_DATA *head = GetThisSectionData(alienStatusPointer->HModelController.section_data, "head"); |
| | 3752 | |
| | 3753 | /* Is it still attached? */ |
| | 3754 | if (head && !(head->flags & section_data_notreal)) |
| | 3755 | { |
| | 3756 | PlayAlienSound((int)alienStatusPointer->Type, ASC_Scream_Dying, 0, &alienStatusPointer->sound_mouth,
&sbPtr->DynPtr->Position); |
| | 3757 | //PlayAlienSound((int)alienStatusPointer->Type, ASC_Death, 0, NULL, &sbPtr->DynPtr->Position); |
| | 3758 | |
| | 3759 | if(NetworkPeer == AvP.PlayMode) |
| | 3760 | AddNetMsg_SpotAlienSound((int)ASC_Scream_Dying, (int)alienStatusPointer->Type, 0, &sbPtr->DynPtr->Position); |
| | 3761 | } |
| | 3762 | } |
| | 3763 | } |
| | 3764 | |
| | 3765 | if(sbPtr->DynPtr->OrientMat.mat22 < 63000) // should be crouched |
| | 3766 | { |
| | 3767 | } |
| | 3768 | else if(alienStatusPointer->IAmCrouched) // crouched on flat |
| | 3769 | { |
| | 3770 | if (Standard == alienStatusPointer->Type) |
| | 3771 | { |
| | 3772 | if (damage->Electrical) |
| | 3773 | { |
| | 3774 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrawl, (int)ACSS_Pain_Fall_Right, -1,
0); |
| | 3775 | this_death = &Alien_Deaths[1]; |
| | 3776 | } |
| | 3777 | else if(facing.Front && damage->ExplosivePower) |
| | 3778 | { |
| | 3779 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienCrawl, (int)ACSS_Boom_Fall_Back,
ONE_FIXED, 0); |
| | 3780 | this_death = &Alien_Deaths[2]; |
| | 3781 | } |
| | 3782 | else |
| | 3783 | { |
| | 3784 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrouch, (int)ACrSS_Dies, -1, 0); |
| | 3785 | this_death = &Alien_Deaths[0]; |
| | 3786 | } |
| | 3787 | } |
| | 3788 | else if(Predalien == alienStatusPointer->Type && ((FastRandom() & 65535) < 25000)) |
| | 3789 | { |
| | 3790 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrouch, (int)ACrSS_Dies_Thrash, -1, 0); |
| | 3791 | this_death = &Alien_Deaths[9]; |
| | 3792 | } |
| | 3793 | else |
| | 3794 | { |
| | 3795 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienCrouch, (int)ACrSS_Dies, -1, 0); |
| | 3796 | this_death = &Alien_Deaths[0]; |
| | 3797 | } |
| | 3798 | } |
| | 3799 | else // standing on flat |
| | 3800 | { |
| | 3801 | if (Standard == alienStatusPointer->Type) |
| | 3802 | { |
| | 3803 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Back, -1, 0); //
not now |
| | 3804 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Spin_Clockwise, -1, 0); //
now now |
| | 3805 | |
| | 3806 | if(damage->ExplosivePower) |
| | 3807 | { |
| | 3808 | if((FastRandom() & 65535) < 30000) |
| | 3809 | { |
| | 3810 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back,
-1, 0); |
| | 3811 | this_death = &Alien_Deaths[3]; |
| | 3812 | } |
| | 3813 | else if(facing.Front) |
| | 3814 | { |
| | 3815 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0); |
| | 3816 | this_death = &Alien_Deaths[4]; |
| | 3817 | } |
| | 3818 | else if(facing.Back) |
| | 3819 | { |
| | 3820 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd, -1,
0); |
| | 3821 | this_death = &Alien_Deaths[6]; |
| | 3822 | } |
| | 3823 | } |
| | 3824 | else if(damage->Electrical && ((FastRandom() & 65535) > 20000)) |
| | 3825 | { |
| | 3826 | if((FastRandom() & 65535) < 30000) |
| | 3827 | { |
| | 3828 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd,
-1, 0); |
| | 3829 | this_death = &Alien_Deaths[5]; |
| | 3830 | } |
| | 3831 | else |
| | 3832 | { |
| | 3833 | } |
| | 3834 | } |
| | 3835 | else |
| | 3836 | { |
| | 3837 | if(facing.Front && ((FastRandom() & 65535) < 30000)) |
| | 3838 | { |
| | 3839 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0); |
| | 3840 | this_death = &Alien_Deaths[4]; |
| | 3841 | } |
| | 3842 | else |
| | 3843 | { |
| | 3844 | switch(FastRandom() % 3) |
| | 3845 | { |
| | 3846 | case 0: |
| | 3847 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd,
-1, 0); |
| | 3848 | this_death = &Alien_Deaths[6]; |
| | 3849 | break; |
| | 3850 | case 1: |
| | 3851 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Back, -1, 0); |
| | 3852 | this_death = &Alien_Deaths[3]; |
| | 3853 | break; |
| | 3854 | case 2: |
| | 3855 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd,
-1, 0); |
| | 3856 | this_death = &Alien_Deaths[5]; |
| | 3857 | } |
| | 3858 | } |
| | 3859 | } |
| | 3860 | } |
| | 3861 | else if (Predalien == alienStatusPointer->Type) |
| | 3862 | { |
| | 3863 | switch(FastRandom() % 4) |
| | 3864 | { |
| | 3865 | case 0: |
| | 3866 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back, -1,
0); |
| | 3867 | this_death = &Alien_Deaths[3]; |
| | 3868 | break; |
| | 3869 | case 1: |
| | 3870 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0); |
| | 3871 | this_death = &Alien_Deaths[4]; |
| | 3872 | break; |
| | 3873 | case 2: |
| | 3874 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd, -1,
0); |
| | 3875 | this_death = &Alien_Deaths[5]; |
| | 3876 | break; |
| | 3877 | case 3: |
| | 3878 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd, -1,
0); |
| | 3879 | this_death = &Alien_Deaths[6]; |
| | 3880 | } |
| | 3881 | /* |
| | 3882 | if(facing.Front) |
| | 3883 | { |
| | 3884 | if(fall_back) |
| | 3885 | { |
| | 3886 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1, 0); |
| | 3887 | this_death = &Alien_Deaths[4]; |
| | 3888 | } |
| | 3889 | else |
| | 3890 | { |
| | 3891 | if((FastRandom() & 65535) > 20000) |
| | 3892 | { |
| | 3893 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Fwd, -1, 0); |
| | 3894 | this_death = &Alien_Deaths[5]; |
| | 3895 | } |
| | 3896 | else |
| | 3897 | { |
| | 3898 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1,
0); |
| | 3899 | this_death = &Alien_Deaths[4]; |
| | 3900 | } |
| | 3901 | } |
| | 3902 | } |
| | 3903 | else |
| | 3904 | { |
| | 3905 | if(fall_back) |
| | 3906 | { |
| | 3907 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Fwd,
-1, 0); |
| | 3908 | this_death = &Alien_Deaths[5]; |
| | 3909 | } |
| | 3910 | else |
| | 3911 | { |
| | 3912 | if((FastRandom() & 65535) > 20000) |
| | 3913 | { |
| | 3914 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Back, -1, 0); |
| | 3915 | this_death = &Alien_Deaths[3]; |
| | 3916 | } |
| | 3917 | else |
| | 3918 | { |
| | 3919 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienStand,
(int)ASSS_Boom_Fall_Fwd, -1, 0); |
| | 3920 | this_death = &Alien_Deaths[6]; |
| | 3921 | } |
| | 3922 | } |
| | 3923 | } |
| | 3924 | */ |
| | 3925 | } |
| | 3926 | else |
| | 3927 | { |
| | 3928 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Back, -1, 0);
// not now |
| | 3929 | |
| | 3930 | if(damage->Electrical) |
| | 3931 | { |
| | 3932 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back, -1,
0); |
| | 3933 | this_death = &Alien_Deaths[3]; |
| | 3934 | } |
| | 3935 | else if(facing.Front) |
| | 3936 | { |
| | 3937 | if(damage->ExplosivePower) |
| | 3938 | { |
| | 3939 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Spin_Clockwise,
-1, 0); |
| | 3940 | this_death = &Alien_Deaths[8]; |
| | 3941 | } |
| | 3942 | else |
| | 3943 | { |
| | 3944 | switch(FastRandom() % 3) |
| | 3945 | { |
| | 3946 | case 0: |
| | 3947 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies,
-1, 0); |
| | 3948 | this_death = &Alien_Deaths[4]; |
| | 3949 | break; |
| | 3950 | case 1: |
| | 3951 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand,
(int)ASSS_Pain_Fall_Back, -1, 0); |
| | 3952 | this_death = &Alien_Deaths[3]; |
| | 3953 | break; |
| | 3954 | case 2: |
| | 3955 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand,
(int)ASSS_Boom_Fall_Fwd, -1, 0); |
| | 3956 | this_death = &Alien_Deaths[6]; |
| | 3957 | } |
| | 3958 | } |
| | 3959 | } |
| | 3960 | else |
| | 3961 | { |
| | 3962 | if((FastRandom() & 65535) < 20000) |
| | 3963 | { |
| | 3964 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Pain_Fall_Back,
-1, 0); |
| | 3965 | this_death = &Alien_Deaths[3]; |
| | 3966 | } |
| | 3967 | else |
| | 3968 | { |
| | 3969 | //InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_AlienStand, (int)ASSS_Boom_Fall_Fwd, -1,
0); |
| | 3970 | this_death = &Alien_Deaths[6]; |
| | 3971 | } |
| | 3972 | } |
| | 3973 | } |
| | 3974 | } |
| | 3975 | |
| | 3976 | if(this_death == NULL) |
| | 3977 | this_death = GetAlienDeathSequence(&alienStatusPointer->HModelController, NULL, alienStatusPointer->Wounds, alienStatusPointer->Wounds, deathtype,
&facing, 0, alienStatusPointer->IAmCrouched, electrical); |
| | 3978 | |
| | 3979 | Convert_Alien_To_Corpse(sbPtr, this_death, damage); |
| | 3980 | } |
| | 3981 | |
| | 3982 | /*----------------------Patrick 7/11/96----------------------------- |
| | 3983 | Handle weapon impact on an alien |
| | 3984 | --------------------------------------------------------------------*/ |
| | 3985 | /* KJL 11:46:43 12/17/96 - rewritten */ |
| | 3986 | |
| | 3987 | // JB 16/6/97 rewritten |
| | 3988 | // Patrick 29/7/97 rewritten again. again. |
| | 3989 | // ChrisF 16/9/97 rewritten again again, again. |
| | 3990 | // ChrisF 26/11/97 rewritten again, again, again, again. |
| | 3991 | // ChrisF 1/4/98 rewritten again again again again again. Okay, 'modified' then. Added directional parameter. |
| | 3992 | // ChrisF 20/11/98 rewritten again again again again again again, added hit delta support. |
| | 3993 | // ChrisF 15/2/99 rewritten again again again again again again again, added fragging noise. |
| | 3994 | |
| | 3995 | void AlienIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, int wounds, SECTION_DATA *Section, VECTORCH *incoming) |
| | 3996 | { |
| | 3997 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3998 | |
| | 3999 | alienStatusPointer->Wounds |= wounds; |
| | 4000 | |
| | 4001 | alienStatusPointer->CanStand = !((alienStatusPointer->Wounds & (section_flag_left_leg | section_flag_right_leg)) |
| | 4002 | || ((alienStatusPointer->Wounds & section_flag_left_foot) && (alienStatusPointer->Wounds & section_flag_right_foot))); |
| | 4003 | |
| | 4004 | /* Can only climb if alien has both hands... */ |
| | 4005 | alienStatusPointer->CanClimb = !((alienStatusPointer->Wounds & section_flag_left_hand) || (alienStatusPointer->Wounds &
section_flag_right_hand)); |
| | 4006 | |
| | 4007 | //if(!(alienStatusPointer->CanStand && alienStatusPointer->CanClimb)) |
| | 4008 | |
| | 4009 | if(!alienStatusPointer->CanStand) |
| | 4010 | alienStatusPointer->IAmCrouched = 1; |
| | 4011 | |
| | 4012 | //if (incoming) printf("Alien hit from %d %d %d\n", incoming->vx, incoming->vy, incoming->vz); |
| | 4013 | |
| | 4014 | if(incoming && damage->ExplosivePower) |
| | 4015 | sbPtr->DynPtr->UseStandardGravity = 1; |
| | 4016 | |
| | 4017 | if (sbPtr->DamageBlock.Health <= 0) |
| | 4018 | { |
| | 4019 | if (AvP.PlayerType != I_Alien) |
| | 4020 | CurrentGameStats_CreatureKilled(sbPtr, Section); |
| | 4021 | |
| | 4022 | sbPtr->DynPtr->UseStandardGravity = 1; |
| | 4023 | KillAlien(sbPtr, wounds, damage, incoming); |
| | 4024 | } |
| | 4025 | else //if(!alienStatusPointer->unconscious) |
| | 4026 | { |
| | 4027 | if(0) |
| | 4028 | switch(alienStatusPointer->BehaviourState) |
| | 4029 | { |
| | 4030 | case ABS_Dormant: |
| | 4031 | Alien_Awaken(sbPtr); |
| | 4032 | break; |
| | 4033 | default: |
| | 4034 | if(NULL == alienStatusPointer->Target) |
| | 4035 | { |
| | 4036 | NPC_OBSTRUCTIONREPORT obstruction = {0, 0, 1, 0}; |
| | 4037 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 4038 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 4039 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 4040 | alienStatusPointer->StateTimer = NPC_AVOIDTIME; |
| | 4041 | //alienStatusPointer->BehaviourState = ABS_Retreat; |
| | 4042 | puts("no target"); |
| | 4043 | } |
| | 4044 | else if((FastRandom() & 32) < 11) |
| | 4045 | { |
| | 4046 | puts("Target"); |
| | 4047 | NPC_OBSTRUCTIONREPORT obstruction = {0, 0, 1, 0}; |
| | 4048 | NPC_InitMovementData(&alienStatusPointer->moveData); |
| | 4049 | NPCGetAvoidanceDirection(sbPtr, &alienStatusPointer->moveData.avoidanceDirn, &obstruction); |
| | 4050 | alienStatusPointer->BehaviourState = ABS_Avoidance; |
| | 4051 | alienStatusPointer->StateTimer = NPC_AVOIDTIME/8; |
| | 4052 | } |
| | 4053 | } |
| | 4054 | |
| | 4055 | if(!alienStatusPointer->CanStand) |
| | 4056 | SetAlienShapeAnimSequence_Core(sbPtr, HMSQT_AlienCrawl, ACSS_Crawl_Hurt, ONE_FIXED >> 1, (ONE_FIXED >> 2)); |
| | 4057 | |
| | 4058 | if(((alienStatusPointer->Wounds & section_flag_left_arm) && (alienStatusPointer->Wounds & section_flag_right_arm)) |
| | 4059 | || |
| | 4060 | ((alienStatusPointer->Wounds & section_flag_left_hand) && (alienStatusPointer->Wounds & section_flag_right_hand))) |
| | 4061 | { |
| | 4062 | alienStatusPointer->MaxSpeed = 800; |
| | 4063 | } |
| | 4064 | else |
| | 4065 | { |
| | 4066 | RecomputeAlienSpeed(sbPtr); |
| | 4067 | } |
| | 4068 | |
| | 4069 | /* Now, get anim speed. */ |
| | 4070 | |
| | 4071 | HMODEL_SEQUENCE_TYPES sequence_type = (HMODEL_SEQUENCE_TYPES)alienStatusPointer->HModelController.Sequence_Type; |
| | 4072 | |
| | 4073 | int subsequence = alienStatusPointer->HModelController.Sub_Sequence; |
| | 4074 | /* That is what the controller thinks the shape is playing. */ |
| | 4075 | |
| | 4076 | int factor = GetAlienSpeedFactor_ForSequence(sbPtr, sequence_type, subsequence); |
| | 4077 | int changespeed = 0; |
| | 4078 | |
| | 4079 | switch (alienStatusPointer->Type) |
| | 4080 | { |
| | 4081 | case Standard: |
| | 4082 | if (factor != ONE_FIXED) |
| | 4083 | changespeed = 1; |
| | 4084 | break; |
| | 4085 | case Predalien: |
| | 4086 | if (factor != PREDALIEN_SPEED_FACTOR) |
| | 4087 | changespeed = 1; |
| | 4088 | break; |
| | 4089 | case Praetorian: |
| | 4090 | if (factor != PRAETORIAN_SPEED_FACTOR) |
| | 4091 | changespeed = 1; |
| | 4092 | default: |
| | 4093 | break; |
| | 4094 | } |
| | 4095 | |
| | 4096 | if (changespeed) |
| | 4097 | { |
| | 4098 | /* ONE_FIXED implies we're playing an invariant length anim. */ |
| | 4099 | int newspeed = DIV_FIXED(alienStatusPointer->last_anim_length, factor); |
| | 4100 | |
| | 4101 | HModel_ChangeSpeed(&alienStatusPointer->HModelController, newspeed); |
| | 4102 | } |
| | 4103 | |
| | 4104 | if (alienStatusPointer->sound_mouth == SOUND_NOACTIVEINDEX) |
| | 4105 | { |
| | 4106 | int pitch = (FastRandom() & 255) - 128; |
| | 4107 | |
| | 4108 | PlayAlienSound((int)alienStatusPointer->Type, ASC_Scream_Hurt, pitch, &alienStatusPointer->sound_mouth,
&sbPtr->DynPtr->Position); |
| | 4109 | |
| | 4110 | if(NetworkPeer == AvP.PlayMode) |
| | 4111 | AddNetMsg_SpotAlienSound(ASC_Scream_Hurt, (int)alienStatusPointer->Type, pitch, &sbPtr->DynPtr->Position); |
| | 4112 | } |
| | 4113 | |
| | 4114 | if (TotalKineticDamage(damage) >= 10) |
| | 4115 | { |
| | 4116 | int frontback = 1; |
| | 4117 | |
| | 4118 | if (incoming && (incoming->vz >= 0)) |
| | 4119 | frontback = 0; |
| | 4120 | |
| | 4121 | if (frontback) |
| | 4122 | { |
| | 4123 | DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&alienStatusPointer->HModelController, "HitDelta"); |
| | 4124 | |
| | 4125 | /* Only do it from the front. */ |
| | 4126 | if (hitdelta && !hitdelta->Playing) |
| | 4127 | { |
| | 4128 | if(damage->ExplosivePower && (sbPtr->DynPtr->OrientMat.mat22 > 63000)) |
| | 4129 | { |
| | 4130 | if(!alienStatusPointer->IAmCrouched) |
| | 4131 | { |
| | 4132 | if ((Praetorian == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000)) |
| | 4133 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand,
(int)ASSS_Spin_Clockwise, -1, 0); |
| | 4134 | else |
| | 4135 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies,
-1, 0); |
| | 4136 | |
| | 4137 | alienStatusPointer->unconscious = ONE_FIXED * 5 + ( (FastRandom() & 7) * ONE_FIXED); |
| | 4138 | } |
| | 4139 | else if ((Standard == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000)) |
| | 4140 | { |
| | 4141 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienCrawl,
(int)ACSS_Boom_Fall_Back, ONE_FIXED, 0); |
| | 4142 | alienStatusPointer->unconscious = ONE_FIXED * 6 + ( (FastRandom() & 7) * ONE_FIXED); |
| | 4143 | } |
| | 4144 | } |
| | 4145 | else |
| | 4146 | { |
| | 4147 | /* A hierarchy with hit deltas! */ |
| | 4148 | int CrouchSubSequence; |
| | 4149 | int StandSubSequence; |
| | 4150 | |
| | 4151 | if (Section == NULL) |
| | 4152 | { |
| | 4153 | if ((FastRandom() & 65535) < 32767) |
| | 4154 | { |
| | 4155 | CrouchSubSequence = ACrSS_Hit_Left; |
| | 4156 | StandSubSequence = ASSS_Hit_Left; |
| | 4157 | } |
| | 4158 | else |
| | 4159 | { |
| | 4160 | CrouchSubSequence = ACrSS_Hit_Right; |
| | 4161 | StandSubSequence = ASSS_Hit_Right; |
| | 4162 | } |
| | 4163 | } |
| | 4164 | else if ((Section->sempai->flags & section_flag_left_arm) || (Section->sempai->flags & section_flag_left_hand)) |
| | 4165 | { |
| | 4166 | CrouchSubSequence = ACrSS_Hit_Left; |
| | 4167 | StandSubSequence = ASSS_Hit_Left; |
| | 4168 | } |
| | 4169 | else if ((Section->sempai->flags & section_flag_right_arm) || (Section->sempai->flags & section_flag_right_hand)) |
| | 4170 | { |
| | 4171 | CrouchSubSequence = ACrSS_Hit_Right; |
| | 4172 | StandSubSequence = ASSS_Hit_Right; |
| | 4173 | } |
| | 4174 | else |
| | 4175 | { |
| | 4176 | /* Chest or misc. hit. */ |
| | 4177 | if ((FastRandom() & 65535) < 32767) |
| | 4178 | { |
| | 4179 | CrouchSubSequence = ACrSS_Hit_Left; |
| | 4180 | StandSubSequence = ASSS_Hit_Left; |
| | 4181 | } |
| | 4182 | else |
| | 4183 | { |
| | 4184 | CrouchSubSequence = ACrSS_Hit_Right; |
| | 4185 | StandSubSequence = ASSS_Hit_Right; |
| | 4186 | } |
| | 4187 | } |
| | 4188 | |
| | 4189 | if(alienStatusPointer->IAmCrouched) |
| | 4190 | { |
| | 4191 | if (HModelSequence_Exists(&alienStatusPointer->HModelController, (int)HMSQT_AlienCrouch, CrouchSubSequence)) |
| | 4192 | Start_Delta_Sequence(hitdelta, (int)HMSQT_AlienCrouch, CrouchSubSequence, -1); |
| | 4193 | } |
| | 4194 | else |
| | 4195 | { |
| | 4196 | if (HModelSequence_Exists(&alienStatusPointer->HModelController, (int)HMSQT_AlienStand, StandSubSequence)) |
| | 4197 | Start_Delta_Sequence(hitdelta, (int)HMSQT_AlienStand, StandSubSequence, -1); |
| | 4198 | } |
| | 4199 | |
| | 4200 | hitdelta->Playing = 1; |
| | 4201 | } |
| | 4202 | } |
| | 4203 | else if(damage->ExplosivePower && (sbPtr->DynPtr->OrientMat.mat22 > 63000)) |
| | 4204 | { |
| | 4205 | if(!alienStatusPointer->IAmCrouched) |
| | 4206 | { |
| | 4207 | if ((Praetorian == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000)) |
| | 4208 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED>>3), (int)HMSQT_AlienStand,
(int)ASSS_Spin_Clockwise, -1, 0); |
| | 4209 | else |
| | 4210 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 2), (int)HMSQT_AlienStand, (int)ASSS_Dies, -1,
0); |
| | 4211 | |
| | 4212 | alienStatusPointer->unconscious = ONE_FIXED * 5 + ( (FastRandom() & 7) * ONE_FIXED); |
| | 4213 | } |
| | 4214 | else if ((Standard == alienStatusPointer->Type) && ((FastRandom() & 65535) < 30000)) |
| | 4215 | { |
| | 4216 | InitHModelTweening(&alienStatusPointer->HModelController, (ONE_FIXED >> 4), (int)HMSQT_AlienCrawl,
(int)ACSS_Boom_Fall_Back, ONE_FIXED, 0); |
| | 4217 | alienStatusPointer->unconscious = ONE_FIXED * 6 + ( (FastRandom() & 7) * ONE_FIXED); |
| | 4218 | } |
| | 4219 | } |
| | 4220 | } |
| | 4221 | } |
| | 4222 | } |
| | 4223 | } |
| | 4224 | |
| | 4225 | /*--------------------** |
| | 4226 | ** Loading and Saving ** |
| | 4227 | **--------------------*/ |
| | 4228 | #include "savegame.h" |
| | 4229 | typedef struct alien_save_block |
| | 4230 | { |
| | 4231 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 4232 | |
| | 4233 | ALIEN_TYPE Type; |
| | 4234 | int GibbFactor; |
| | 4235 | int Wounds; |
| | 4236 | int last_anim_length; |
| | 4237 | ALIEN_BHSTATE BehaviourState; |
| | 4238 | |
| | 4239 | int incidentFlag; |
| | 4240 | int incidentTimer; |
| | 4241 | |
| | 4242 | int CurveRadius; |
| | 4243 | int CurveLength; |
| | 4244 | int CurveTimeOut; |
| | 4245 | int StateTimer; |
| | 4246 | int IAmCrouched; |
| | 4247 | int CurrentLightAtAlien; |
| | 4248 | int unconscious; |
| | 4249 | int CanStand; |
| | 4250 | int CanClimb; |
| | 4251 | int huntingModuleIndex; |
| | 4252 | int currentAttackCode; |
| | 4253 | // NPC_MOVEMENTDATA moveData; |
| | 4254 | NPC_WANDERDATA wanderData; |
| | 4255 | |
| | 4256 | // HMODELCONTROLLER HModelController; |
| | 4257 | |
| | 4258 | // STRATEGYBLOCK* generator_sbptr;//0 unless created by a generator |
| | 4259 | |
| | 4260 | char Target_SBname[SB_NAME_LENGTH]; |
| | 4261 | char Generator_SBname[SB_NAME_LENGTH]; |
| | 4262 | |
| | 4263 | //strategyblock stuff |
| | 4264 | DAMAGEBLOCK DamageBlock; |
| | 4265 | DYNAMICSBLOCK dynamics; |
| | 4266 | |
| | 4267 | } ALIEN_SAVE_BLOCK; |
| | 4268 | |
| | 4269 | //defines for load/save macros |
| | 4270 | #define SAVELOAD_BLOCK block |
| | 4271 | #define SAVELOAD_BEHAV alienStatusPointer |
| | 4272 | |
| | 4273 | void LoadStrategy_Alien(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 4274 | { |
| | 4275 | ALIEN_STATUS_BLOCK* alienStatusPointer; |
| | 4276 | ALIEN_SAVE_BLOCK* block = (ALIEN_SAVE_BLOCK*) header; |
| | 4277 | |
| | 4278 | //check the size of the save block |
| | 4279 | if(header->size != sizeof(*block)) |
| | 4280 | return; |
| | 4281 | |
| | 4282 | //find the existing strategy block |
| | 4283 | STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname); |
| | 4284 | |
| | 4285 | if(sbPtr) |
| | 4286 | { |
| | 4287 | //make sure the strategy found is of the right type |
| | 4288 | if(sbPtr->type != I_BehaviourAlien) |
| | 4289 | return; |
| | 4290 | } |
| | 4291 | else |
| | 4292 | { |
| | 4293 | //we will have to generate an alien then |
| | 4294 | TOOLS_DATA_ALIEN tda; |
| | 4295 | |
| | 4296 | //make sure the alien is in a module |
| | 4297 | if(!ModuleFromPosition(&block->dynamics.Position, NULL)) |
| | 4298 | return; |
| | 4299 | |
| | 4300 | sbPtr = CreateActiveStrategyBlock(I_BehaviourAlien); |
| | 4301 | |
| | 4302 | if(!sbPtr) |
| | 4303 | return; |
| | 4304 | |
| | 4305 | sbPtr->maintainVisibility = 1; |
| | 4306 | COPY_NAME(sbPtr->SBname,block->header.SBname); |
| | 4307 | |
| | 4308 | //create using a fake tools data |
| | 4309 | tda.position = block->dynamics.Position; |
| | 4310 | COPY_NAME(tda.nameID, block->header.SBname); |
| | 4311 | COPY_NAME(tda.death_target_ID, Null_Name); |
| | 4312 | tda.type = block->Type; |
| | 4313 | tda.start_inactive = 0; |
| | 4314 | |
| | 4315 | tda.starteuler.EulerX = tda.starteuler.EulerY = tda.starteuler.EulerZ = 0; |
| | 4316 | |
| | 4317 | EnableBehaviourType(sbPtr, &tda); |
| | 4318 | } |
| | 4319 | |
| | 4320 | alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->dataptr; |
| | 4321 | |
| | 4322 | //start copying stuff |
| | 4323 | |
| | 4324 | COPYELEMENT_LOAD(Type) |
| | 4325 | COPYELEMENT_LOAD(GibbFactor) |
| | 4326 | COPYELEMENT_LOAD(Wounds) |
| | 4327 | COPYELEMENT_LOAD(last_anim_length) |
| | 4328 | COPYELEMENT_LOAD(BehaviourState) |
| | 4329 | COPYELEMENT_LOAD(incidentFlag) |
| | 4330 | COPYELEMENT_LOAD(incidentTimer) |
| | 4331 | COPYELEMENT_LOAD(CurveRadius) |
| | 4332 | COPYELEMENT_LOAD(CurveLength) |
| | 4333 | COPYELEMENT_LOAD(CurveTimeOut) |
| | 4334 | COPYELEMENT_LOAD(StateTimer) |
| | 4335 | COPYELEMENT_LOAD(IAmCrouched) |
| | 4336 | COPYELEMENT_LOAD(CurrentLightAtAlien) |
| | 4337 | COPYELEMENT_LOAD(unconscious) |
| | 4338 | COPYELEMENT_LOAD(CanStand) |
| | 4339 | COPYELEMENT_LOAD(CanClimb) |
| | 4340 | COPYELEMENT_LOAD(wanderData) |
| | 4341 | |
| | 4342 | //load target |
| | 4343 | COPY_NAME(alienStatusPointer->Target_SBname,block->Target_SBname); |
| | 4344 | alienStatusPointer->Target = FindSBWithName(alienStatusPointer->Target_SBname); |
| | 4345 | |
| | 4346 | //load hunting module |
| | 4347 | if(block->huntingModuleIndex >= 0 && block->huntingModuleIndex < AIModuleArraySize) |
| | 4348 | alienStatusPointer->huntingModule = &AIModuleArray[block->huntingModuleIndex]; |
| | 4349 | else |
| | 4350 | alienStatusPointer->huntingModule = NULL; |
| | 4351 | |
| | 4352 | //get the alien's attack from the attack code |
| | 4353 | alienStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode); |
| | 4354 | |
| | 4355 | *sbPtr->DynPtr = block->dynamics; |
| | 4356 | sbPtr->DamageBlock = block->DamageBlock; |
| | 4357 | |
| | 4358 | //find the alien's generator |
| | 4359 | alienStatusPointer->generator_sbptr = FindSBWithName(block->Generator_SBname); |
| | 4360 | |
| | 4361 | //load the aliens hierarchy |
| | 4362 | { |
| | 4363 | SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); |
| | 4364 | |
| | 4365 | if(hier_header) |
| | 4366 | LoadHierarchy(hier_header,&alienStatusPointer->HModelController); |
| | 4367 | } |
| | 4368 | |
| | 4369 | Load_SoundState(&alienStatusPointer->soundOnFire); |
| | 4370 | Load_SoundState(&alienStatusPointer->sound_mouth); |
| | 4371 | } |
| | 4372 | |
| | 4373 | void SaveStrategy_Alien(STRATEGYBLOCK* sbPtr) |
| | 4374 | { |
| | 4375 | ALIEN_SAVE_BLOCK *block; |
| | 4376 | ALIEN_STATUS_BLOCK* alienStatusPointer = (ALIEN_STATUS_BLOCK*)sbPtr->dataptr; |
| | 4377 | |
| | 4378 | GET_STRATEGY_SAVE_BLOCK(block,sbPtr); |
| | 4379 | |
| | 4380 | //start copying stuff |
| | 4381 | |
| | 4382 | COPYELEMENT_SAVE(Type) |
| | 4383 | COPYELEMENT_SAVE(GibbFactor) |
| | 4384 | COPYELEMENT_SAVE(Wounds) |
| | 4385 | COPYELEMENT_SAVE(last_anim_length) |
| | 4386 | COPYELEMENT_SAVE(BehaviourState) |
| | 4387 | COPYELEMENT_SAVE(incidentFlag) |
| | 4388 | COPYELEMENT_SAVE(incidentTimer) |
| | 4389 | COPYELEMENT_SAVE(CurveRadius) |
| | 4390 | COPYELEMENT_SAVE(CurveLength) |
| | 4391 | COPYELEMENT_SAVE(CurveTimeOut) |
| | 4392 | COPYELEMENT_SAVE(StateTimer) |
| | 4393 | COPYELEMENT_SAVE(IAmCrouched) |
| | 4394 | COPYELEMENT_SAVE(CurrentLightAtAlien) |
| | 4395 | COPYELEMENT_LOAD(unconscious) |
| | 4396 | COPYELEMENT_LOAD(CanStand) |
| | 4397 | COPYELEMENT_LOAD(CanClimb) |
| | 4398 | COPYELEMENT_SAVE(wanderData) |
| | 4399 | |
| | 4400 | //save target |
| | 4401 | COPY_NAME(block->Target_SBname,alienStatusPointer->Target_SBname); |
| | 4402 | |
| | 4403 | //save hunting module |
| | 4404 | if(alienStatusPointer->huntingModule) |
| | 4405 | block->huntingModuleIndex = alienStatusPointer->huntingModule->m_index; |
| | 4406 | else |
| | 4407 | block->huntingModuleIndex = -1; |
| | 4408 | |
| | 4409 | //save attack code |
| | 4410 | if(alienStatusPointer->current_attack) |
| | 4411 | block->currentAttackCode = alienStatusPointer->current_attack->Unique_Code; |
| | 4412 | else |
| | 4413 | block->currentAttackCode = -1; |
| | 4414 | |
| | 4415 | //save the alien's generator name |
| | 4416 | if(alienStatusPointer->generator_sbptr) |
| | 4417 | { |
| | 4418 | COPY_NAME(block->Generator_SBname, alienStatusPointer->generator_sbptr->SBname); |
| | 4419 | } |
| | 4420 | else |
| | 4421 | { |
| | 4422 | COPY_NAME(block->Generator_SBname, Null_Name); |
| | 4423 | } |
| | 4424 | |
| | 4425 | block->dynamics = *sbPtr->DynPtr; |
| | 4426 | block->dynamics.CollisionReportPtr = 0; |
| | 4427 | block->DamageBlock = sbPtr->DamageBlock; |
| | 4428 | |
| | 4429 | //save the aliens hierarchy |
| | 4430 | SaveHierarchy(&alienStatusPointer->HModelController); |
| | 4431 | |
| | 4432 | Save_SoundState(&alienStatusPointer->soundOnFire); |
| | 4433 | Save_SoundState(&alienStatusPointer->sound_mouth); |
| | 4434 | } |