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