| | 1 | #include "system.h" |
| | 2 | #include "prototyp.h" |
| | 3 | #include "stratdef.h" |
| | 4 | #include "pfarlocs.h" |
| | 5 | #include "pheromon.h" |
| | 6 | #include "bh_ais.h" |
| | 7 | #include "bh_types.h" |
| | 8 | #include "bh_far.h" |
| | 9 | #include "npc_marine.h" |
| | 10 | #include "npc_alien.h" |
| | 11 | #include "weapons.h" |
| | 12 | #include "weaponbehaviour.h" |
| | 13 | #include "los.h" |
| | 14 | #include "targeting.h" |
| | 15 | #include "pldghost.h" |
| | 16 | #include "generator.h" |
| | 17 | #include "corpse.h" |
| | 18 | #include "npc_dummy.h" |
| | 19 | #include "scream.h" |
| | 20 | #include "extents.h" |
| | 21 | #include "game_statistics.h" |
| | 22 | #include <assert.h> |
| | 23 | #include <stdlib.h> |
| | 24 | #include <stdio.h> |
| | 25 | #include <string.h> |
| | 26 | |
| | 27 | extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); |
| | 28 | extern uint8_t Null_Name[8]; |
| | 29 | extern const VECTORCH null_vec; |
| | 30 | |
| | 31 | static const PREDATOR_WEAPON_DATA *GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id); |
| | 32 | |
| | 33 | extern void NPC_GetBimbleTarget(STRATEGYBLOCK *sbPtr,VECTORCH *output); |
| | 34 | |
| | 35 | /* Patrick 21/8/97 -------------------------------------------------- |
| | 36 | Predator personalisation parameters: |
| | 37 | format: health,speed,defenceHealth,useShoulderCannon, |
| | 38 | timebetweenRangedAttacks,maxShotsPerRangedAttack, |
| | 39 | timeBetweenEachShot,closeAttackDamage,chanceOfCloaking(1-8) |
| | 40 | ---------------------------------------------------------------------*/ |
| | 41 | static const PREDATOR_PERSONALPARAMETERS predatorCV[] = |
| | 42 | { |
| | 43 | {800,8000,200,1,(2*ONE_FIXED),3,(ONE_FIXED),25,200,2}, |
| | 44 | {1000,7000,500,0,(ONE_FIXED),1,(ONE_FIXED>>1),20,400,4}, |
| | 45 | {600,10000,10,1,(4*ONE_FIXED),2,(ONE_FIXED>>1),50,300,8}, |
| | 46 | {600,8000,200,0,(2*ONE_FIXED),2,(ONE_FIXED),25,500,2}, |
| | 47 | {1000,9000,100,1,(ONE_FIXED),1,(ONE_FIXED>>1),35,400,6}, |
| | 48 | }; |
| | 49 | |
| | 50 | static enum AMMO_ID GetPredatorAttackDamageType(STRATEGYBLOCK *sbPtr,int flagnum) |
| | 51 | { |
| | 52 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 53 | |
| | 54 | return (predatorStatusPointer->current_attack == NULL) ? AMMO_NONE : predatorStatusPointer->current_attack->flag_damage[flagnum]; |
| | 55 | } |
| | 56 | |
| | 57 | static int make_new_predator(STRATEGYBLOCK *sbPtr) |
| | 58 | { |
| | 59 | sbPtr->dataptr = malloc(sizeof(PREDATOR_STATUS_BLOCK)); |
| | 60 | sbPtr->maintainVisibility = 1; |
| | 61 | sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL); |
| | 62 | |
| | 63 | if(NULL == sbPtr->dataptr) |
| | 64 | { |
| | 65 | RemoveBehaviourStrategy(sbPtr); |
| | 66 | return 0; |
| | 67 | } |
| | 68 | |
| | 69 | { |
| | 70 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator]; |
| | 71 | sbPtr->DamageBlock = NpcData->StartingStats; |
| | 72 | sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT; |
| | 73 | sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT; |
| | 74 | } |
| | 75 | |
| | 76 | PREDATOR_STATUS_BLOCK *new_predator = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 77 | |
| | 78 | NPC_InitMovementData(&new_predator->moveData); |
| | 79 | NPC_InitWanderData(&new_predator->wanderData); |
| | 80 | |
| | 81 | new_predator->HModelController.Deltas = NULL; |
| | 82 | new_predator->HModelController.Root_Section = NULL; |
| | 83 | new_predator->HModelController.section_data = NULL; |
| | 84 | new_predator->personalNumber = FastRandom() % 5; |
| | 85 | new_predator->health = predatorCV[new_predator->personalNumber].startingHealth; |
| | 86 | new_predator->behaviourState = PBS_Wandering; |
| | 87 | new_predator->lastState = PBS_Wandering; |
| | 88 | |
| | 89 | new_predator->stateTimer = PRED_FAR_MOVE_TIME; |
| | 90 | new_predator->internalState = 0; |
| | 91 | new_predator->patience = PRED_PATIENCE_TIME; |
| | 92 | new_predator->enableSwap = 0; |
| | 93 | new_predator->enableTaunt = 0; |
| | 94 | new_predator->weaponTarget.vx = 0; |
| | 95 | new_predator->weaponTarget.vy = 0; |
| | 96 | new_predator->weaponTarget.vz = 0; |
| | 97 | new_predator->volleySize = 0; |
| | 98 | |
| | 99 | new_predator->obstruction.environment = 0; |
| | 100 | new_predator->obstruction.destructableObject = 0; |
| | 101 | new_predator->obstruction.otherCharacter = 0; |
| | 102 | new_predator->obstruction.anySingleObstruction = 0; |
| | 103 | |
| | 104 | Initialise_AvoidanceManager(&new_predator->avoidanceManager); |
| | 105 | InitWaypointManager(&new_predator->waypointManager); |
| | 106 | |
| | 107 | new_predator->IAmCrouched = 0; |
| | 108 | new_predator->nearSpeed = predatorCV[new_predator->personalNumber].speed; |
| | 109 | new_predator->GibbFactor = 0; |
| | 110 | new_predator->incidentFlag = 0; |
| | 111 | new_predator->incidentTimer = 0; |
| | 112 | |
| | 113 | new_predator->MeleeWeapon = GetThisNPCPredatorWeapon((FastRandom() & 1) ? PNPCW_Wristblade : PNPCW_Staff); |
| | 114 | new_predator->SecondaryWeapon = (FastRandom() & 1) ? PNPCW_Pistol : PNPCW_Speargun; |
| | 115 | new_predator->Selected_Weapon = new_predator->MeleeWeapon; |
| | 116 | |
| | 117 | new_predator->ChangeToWeapon = PNPCW_End; |
| | 118 | new_predator->current_attack = NULL; |
| | 119 | |
| | 120 | new_predator->closets_target = NULL; |
| | 121 | new_predator->Targets[0] = NULL; |
| | 122 | new_predator->Targets[1] = NULL; |
| | 123 | new_predator->Targets[2] = NULL; |
| | 124 | new_predator->Targets[3] = NULL; |
| | 125 | |
| | 126 | COPY_NAME(new_predator->Target_SBname, Null_Name); |
| | 127 | new_predator->soundHandle = SOUND_NOACTIVEINDEX; |
| | 128 | |
| | 129 | new_predator->CloakStatus = PCLOAK_Off; |
| | 130 | new_predator->CloakingEffectiveness = 0; |
| | 131 | new_predator->CloakTimer = 0; |
| | 132 | |
| | 133 | new_predator->Pred_Laser_Sight.TargetID = 0; |
| | 134 | new_predator->Pred_Laser_Sight.DotIsOnPlayer = 0; |
| | 135 | new_predator->Pred_Laser_Sight.LightSource = null_vec; |
| | 136 | new_predator->Pred_Laser_Sight.Normal[0] = null_vec; |
| | 137 | new_predator->Pred_Laser_Sight.Normal[1] = null_vec; |
| | 138 | new_predator->Pred_Laser_Sight.Normal[2] = null_vec; |
| | 139 | |
| | 140 | new_predator->Pred_Laser_Sight.Position[0] = null_vec; |
| | 141 | new_predator->Pred_Laser_Sight.Position[1] = null_vec; |
| | 142 | new_predator->Pred_Laser_Sight.Position[2] = null_vec; |
| | 143 | |
| | 144 | new_predator->Pred_Laser_On = 0; |
| | 145 | new_predator->Angry = 0; |
| | 146 | new_predator->RifleArrows = (PNPCW_Speargun == new_predator->SecondaryWeapon) ? 20 : 0; |
| | 147 | new_predator->path = -1; |
| | 148 | new_predator->stepnumber = -1; |
| | 149 | new_predator->missionmodule = NULL; |
| | 150 | new_predator->fearmodule = NULL; |
| | 151 | |
| | 152 | //a generated predator won't have a death target |
| | 153 | { |
| | 154 | int i; |
| | 155 | for(i=0;i<SB_NAME_LENGTH;i++) |
| | 156 | new_predator->death_target_ID[i] = 0; |
| | 157 | } |
| | 158 | |
| | 159 | new_predator->death_target_sbptr = NULL; |
| | 160 | new_predator->death_target_request = 0; |
| | 161 | |
| | 162 | SECTION *root_section = GetNamedHierarchyFromLibrary("hnpcpredator", new_predator->Selected_Weapon->HierarchyName); |
| | 163 | |
| | 164 | if (!root_section || !sbPtr->containingModule) |
| | 165 | { |
| | 166 | RemoveBehaviourStrategy(sbPtr); |
| | 167 | return 0; |
| | 168 | } |
| | 169 | |
| | 170 | Create_HModel(&new_predator->HModelController, root_section); |
| | 171 | InitHModelSequence(&new_predator->HModelController, 0, 0, ONE_FIXED); |
| | 172 | |
| | 173 | if (new_predator->Selected_Weapon->UseElevation) |
| | 174 | { |
| | 175 | DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_predator->HModelController, "Elevation", (int)HMSQT_PredatorStand,
(int)PSSS_Elevation, 0); |
| | 176 | assert(delta); |
| | 177 | delta->timer = 32767; |
| | 178 | } |
| | 179 | |
| | 180 | new_predator->My_Elevation_Section = GetThisSectionData(new_predator->HModelController.section_data,
new_predator->Selected_Weapon->ElevationName); |
| | 181 | |
| | 182 | if (HModelSequence_Exists(&new_predator->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_HitChestFront)) |
| | 183 | { |
| | 184 | DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_predator->HModelController, "HitDelta", (int)HMSQT_PredatorStand,
(int)PSSS_HitChestFront, -1); |
| | 185 | assert(delta); |
| | 186 | delta->Playing = 0; |
| | 187 | } |
| | 188 | |
| | 189 | ProveHModel_Far(&new_predator->HModelController, sbPtr); |
| | 190 | |
| | 191 | return 1; |
| | 192 | } |
| | 193 | |
| | 194 | static void PredatorCloakOn(PREDATOR_STATUS_BLOCK *predStatus) |
| | 195 | { |
| | 196 | switch(predStatus->CloakStatus) |
| | 197 | { |
| | 198 | case PCLOAK_Activating: |
| | 199 | case PCLOAK_On: |
| | 200 | break; |
| | 201 | case PCLOAK_Deactivating: |
| | 202 | predStatus->CloakStatus = PCLOAK_Activating; |
| | 203 | break; /* Don't reset timer. */ |
| | 204 | default: |
| | 205 | { |
| | 206 | /* Cloak ust be Off. */ |
| | 207 | predStatus->CloakStatus = PCLOAK_Activating; |
| | 208 | predStatus->CloakTimer = ONE_FIXED-1; |
| | 209 | } |
| | 210 | } |
| | 211 | } |
| | 212 | |
| | 213 | static void PredatorCloakOff(PREDATOR_STATUS_BLOCK *predStatus) |
| | 214 | { |
| | 215 | switch(predStatus->CloakStatus) |
| | 216 | { |
| | 217 | case PCLOAK_Deactivating: |
| | 218 | case PCLOAK_Off: |
| | 219 | break; |
| | 220 | case PCLOAK_Activating: |
| | 221 | predStatus->CloakStatus = PCLOAK_Deactivating; |
| | 222 | break; /* Don't reset timer. */ |
| | 223 | default: |
| | 224 | { |
| | 225 | /* Cloak must be On. */ |
| | 226 | predStatus->CloakStatus = PCLOAK_Deactivating; |
| | 227 | predStatus->CloakTimer = 0; |
| | 228 | } |
| | 229 | } |
| | 230 | } |
| | 231 | |
| | 232 | static void DoPredatorCloak(PREDATOR_STATUS_BLOCK *predStatus, DYNAMICSBLOCK *dynPtr) |
| | 233 | { |
| | 234 | switch(predStatus->CloakStatus) |
| | 235 | { |
| | 236 | case PCLOAK_On: |
| | 237 | case PCLOAK_Off: |
| | 238 | break; /* do nothing */ |
| | 239 | case PCLOAK_Activating: |
| | 240 | { |
| | 241 | predStatus->CloakTimer -= NormalFrameTime; |
| | 242 | |
| | 243 | if(predStatus->CloakTimer <= 0) |
| | 244 | { |
| | 245 | predStatus->CloakTimer = 0; |
| | 246 | predStatus->CloakStatus = PCLOAK_On; |
| | 247 | } |
| | 248 | } |
| | 249 | break; |
| | 250 | case PCLOAK_Deactivating: |
| | 251 | { |
| | 252 | predStatus->CloakTimer += NormalFrameTime; |
| | 253 | |
| | 254 | if(predStatus->CloakTimer >= ONE_FIXED) |
| | 255 | { |
| | 256 | predStatus->CloakTimer = 0; |
| | 257 | predStatus->CloakStatus = PCLOAK_Off; |
| | 258 | } |
| | 259 | } |
| | 260 | break; |
| | 261 | default: |
| | 262 | assert(1==0); |
| | 263 | break; |
| | 264 | } |
| | 265 | |
| | 266 | if(predStatus->CloakStatus != PCLOAK_Off) |
| | 267 | { |
| | 268 | VECTORCH velocity; |
| | 269 | |
| | 270 | velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; |
| | 271 | velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; |
| | 272 | velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; |
| | 273 | |
| | 274 | int maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*4, NormalFrameTime); |
| | 275 | |
| | 276 | if (maxPossibleEffectiveness < 0) |
| | 277 | maxPossibleEffectiveness = 0; |
| | 278 | |
| | 279 | predStatus->CloakingEffectiveness += NormalFrameTime; |
| | 280 | |
| | 281 | if (predStatus->CloakingEffectiveness > maxPossibleEffectiveness) |
| | 282 | predStatus->CloakingEffectiveness = maxPossibleEffectiveness; |
| | 283 | } |
| | 284 | else |
| | 285 | { |
| | 286 | predStatus->CloakingEffectiveness -= NormalFrameTime; |
| | 287 | |
| | 288 | if (predStatus->CloakingEffectiveness < 0) |
| | 289 | predStatus->CloakingEffectiveness = 0; |
| | 290 | } |
| | 291 | |
| | 292 | //printf("cloaking effectiveness %d\n", predStatus->CloakingEffectiveness); |
| | 293 | } |
| | 294 | |
| | 295 | static void PredatorNearDamageShell(STRATEGYBLOCK *sbPtr) |
| | 296 | { |
| | 297 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 298 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 299 | |
| | 300 | /* Damage shell! */ |
| | 301 | int workingflags = predatorStatusPointer->HModelController.keyframe_flags >> 1; |
| | 302 | int flagnum = 0; |
| | 303 | int dist = VectorDistance(&dynPtr->Position, &predatorStatusPointer->closets_target->DynPtr->Position); |
| | 304 | int dodamage = (dist <= predatorStatusPointer->MeleeWeapon->MaxRange); |
| | 305 | int a = 0; |
| | 306 | |
| | 307 | for (; a < NUM_ATTACKFLAGS; a++) |
| | 308 | { |
| | 309 | if (workingflags & 1) |
| | 310 | { |
| | 311 | /* Oops, check range first. */ |
| | 312 | if (dodamage) |
| | 313 | { |
| | 314 | if (predatorStatusPointer->closets_target->DisplayBlock) |
| | 315 | { |
| | 316 | VECTORCH rel_pos,attack_dir; |
| | 317 | |
| | 318 | rel_pos.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 319 | rel_pos.vy = predatorStatusPointer->closets_target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy; |
| | 320 | rel_pos.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 321 | |
| | 322 | GetDirectionOfAttack(predatorStatusPointer->closets_target, &rel_pos, &attack_dir); |
| | 323 | |
| | 324 | if (predatorStatusPointer->closets_target->DisplayBlock->HModelControlBlock) |
| | 325 | HtoHDamageToHModel(predatorStatusPointer->closets_target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage, ONE_FIXED, sbPtr,
&attack_dir); |
| | 326 | else |
| | 327 | CauseDamageToObject(predatorStatusPointer->closets_target,&TemplateAmmo[GetPredatorAttackDamageType(sbPtr,flagnum)].MaxDamage,
ONE_FIXED,&attack_dir); |
| | 328 | } |
| | 329 | else |
| | 330 | { |
| | 331 | VECTORCH rel_pos, attack_dir; |
| | 332 | |
| | 333 | rel_pos.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 334 | rel_pos.vy = predatorStatusPointer->closets_target->DynPtr->Position.vy - sbPtr->DynPtr->Position.vy; |
| | 335 | rel_pos.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 336 | |
| | 337 | GetDirectionOfAttack(predatorStatusPointer->closets_target, &rel_pos, &attack_dir); |
| | 338 | |
| | 339 | CauseDamageToObject(predatorStatusPointer->closets_target, &TemplateAmmo[GetPredatorAttackDamageType(sbPtr, flagnum)].MaxDamage, ONE_FIXED,
&attack_dir); |
| | 340 | } |
| | 341 | } |
| | 342 | |
| | 343 | PlayPredatorSound(0, PSC_Swipe, 0, NULL, &sbPtr->DynPtr->Position); |
| | 344 | } |
| | 345 | /* Prepare next flag. */ |
| | 346 | workingflags >>= 1; |
| | 347 | flagnum++; |
| | 348 | } |
| | 349 | } |
| | 350 | |
| | 351 | static void SetPredatorAnimationSequence(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweening) |
| | 352 | { |
| | 353 | assert(sbPtr); |
| | 354 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 355 | assert(predatorStatusPointer); |
| | 356 | |
| | 357 | assert(length != 0); |
| | 358 | |
| | 359 | if (tweening <= 0) |
| | 360 | InitHModelSequence(&predatorStatusPointer->HModelController, (int)type, subtype, length); |
| | 361 | else |
| | 362 | InitHModelTweening(&predatorStatusPointer->HModelController, tweening, (int)type,subtype,length, 1); |
| | 363 | } |
| | 364 | |
| | 365 | static int PredatorShouldBeCrawling(STRATEGYBLOCK *sbPtr) |
| | 366 | { |
| | 367 | return (sbPtr->containingModule->m_flags & MODULEFLAG_AIRDUCT); |
| | 368 | } |
| | 369 | |
| | 370 | static void CentrePredatorElevation(STRATEGYBLOCK *sbPtr) |
| | 371 | { |
| | 372 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 373 | |
| | 374 | if (predatorStatusPointer->Selected_Weapon->UseElevation) |
| | 375 | { |
| | 376 | DELTA_CONTROLLER *elevation_controller = Get_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation"); |
| | 377 | |
| | 378 | if (elevation_controller) |
| | 379 | { |
| | 380 | /* You can't be too careful with swap weapon stuff...? */ |
| | 381 | elevation_controller->timer = 32767; |
| | 382 | } |
| | 383 | } |
| | 384 | } |
| | 385 | |
| | 386 | void MakePredatorNear(STRATEGYBLOCK *sbPtr) |
| | 387 | { |
| | 388 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 389 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 390 | assert(sbPtr->DisplayBlock == NULL); |
| | 391 | |
| | 392 | DISPLAYBLOCK *dPtr = CreateActiveObject(); |
| | 393 | |
| | 394 | if(dPtr == NULL) |
| | 395 | return; /* cannot allocate displayblock, so leave far */ |
| | 396 | |
| | 397 | sbPtr->DisplayBlock = dPtr; |
| | 398 | dPtr->ObStrategyBlock = sbPtr; |
| | 399 | |
| | 400 | /* need to initialise positional information in the new display block */ |
| | 401 | dPtr->ObWorld = dynPtr->Position; |
| | 402 | dPtr->ObEuler = dynPtr->OrientEuler; |
| | 403 | dPtr->ObMat = dynPtr->OrientMat; |
| | 404 | |
| | 405 | predatorStatusPointer->weaponTarget.vx = predatorStatusPointer->weaponTarget.vy = predatorStatusPointer->weaponTarget.vz = 0; |
| | 406 | predatorStatusPointer->volleySize = 0; |
| | 407 | predatorStatusPointer->CloakStatus = PCLOAK_Off; |
| | 408 | predatorStatusPointer->CloakingEffectiveness = 0; |
| | 409 | predatorStatusPointer->CloakTimer = 0; |
| | 410 | |
| | 411 | /* regenerate health (before deciding whether to attack or defend) */ |
| | 412 | if(predatorStatusPointer->health < predatorCV[predatorStatusPointer->personalNumber].startingHealth) |
| | 413 | { |
| | 414 | predatorStatusPointer->health += predatorCV[predatorStatusPointer->personalNumber].regenerationUnit; |
| | 415 | |
| | 416 | if(predatorStatusPointer->health > predatorCV[predatorStatusPointer->personalNumber].startingHealth) |
| | 417 | predatorStatusPointer->health = predatorCV[predatorStatusPointer->personalNumber].startingHealth; |
| | 418 | } |
| | 419 | |
| | 420 | dPtr->HModelControlBlock = &predatorStatusPointer->HModelController; |
| | 421 | |
| | 422 | CentrePredatorElevation(sbPtr); |
| | 423 | |
| | 424 | ProveHModel(dPtr->HModelControlBlock, dPtr); |
| | 425 | |
| | 426 | predatorStatusPointer->IAmCrouched = PredatorShouldBeCrawling(sbPtr); |
| | 427 | |
| | 428 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 429 | |
| | 430 | switch(predatorStatusPointer->behaviourState) |
| | 431 | { |
| | 432 | case PBS_Recovering: |
| | 433 | { |
| | 434 | if(predatorStatusPointer->IAmCrouched) |
| | 435 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); |
| | 436 | else |
| | 437 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); |
| | 438 | } |
| | 439 | break; |
| | 440 | case PBS_SwapWeapon: |
| | 441 | case PBS_SelfDestruct: |
| | 442 | break; |
| | 443 | default: |
| | 444 | { |
| | 445 | if(predatorStatusPointer->IAmCrouched) |
| | 446 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); |
| | 447 | else |
| | 448 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); |
| | 449 | } |
| | 450 | } |
| | 451 | } |
| | 452 | |
| | 453 | static void CreatePredoBot(VECTORCH *position) |
| | 454 | { |
| | 455 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourPredator); |
| | 456 | |
| | 457 | if(NULL != sbPtr) |
| | 458 | { |
| | 459 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 460 | |
| | 461 | if(sbPtr->DynPtr) |
| | 462 | { |
| | 463 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 464 | dynPtr->PrevPosition = dynPtr->Position = *position; |
| | 465 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 466 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 467 | dynPtr->Mass = 180; |
| | 468 | make_new_predator(sbPtr); |
| | 469 | AssignNewSBName(sbPtr); |
| | 470 | } |
| | 471 | else |
| | 472 | { |
| | 473 | RemoveBehaviourStrategy(sbPtr); |
| | 474 | GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE"); |
| | 475 | } |
| | 476 | } |
| | 477 | } |
| | 478 | |
| | 479 | void CastPredoBot() |
| | 480 | { |
| | 481 | #define BOTRANGE 2000 |
| | 482 | |
| | 483 | VECTORCH position; |
| | 484 | |
| | 485 | position = PlayerStatus.sbptr->DynPtr->Position; |
| | 486 | position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE); |
| | 487 | position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE); |
| | 488 | position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE); |
| | 489 | |
| | 490 | CreatePredoBot(&position); |
| | 491 | } |
| | 492 | |
| | 493 | /* Patrick 4/7/97 -------------------------------------------------- |
| | 494 | Basic NPC functions for predator: |
| | 495 | Initialiser, visibility management,behaviour shell, and damage functions |
| | 496 | ---------------------------------------------------------------------*/ |
| | 497 | void InitPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) |
| | 498 | { |
| | 499 | TOOLS_DATA_PREDATOR *toolsData = (TOOLS_DATA_PREDATOR *)bhdata; |
| | 500 | |
| | 501 | { |
| | 502 | int i; |
| | 503 | for(i=0;i<SB_NAME_LENGTH;i++) |
| | 504 | sbPtr->SBname[i] = toolsData->nameID[i]; |
| | 505 | } |
| | 506 | |
| | 507 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 508 | |
| | 509 | if(sbPtr->DynPtr) |
| | 510 | { |
| | 511 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 512 | dynPtr->PrevPosition = dynPtr->Position = toolsData->position; |
| | 513 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 514 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 515 | dynPtr->Mass = 180; |
| | 516 | |
| | 517 | if(make_new_predator(sbPtr)) |
| | 518 | { |
| | 519 | PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->dataptr; |
| | 520 | |
| | 521 | predatorStatus->SecondaryWeapon = toolsData->secondary; |
| | 522 | predatorStatus->path = toolsData->path; |
| | 523 | predatorStatus->stepnumber = toolsData->stepnumber; |
| | 524 | |
| | 525 | if ((predatorStatus->path != -1) && (predatorStatus->stepnumber != -1)) |
| | 526 | predatorStatus->behaviourState = PBS_Pathfinding; |
| | 527 | |
| | 528 | { |
| | 529 | |
| | 530 | int i; |
| | 531 | for(i=0; i < SB_NAME_LENGTH; i++) |
| | 532 | predatorStatus->death_target_ID[i] = toolsData->death_target_ID[i]; |
| | 533 | } |
| | 534 | |
| | 535 | predatorStatus->death_target_request = toolsData->death_target_request; |
| | 536 | } |
| | 537 | } |
| | 538 | else |
| | 539 | { |
| | 540 | RemoveBehaviourStrategy(sbPtr); |
| | 541 | } |
| | 542 | } |
| | 543 | |
| | 544 | void InitDormantPredatorBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) |
| | 545 | { |
| | 546 | assert(sbPtr); |
| | 547 | DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv = malloc(sizeof(DORMANT_PREDATOR_STATUS_BLOCK)); |
| | 548 | |
| | 549 | pred_bhv->bhvr_type = I_BehaviourDormantPredator; |
| | 550 | pred_bhv->toolsData = bhdata; |
| | 551 | |
| | 552 | sbPtr->dataptr = (void*) pred_bhv; |
| | 553 | } |
| | 554 | |
| | 555 | void ActivateDormantPredator(STRATEGYBLOCK* sbPtr) |
| | 556 | { |
| | 557 | assert(sbPtr); |
| | 558 | assert(sbPtr->dataptr); |
| | 559 | DORMANT_PREDATOR_STATUS_BLOCK* pred_bhv = (DORMANT_PREDATOR_STATUS_BLOCK*)sbPtr->dataptr; |
| | 560 | void* toolsData = pred_bhv->toolsData; |
| | 561 | |
| | 562 | //convert this strategyblock to a predator |
| | 563 | free(pred_bhv); |
| | 564 | |
| | 565 | sbPtr->type = I_BehaviourPredator; |
| | 566 | EnableBehaviourType(sbPtr, toolsData); |
| | 567 | |
| | 568 | //find strategyblock of death target |
| | 569 | { |
| | 570 | PREDATOR_STATUS_BLOCK *predatorStatus = (PREDATOR_STATUS_BLOCK *)sbPtr->dataptr; |
| | 571 | predatorStatus->death_target_sbptr = FindSBWithName(predatorStatus->death_target_ID); |
| | 572 | } |
| | 573 | |
| | 574 | sbPtr->maintainVisibility = 1; |
| | 575 | sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL); |
| | 576 | } |
| | 577 | |
| | 578 | static void SetPredatorElevation(STRATEGYBLOCK *sbPtr) |
| | 579 | { |
| | 580 | VECTORCH gunpos; |
| | 581 | |
| | 582 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 583 | |
| | 584 | if (!predatorStatusPointer->Selected_Weapon->UseElevation) |
| | 585 | return; /* Non elevating weapon. */ |
| | 586 | |
| | 587 | /* Get gun position? */ |
| | 588 | |
| | 589 | if (predatorStatusPointer->My_Elevation_Section) |
| | 590 | gunpos = predatorStatusPointer->My_Elevation_Section->World_Offset; |
| | 591 | else |
| | 592 | GetTargetingPointOfObject_Far(sbPtr,&gunpos); |
| | 593 | |
| | 594 | /* Aim at weaponTarget. */ |
| | 595 | |
| | 596 | int offsetx = predatorStatusPointer->weaponTarget.vx - gunpos.vx; |
| | 597 | int offsety = predatorStatusPointer->weaponTarget.vz - gunpos.vz; |
| | 598 | int offseta = -(predatorStatusPointer->weaponTarget.vy - gunpos.vy); |
| | 599 | |
| | 600 | while( (offsetx > (ONE_FIXED>>2)) |
| | 601 | ||(offsety > (ONE_FIXED>>2)) |
| | 602 | ||(offseta > (ONE_FIXED>>2)) |
| | 603 | ||(offsetx < -(ONE_FIXED>>2)) |
| | 604 | ||(offsety < -(ONE_FIXED>>2)) |
| | 605 | ||(offseta < -(ONE_FIXED>>2))) |
| | 606 | { |
| | 607 | offsetx >>= 1; |
| | 608 | offsety >>= 1; |
| | 609 | offseta >>= 1; |
| | 610 | } |
| | 611 | |
| | 612 | int offsetz = SqRoot32((offsetx*offsetx)+(offsety*offsety)); |
| | 613 | int angle1 = ArcTan(offseta,offsetz); |
| | 614 | |
| | 615 | if (angle1 >= 3072) angle1 -= 4096; |
| | 616 | if (angle1 >= 2048) angle1 = angle1-3072; |
| | 617 | if (angle1 > 1024) angle1 =2048-angle1; |
| | 618 | |
| | 619 | assert(angle1 >= -1024); |
| | 620 | assert(angle1 <= 1024); |
| | 621 | |
| | 622 | DELTA_CONTROLLER *elevation_controller = Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); |
| | 623 | |
| | 624 | assert(elevation_controller); |
| | 625 | |
| | 626 | { |
| | 627 | int fake_timer=1024-angle1; |
| | 628 | fake_timer <<= 5; |
| | 629 | |
| | 630 | if (fake_timer > 65536) |
| | 631 | fake_timer = 65535; |
| | 632 | |
| | 633 | assert(fake_timer >= 0); |
| | 634 | assert(fake_timer < 65536); |
| | 635 | |
| | 636 | elevation_controller->timer = fake_timer; |
| | 637 | } |
| | 638 | } |
| | 639 | |
| | 640 | static void ProcessFarPredatorTargetAIModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) |
| | 641 | { |
| | 642 | assert(targetModule); |
| | 643 | |
| | 644 | NPC_TARGETMODULESTATUS targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule, 0); |
| | 645 | |
| | 646 | switch(targetStatus) |
| | 647 | { |
| | 648 | case NPCTM_NoEntryPoint: |
| | 649 | /* do nothing: can't get in. reset lastVisitedModule to avoid getting |
| | 650 | stuck in a conceptual dead end (?)*/ |
| | 651 | case NPCTM_LiftTeleport: |
| | 652 | case NPCTM_LiftDoorOpen: |
| | 653 | case NPCTM_LiftDoorNotOpen: |
| | 654 | FarNpc_FlipAround(sbPtr); |
| | 655 | break; |
| | 656 | case NPCTM_NormalRoom: |
| | 657 | case NPCTM_AirDuct: |
| | 658 | case NPCTM_SecurityDoorOpen: |
| | 659 | case NPCTM_ProxDoorOpen: |
| | 660 | LocateFarNPCInAIModule(sbPtr, targetModule); |
| | 661 | break; |
| | 662 | case NPCTM_ProxDoorNotOpen: |
| | 663 | { |
| | 664 | /* trigger the door, and set timer to quick so we can catch the door when it's open */ |
| | 665 | MODULE *renderModule = *(targetModule->m_module_ptrs); |
| | 666 | /* trigger the door, and set timer to quick so we can catch the door when it's open */ |
| | 667 | ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->dataptr)->alienTrigger = 1; |
| | 668 | } |
| | 669 | break; |
| | 670 | case NPCTM_SecurityDoorNotOpen: |
| | 671 | { |
| | 672 | MODULE *renderModule = *(targetModule->m_module_ptrs); |
| | 673 | /* do some door opening stuff here. Door should stay open for long enough |
| | 674 | for us to catch it open next time */ |
| | 675 | RequestState(renderModule->m_sbptr, 1, 0); |
| | 676 | } |
| | 677 | break; |
| | 678 | default: |
| | 679 | { |
| | 680 | assert(1==0); |
| | 681 | break; |
| | 682 | } |
| | 683 | } |
| | 684 | } |
| | 685 | |
| | 686 | static void PredatorHandleMovingAnimation(STRATEGYBLOCK *sbPtr) |
| | 687 | { |
| | 688 | VECTORCH offset; |
| | 689 | int animfactor; |
| | 690 | |
| | 691 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 692 | |
| | 693 | offset.vx = sbPtr->DynPtr->Position.vx - sbPtr->DynPtr->PrevPosition.vx; |
| | 694 | offset.vy = sbPtr->DynPtr->Position.vy - sbPtr->DynPtr->PrevPosition.vy; |
| | 695 | offset.vz = sbPtr->DynPtr->Position.vz - sbPtr->DynPtr->PrevPosition.vz; |
| | 696 | |
| | 697 | /* ...compute speed factor... */ |
| | 698 | int speed = Magnitude(&offset); |
| | 699 | |
| | 700 | if ((speed < (MUL_FIXED(NormalFrameTime, 50))) && !predatorStatusPointer->HModelController.Tweening) |
| | 701 | { |
| | 702 | /* Not moving much, are we? Be stationary! */ |
| | 703 | |
| | 704 | #ifdef SHOWPREDOSTATS |
| | 705 | printf("Forced stationary animation!\n"); |
| | 706 | #endif |
| | 707 | |
| | 708 | if(predatorStatusPointer->IAmCrouched) |
| | 709 | { |
| | 710 | if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorCrouch) |
| | 711 | ||(predatorStatusPointer->HModelController.Sub_Sequence != PCrSS_Standard)) |
| | 712 | { |
| | 713 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrouch,PCrSS_Standard,-1,(ONE_FIXED>>3)); |
| | 714 | } |
| | 715 | } |
| | 716 | else |
| | 717 | { |
| | 718 | if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorStand) |
| | 719 | || (predatorStatusPointer->HModelController.Sub_Sequence != PSSS_Standard)) |
| | 720 | { |
| | 721 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorStand,PSSS_Standard,-1,(ONE_FIXED>>3)); |
| | 722 | // Alex: this is a bit of a fudge |
| | 723 | (predatorStatusPointer->avoidanceManager.avoidanceDirection).vx = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vx; |
| | 724 | (predatorStatusPointer->avoidanceManager.avoidanceDirection).vz = -(predatorStatusPointer->avoidanceManager.avoidanceDirection).vz; |
| | 725 | } |
| | 726 | } |
| | 727 | return; |
| | 728 | } |
| | 729 | |
| | 730 | speed = DIV_FIXED(speed, NormalFrameTime); |
| | 731 | |
| | 732 | if (!speed) |
| | 733 | animfactor = ONE_FIXED; |
| | 734 | else |
| | 735 | animfactor = DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down... |
| | 736 | |
| | 737 | assert(animfactor > 0); |
| | 738 | |
| | 739 | #ifdef SHOWPREDOSTATS |
| | 740 | printf("Anim Factor %d, Tweening %d, Speed %d\n",animfactor,predatorStatusPointer->HModelController.Tweening,speed); |
| | 741 | #endif |
| | 742 | |
| | 743 | int walking = 0; |
| | 744 | |
| | 745 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController, HMSQT_PredatorRun, PRSS_Walk)) |
| | 746 | { |
| | 747 | /* Are we currently walking? */ |
| | 748 | if ((predatorStatusPointer->HModelController.Sequence_Type == HMSQT_PredatorRun) |
| | 749 | && (predatorStatusPointer->HModelController.Sub_Sequence == PRSS_Walk)) |
| | 750 | { |
| | 751 | if (speed < PRED_WALKING_SPEED_MAX) |
| | 752 | walking = 1; |
| | 753 | } |
| | 754 | else |
| | 755 | { |
| | 756 | if (speed < PRED_WALKING_SPEED_MIN) |
| | 757 | walking = 1; |
| | 758 | } |
| | 759 | } |
| | 760 | |
| | 761 | /* Start animation? */ |
| | 762 | if (!predatorStatusPointer->HModelController.Tweening) |
| | 763 | { |
| | 764 | /* If still tweening, probably best to leave it alone... */ |
| | 765 | |
| | 766 | if (PredatorShouldBeCrawling(sbPtr)) |
| | 767 | { |
| | 768 | predatorStatusPointer->IAmCrouched = 1; |
| | 769 | |
| | 770 | /* Only one possible sequence here. */ |
| | 771 | if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorCrawl) |
| | 772 | || (predatorStatusPointer->HModelController.Sub_Sequence != PCSS_Standard)) |
| | 773 | { |
| | 774 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorCrawl,PCSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); |
| | 775 | } |
| | 776 | |
| | 777 | } |
| | 778 | else if (!walking) |
| | 779 | { |
| | 780 | predatorStatusPointer->IAmCrouched = 0; |
| | 781 | |
| | 782 | /* Are we doing the right anim? */ |
| | 783 | if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorRun) |
| | 784 | || (predatorStatusPointer->HModelController.Sub_Sequence != PRSS_Standard)) |
| | 785 | { |
| | 786 | /* If we're currently walking, tween over. */ |
| | 787 | if ((predatorStatusPointer->HModelController.Sequence_Type == HMSQT_PredatorRun) |
| | 788 | && (predatorStatusPointer->HModelController.Sub_Sequence == PRSS_Walk)) |
| | 789 | { |
| | 790 | InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun, |
| | 791 | PRSS_Standard,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1); |
| | 792 | } |
| | 793 | else |
| | 794 | { |
| | 795 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Standard,ONE_FIXED,(ONE_FIXED>>3)); |
| | 796 | } |
| | 797 | } |
| | 798 | } |
| | 799 | else |
| | 800 | { |
| | 801 | predatorStatusPointer->IAmCrouched = 0; |
| | 802 | |
| | 803 | /* Are we doing the right anim? */ |
| | 804 | if ((predatorStatusPointer->HModelController.Sequence_Type != HMSQT_PredatorRun) |
| | 805 | ||(predatorStatusPointer->HModelController.Sub_Sequence != PRSS_Walk)) |
| | 806 | { |
| | 807 | /* If we're currently running, tween over. */ |
| | 808 | if ((predatorStatusPointer->HModelController.Sequence_Type == HMSQT_PredatorRun) |
| | 809 | && (predatorStatusPointer->HModelController.Sub_Sequence == PRSS_Standard)) |
| | 810 | { |
| | 811 | InitHModelTweening_ToTheMiddle(&predatorStatusPointer->HModelController, (ONE_FIXED>>3),HMSQT_PredatorRun, |
| | 812 | PRSS_Walk,(ONE_FIXED<<1),((predatorStatusPointer->HModelController.sequence_timer+(ONE_FIXED>>3))&65535),1); |
| | 813 | } |
| | 814 | else |
| | 815 | { |
| | 816 | SetPredatorAnimationSequence(sbPtr,HMSQT_PredatorRun,PRSS_Walk,ONE_FIXED,(ONE_FIXED>>3)); |
| | 817 | } |
| | 818 | } |
| | 819 | } |
| | 820 | } |
| | 821 | |
| | 822 | if (!predatorStatusPointer->HModelController.Tweening) |
| | 823 | HModel_SetToolsRelativeSpeed(&predatorStatusPointer->HModelController,animfactor); |
| | 824 | } |
| | 825 | |
| | 826 | static void Predator_Enter_Attacking_State(STRATEGYBLOCK *sbPtr) |
| | 827 | { |
| | 828 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 829 | |
| | 830 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 831 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 832 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 833 | predatorStatusPointer->volleySize = 0; |
| | 834 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 835 | predatorStatusPointer->behaviourState = PBS_Attacking; |
| | 836 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 837 | predatorStatusPointer->Pred_Laser_On = 0; |
| | 838 | predatorStatusPointer->internalState = 0; |
| | 839 | /* Become patient again. */ |
| | 840 | predatorStatusPointer->patience = PRED_PATIENCE_TIME; |
| | 841 | |
| | 842 | switch(predatorStatusPointer->Selected_Weapon->id) |
| | 843 | { |
| | 844 | case PNPCW_Wristblade: |
| | 845 | { |
| | 846 | ATTACK_DATA *thisAttack = GetWristbladeAttackSequence(&predatorStatusPointer->HModelController,0, predatorStatusPointer->IAmCrouched); |
| | 847 | SetPredatorAnimationSequence(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime); |
| | 848 | predatorStatusPointer->current_attack = thisAttack; |
| | 849 | } |
| | 850 | break; |
| | 851 | case PNPCW_Staff: |
| | 852 | { |
| | 853 | ATTACK_DATA *thisAttack = GetPredStaffAttackSequence(&predatorStatusPointer->HModelController,0, predatorStatusPointer->IAmCrouched); |
| | 854 | SetPredatorAnimationSequence(sbPtr, thisAttack->Sequence_Type, thisAttack->Sub_Sequence, thisAttack->Sequence_Length,
thisAttack->TweeningTime); |
| | 855 | predatorStatusPointer->current_attack = thisAttack; |
| | 856 | } |
| | 857 | break; |
| | 858 | default: |
| | 859 | { |
| | 860 | if(predatorStatusPointer->IAmCrouched) |
| | 861 | SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorCrouch, PCrSS_Attack_Primary, -1, (ONE_FIXED>>3)); |
| | 862 | else |
| | 863 | SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Attack_Primary, -1, (ONE_FIXED>>3)); |
| | 864 | } |
| | 865 | } |
| | 866 | } |
| | 867 | |
| | 868 | static void Predator_Enter_Pathfinder_State(STRATEGYBLOCK *sbPtr) |
| | 869 | { |
| | 870 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 871 | |
| | 872 | assert(predatorStatusPointer->path != -1); |
| | 873 | assert(predatorStatusPointer->stepnumber != -1); |
| | 874 | |
| | 875 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 876 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 877 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 878 | predatorStatusPointer->volleySize = 0; |
| | 879 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 880 | predatorStatusPointer->behaviourState = PBS_Pathfinding; |
| | 881 | predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; |
| | 882 | predatorStatusPointer->Pred_Laser_On = 0; |
| | 883 | } |
| | 884 | |
| | 885 | static void Predator_Enter_Wander_State(STRATEGYBLOCK *sbPtr) |
| | 886 | { |
| | 887 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 888 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 889 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 890 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 891 | predatorStatusPointer->volleySize = 0; |
| | 892 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 893 | predatorStatusPointer->behaviourState = PBS_Wandering; |
| | 894 | predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; |
| | 895 | predatorStatusPointer->Pred_Laser_On = 0; |
| | 896 | } |
| | 897 | |
| | 898 | static int Predator_TargetFilter(STRATEGYBLOCK *candidate, STRATEGYBLOCK *sbPtr) |
| | 899 | { |
| | 900 | switch (candidate->type) |
| | 901 | { |
| | 902 | case I_BehaviourAlien: |
| | 903 | case I_BehaviourMarine: |
| | 904 | case I_BehaviourMarinePlayer: |
| | 905 | case I_BehaviourAlienPlayer: |
| | 906 | case I_BehaviourAutoGun: |
| | 907 | case I_BehaviourFaceHugger: |
| | 908 | case I_BehaviourXenoborg: |
| | 909 | case I_BehaviourQueenAlien: |
| | 910 | return 1; |
| | 911 | case I_BehaviourRocket: |
| | 912 | case I_BehaviourPulseGrenade: |
| | 913 | case I_BehaviourGrenade: |
| | 914 | case I_BehaviourFlare: |
| | 915 | case I_BehaviourProximityGrenade: |
| | 916 | case I_BehaviourFragmentationGrenade: |
| | 917 | case I_BehaviourFrisbee: |
| | 918 | case I_BehaviourMolotov: |
| | 919 | { |
| | 920 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 921 | return (PNPCW_PlasmaCaster == predatorStatusPointer->Selected_Weapon->id); |
| | 922 | } |
| | 923 | //case I_BehaviourSpeargunBolt: |
| | 924 | //case I_BehaviourPlacedLight: // ??? |
| | 925 | case I_BehaviourNetGhost: |
| | 926 | { |
| | 927 | NETGHOSTDATABLOCK *dataptr = candidate->dataptr; |
| | 928 | |
| | 929 | switch (dataptr->type) |
| | 930 | { |
| | 931 | case I_BehaviourMarinePlayer: |
| | 932 | case I_BehaviourAlienPlayer: |
| | 933 | case I_BehaviourPredatorPlayer: |
| | 934 | //return 1; |
| | 935 | return 0; |
| | 936 | default: |
| | 937 | return 0; |
| | 938 | } |
| | 939 | } |
| | 940 | case I_BehaviourDummy: |
| | 941 | { |
| | 942 | DUMMY_STATUS_BLOCK *dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->dataptr); |
| | 943 | assert(dummyStatusPointer); |
| | 944 | switch (dummyStatusPointer->PlayerType) |
| | 945 | { |
| | 946 | case I_Marine: |
| | 947 | case I_Alien: |
| | 948 | return 1; |
| | 949 | default: |
| | 950 | return 0; |
| | 951 | } |
| | 952 | } |
| | 953 | break; |
| | 954 | default: |
| | 955 | return 0; |
| | 956 | } |
| | 957 | } |
| | 958 | |
| | 959 | static STRATEGYBLOCK *Predator_GetNewTarget(STRATEGYBLOCK *sbPtr) |
| | 960 | { |
| | 961 | int neardist = ONE_FIXED; |
| | 962 | STRATEGYBLOCK *nearest = NULL; |
| | 963 | int a; |
| | 964 | assert(sbPtr); |
| | 965 | int target_count=0; |
| | 966 | int wraps = 0; |
| | 967 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 968 | |
| | 969 | MODULE *dmod = ModuleFromPosition(&sbPtr->DynPtr->Position, PlayerStatus.sbptr->containingModule); |
| | 970 | assert(dmod); |
| | 971 | |
| | 972 | MATRIXCH WtoL = sbPtr->DynPtr->OrientMat; |
| | 973 | TransposeMatrixCH(&WtoL); |
| | 974 | |
| | 975 | for (a=0; a < NumActiveStBlocks; a++) |
| | 976 | { |
| | 977 | STRATEGYBLOCK *candidate = ActiveStBlockList[a]; |
| | 978 | |
| | 979 | if ((candidate != sbPtr) && candidate->DynPtr) |
| | 980 | { |
| | 981 | VECTORCH offset; |
| | 982 | /* Arc reject. */ |
| | 983 | |
| | 984 | offset.vx = sbPtr->DynPtr->Position.vx - candidate->DynPtr->Position.vx; |
| | 985 | offset.vy = sbPtr->DynPtr->Position.vy - candidate->DynPtr->Position.vy; |
| | 986 | offset.vz = sbPtr->DynPtr->Position.vz - candidate->DynPtr->Position.vz; |
| | 987 | |
| | 988 | RotateVector(&offset, &WtoL); |
| | 989 | |
| | 990 | if (offset.vz <= 0) |
| | 991 | { |
| | 992 | if (Predator_TargetFilter(candidate, sbPtr)) |
| | 993 | { |
| | 994 | int dist = Approximate3dMagnitude(&offset); |
| | 995 | |
| | 996 | if (dist < neardist) |
| | 997 | { |
| | 998 | /* Check visibility? */ |
| | 999 | if (candidate->DisplayBlock) |
| | 1000 | { |
| | 1001 | /* Near case. */ |
| | 1002 | if (!NPC_IsDead(candidate) && NPCCanSeeTarget(sbPtr, candidate)) |
| | 1003 | { |
| | 1004 | nearest = candidate; |
| | 1005 | neardist = dist; |
| | 1006 | predatorStatusPointer->Targets[target_count] = candidate; |
| | 1007 | |
| | 1008 | if(++target_count > NUMBER_OF_TRACKED_TARGETS) |
| | 1009 | { |
| | 1010 | target_count = 0; |
| | 1011 | wraps++; |
| | 1012 | } |
| | 1013 | } |
| | 1014 | } |
| | 1015 | else |
| | 1016 | { |
| | 1017 | if (!NPC_IsDead(candidate) && IsModuleVisibleFromModule(dmod, candidate->containingModule)) |
| | 1018 | { |
| | 1019 | nearest = candidate; |
| | 1020 | neardist = dist; |
| | 1021 | predatorStatusPointer->Targets[target_count] = candidate; |
| | 1022 | |
| | 1023 | if(++target_count > NUMBER_OF_TRACKED_TARGETS) |
| | 1024 | { |
| | 1025 | target_count = 0; |
| | 1026 | wraps++; |
| | 1027 | } |
| | 1028 | } |
| | 1029 | } |
| | 1030 | } |
| | 1031 | } |
| | 1032 | } |
| | 1033 | } |
| | 1034 | } |
| | 1035 | |
| | 1036 | if(0) |
| | 1037 | { |
| | 1038 | if (!wraps) |
| | 1039 | { |
| | 1040 | target_count = NUMBER_OF_TRACKED_TARGETS; |
| | 1041 | |
| | 1042 | int j=a; |
| | 1043 | |
| | 1044 | for (; j < a; j++) |
| | 1045 | predatorStatusPointer->Targets[j] = NULL; |
| | 1046 | } |
| | 1047 | |
| | 1048 | a = 0; |
| | 1049 | while (predatorStatusPointer->Targets[a]) |
| | 1050 | { |
| | 1051 | printf("PREDATROR TAGET %d\n", predatorStatusPointer->Targets[a]->type); |
| | 1052 | a++; |
| | 1053 | } |
| | 1054 | } |
| | 1055 | |
| | 1056 | return nearest; |
| | 1057 | } |
| | 1058 | |
| | 1059 | static void DoPredatorRandomSound(STRATEGYBLOCK *sbPtr) |
| | 1060 | { |
| | 1061 | int rand = FastRandom(); |
| | 1062 | int pitch = (rand & 255) - 128; |
| | 1063 | |
| | 1064 | assert(sbPtr); |
| | 1065 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1066 | assert(predatorStatusPointer); |
| | 1067 | |
| | 1068 | if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) |
| | 1069 | PlayPredatorSound(0, PSC_Scream_General, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position); |
| | 1070 | } |
| | 1071 | |
| | 1072 | static void predator_change_behaviour(STRATEGYBLOCK *sbPtr) |
| | 1073 | { |
| | 1074 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1075 | assert(predatorStatusPointer); |
| | 1076 | |
| | 1077 | predatorStatusPointer->patience = PRED_PATIENCE_TIME; |
| | 1078 | predatorStatusPointer->volleySize = 0; |
| | 1079 | |
| | 1080 | switch(predatorStatusPointer->behaviourState) |
| | 1081 | { |
| | 1082 | case PBS_Withdrawing: |
| | 1083 | { |
| | 1084 | /* Force re-evaluation of priorities. */ |
| | 1085 | predatorStatusPointer->missionmodule = NULL; |
| | 1086 | predatorStatusPointer->fearmodule = NULL; |
| | 1087 | } // no break |
| | 1088 | case PBS_Engaging: |
| | 1089 | case PBS_Hunting: |
| | 1090 | case PBS_Returning: |
| | 1091 | { |
| | 1092 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1093 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 1094 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 1095 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 1096 | predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; |
| | 1097 | } |
| | 1098 | break; |
| | 1099 | case PBS_Wandering: |
| | 1100 | { |
| | 1101 | if ((predatorStatusPointer->path != -1) && (predatorStatusPointer->stepnumber != -1)) |
| | 1102 | { |
| | 1103 | /* Pathfinding mission. */ |
| | 1104 | switch(predatorStatusPointer->behaviourState) |
| | 1105 | { |
| | 1106 | case PBS_Returning: |
| | 1107 | case PBS_Pathfinding: |
| | 1108 | Predator_Enter_Wander_State(sbPtr); /* A real order. */ |
| | 1109 | break; |
| | 1110 | default: |
| | 1111 | Predator_Enter_Pathfinder_State(sbPtr); |
| | 1112 | } |
| | 1113 | } |
| | 1114 | else |
| | 1115 | { |
| | 1116 | Predator_Enter_Wander_State(sbPtr); |
| | 1117 | } |
| | 1118 | } |
| | 1119 | break; |
| | 1120 | case PBS_Avoidance: |
| | 1121 | { |
| | 1122 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1123 | NPCGetAvoidanceDirection(sbPtr, &predatorStatusPointer->moveData.avoidanceDirn, &predatorStatusPointer->obstruction); |
| | 1124 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 1125 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 1126 | predatorStatusPointer->stateTimer = NPC_AVOIDTIME; |
| | 1127 | } |
| | 1128 | break; |
| | 1129 | case PBS_Recovering: |
| | 1130 | { |
| | 1131 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1132 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 1133 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 1134 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 1135 | |
| | 1136 | if (predatorStatusPointer->Selected_Weapon->id != PNPCW_Medicomp) |
| | 1137 | { |
| | 1138 | predatorStatusPointer->ChangeToWeapon = PNPCW_Medicomp; |
| | 1139 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 1140 | predatorStatusPointer->stateTimer = 0; /* Just starting. */ |
| | 1141 | predatorStatusPointer->IAmCrouched = ((FastRandom() & 65535) > 32767/2); |
| | 1142 | |
| | 1143 | if(predatorStatusPointer->CloakStatus == PCLOAK_Off) |
| | 1144 | PredatorCloakOn(predatorStatusPointer); |
| | 1145 | |
| | 1146 | predator_change_behaviour(sbPtr); |
| | 1147 | } |
| | 1148 | else |
| | 1149 | { |
| | 1150 | predatorStatusPointer->behaviourState = PBS_Recovering; |
| | 1151 | predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; |
| | 1152 | |
| | 1153 | if(predatorStatusPointer->IAmCrouched) |
| | 1154 | SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorCrouch, PCrSS_Attack_Primary, ONE_FIXED,(ONE_FIXED>>3)); |
| | 1155 | else |
| | 1156 | SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Attack_Primary, ONE_FIXED,(ONE_FIXED>>3)); |
| | 1157 | } |
| | 1158 | } |
| | 1159 | break; |
| | 1160 | case PBS_SwapWeapon: |
| | 1161 | { |
| | 1162 | /* What are we swapping to? */ |
| | 1163 | if (predatorStatusPointer->ChangeToWeapon == PNPCW_End) |
| | 1164 | { |
| | 1165 | /* Use default. */ |
| | 1166 | if (predatorStatusPointer->Selected_Weapon == predatorStatusPointer->MeleeWeapon) |
| | 1167 | predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->SecondaryWeapon; |
| | 1168 | else |
| | 1169 | { |
| | 1170 | predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->MeleeWeapon->id; |
| | 1171 | |
| | 1172 | if ((FastRandom() & 65535) > 32767) |
| | 1173 | if (PCLOAK_On == predatorStatusPointer->CloakStatus) |
| | 1174 | PredatorCloakOff(predatorStatusPointer); |
| | 1175 | } |
| | 1176 | } |
| | 1177 | |
| | 1178 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1179 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 1180 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 1181 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 1182 | predatorStatusPointer->stateTimer = 0; /* Just starting. */ |
| | 1183 | predatorStatusPointer->enableSwap = 0; |
| | 1184 | } |
| | 1185 | break; |
| | 1186 | case PBS_Pathfinding: |
| | 1187 | Predator_Enter_Pathfinder_State(sbPtr); |
| | 1188 | default: |
| | 1189 | break; |
| | 1190 | } |
| | 1191 | } |
| | 1192 | |
| | 1193 | |
| | 1194 | void PredatorBehaviour(STRATEGYBLOCK *sbPtr) |
| | 1195 | { |
| | 1196 | int predatorIsNear = 0; |
| | 1197 | char *descriptor; |
| | 1198 | |
| | 1199 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1200 | //sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 1201 | |
| | 1202 | if(sbPtr->DisplayBlock) |
| | 1203 | { |
| | 1204 | //assert(ModuleCurrVisArray[sbPtr->containingModule->m_index]); |
| | 1205 | predatorIsNear = 1; |
| | 1206 | } |
| | 1207 | |
| | 1208 | if (sbPtr->DamageBlock.IsOnFire) |
| | 1209 | { |
| | 1210 | CauseDamageToObject(sbPtr, &damage_profiles[FIREDAMAGE], NormalFrameTime, NULL); |
| | 1211 | |
| | 1212 | if (sbPtr->type == I_BehaviourCorpse) |
| | 1213 | return; /* Gettin' out of here... */ |
| | 1214 | |
| | 1215 | if (predatorStatusPointer->incidentFlag && ((FastRandom() & 65535) < 32767)) |
| | 1216 | sbPtr->DamageBlock.IsOnFire = 0; |
| | 1217 | } |
| | 1218 | |
| | 1219 | InitWaypointSystem(0); |
| | 1220 | predatorStatusPointer->Pred_Laser_On = 0; |
| | 1221 | |
| | 1222 | //DoPredatorCloak(predatorStatusPointer, sbPtr->DynPtr); |
| | 1223 | |
| | 1224 | predatorStatusPointer->incidentFlag = 0; |
| | 1225 | predatorStatusPointer->incidentTimer -= NormalFrameTime; |
| | 1226 | |
| | 1227 | if (predatorStatusPointer->incidentTimer < 0) |
| | 1228 | { |
| | 1229 | predatorStatusPointer->incidentFlag = 1; |
| | 1230 | predatorStatusPointer->incidentTimer = 32767 + (FastRandom() & 65535); |
| | 1231 | } |
| | 1232 | |
| | 1233 | switch(predatorStatusPointer->behaviourState) |
| | 1234 | { |
| | 1235 | case PBS_Taunting: |
| | 1236 | { |
| | 1237 | if (predatorIsNear) |
| | 1238 | CentrePredatorElevation(sbPtr); |
| | 1239 | else |
| | 1240 | ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr); |
| | 1241 | |
| | 1242 | if(HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) |
| | 1243 | { |
| | 1244 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 1245 | predator_change_behaviour(sbPtr); |
| | 1246 | } |
| | 1247 | } |
| | 1248 | return; |
| | 1249 | case PBS_Recovering: |
| | 1250 | { |
| | 1251 | descriptor = "Recovering"; |
| | 1252 | |
| | 1253 | if (predatorIsNear) |
| | 1254 | CentrePredatorElevation(sbPtr); |
| | 1255 | else |
| | 1256 | ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr); |
| | 1257 | |
| | 1258 | { |
| | 1259 | /* Stay where you are and regain health. */ |
| | 1260 | |
| | 1261 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator]; |
| | 1262 | |
| | 1263 | if (sbPtr->DamageBlock.Health > 0) |
| | 1264 | { |
| | 1265 | int health_increment = DIV_FIXED((NpcData->StartingStats.Health * NormalFrameTime), PRED_REGEN_TIME); |
| | 1266 | |
| | 1267 | sbPtr->DamageBlock.Health += health_increment; |
| | 1268 | |
| | 1269 | if (sbPtr->DamageBlock.Health > (NpcData->StartingStats.Health << ONE_FIXED_SHIFT)) |
| | 1270 | sbPtr->DamageBlock.Health = (NpcData->StartingStats.Health << ONE_FIXED_SHIFT); |
| | 1271 | |
| | 1272 | HModel_Regen(&predatorStatusPointer->HModelController, PRED_REGEN_TIME); |
| | 1273 | } |
| | 1274 | |
| | 1275 | if (sbPtr->DamageBlock.Health == (NpcData->StartingStats.Health << ONE_FIXED_SHIFT)) |
| | 1276 | { |
| | 1277 | DoPredatorRandomSound(sbPtr); |
| | 1278 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 1279 | predator_change_behaviour(sbPtr); |
| | 1280 | } |
| | 1281 | } |
| | 1282 | } |
| | 1283 | return; |
| | 1284 | case PBS_SelfDestruct: |
| | 1285 | { |
| | 1286 | /* No elevation should be present. */ |
| | 1287 | |
| | 1288 | if (!sbPtr->DisplayBlock) |
| | 1289 | { |
| | 1290 | /* We're far... do the timer! */ |
| | 1291 | ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr); |
| | 1292 | } |
| | 1293 | |
| | 1294 | /* And if we're playing Laugh, we'd better laugh... */ |
| | 1295 | |
| | 1296 | if (PCrSS_Det_Prog == predatorStatusPointer->HModelController.Sub_Sequence) |
| | 1297 | { |
| | 1298 | if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) |
| | 1299 | { |
| | 1300 | InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED >> 2), HMSQT_PredatorCrouch, PCrSS_Det_Laugh, -1, 0); |
| | 1301 | } |
| | 1302 | else if (predatorStatusPointer->HModelController.keyframe_flags & 1) |
| | 1303 | { |
| | 1304 | predatorStatusPointer->stateTimer = PRED_SELF_DESTRUCT_TIMER; |
| | 1305 | predatorStatusPointer->internalState = 1; |
| | 1306 | } |
| | 1307 | } |
| | 1308 | else |
| | 1309 | { |
| | 1310 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 1311 | |
| | 1312 | if (predatorStatusPointer->stateTimer <= 0) |
| | 1313 | { |
| | 1314 | predatorStatusPointer->internalState = 2; |
| | 1315 | predatorStatusPointer->GibbFactor = ONE_FIXED; |
| | 1316 | Sound_Play(SID_NICE_EXPLOSION, "d", &sbPtr->DynPtr->Position); |
| | 1317 | MakeVolumetricExplosionAt(&sbPtr->DynPtr->Position, EXPLOSION_SADAR_BLAST); |
| | 1318 | } |
| | 1319 | } |
| | 1320 | } |
| | 1321 | return; |
| | 1322 | default: |
| | 1323 | break; |
| | 1324 | |
| | 1325 | } |
| | 1326 | |
| | 1327 | if (predatorStatusPointer->closets_target == NULL) |
| | 1328 | { |
| | 1329 | if (predatorIsNear || predatorStatusPointer->incidentFlag) |
| | 1330 | { |
| | 1331 | predatorStatusPointer->closets_target = Predator_GetNewTarget(sbPtr); |
| | 1332 | |
| | 1333 | if (predatorStatusPointer->closets_target) |
| | 1334 | { |
| | 1335 | VECTORCH orientationDirn; |
| | 1336 | NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 1337 | orientationDirn.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 1338 | orientationDirn.vy = 0; |
| | 1339 | orientationDirn.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 1340 | NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 1341 | |
| | 1342 | COPY_NAME(predatorStatusPointer->Target_SBname, predatorStatusPointer->closets_target->SBname); |
| | 1343 | |
| | 1344 | int range = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position, &sbPtr->DynPtr->Position); |
| | 1345 | |
| | 1346 | if(range < predatorStatusPointer->Selected_Weapon->MaxRange) |
| | 1347 | { |
| | 1348 | if (predatorStatusPointer->MeleeWeapon == predatorStatusPointer->Selected_Weapon) |
| | 1349 | { |
| | 1350 | switch(predatorStatusPointer->closets_target->type) |
| | 1351 | { |
| | 1352 | case I_BehaviourMarine: |
| | 1353 | case I_BehaviourMarinePlayer: |
| | 1354 | if ((FastRandom() & 65535) < 32767) |
| | 1355 | break; |
| | 1356 | default: |
| | 1357 | if (PCLOAK_On == predatorStatusPointer->CloakStatus) |
| | 1358 | PredatorCloakOff(predatorStatusPointer); |
| | 1359 | } |
| | 1360 | } |
| | 1361 | } |
| | 1362 | } |
| | 1363 | } |
| | 1364 | } |
| | 1365 | else |
| | 1366 | { |
| | 1367 | if (NPC_IsDead(predatorStatusPointer->closets_target) || !NAME_ISEQUAL(predatorStatusPointer->closets_target->SBname,
predatorStatusPointer->Target_SBname)) |
| | 1368 | { |
| | 1369 | predatorStatusPointer->closets_target = NULL; |
| | 1370 | } |
| | 1371 | else // valid target |
| | 1372 | { |
| | 1373 | if(NPCCanSeeTarget(sbPtr, predatorStatusPointer->closets_target)) |
| | 1374 | { |
| | 1375 | VECTORCH orientationDirn; |
| | 1376 | NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 1377 | orientationDirn.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 1378 | orientationDirn.vy = 0; |
| | 1379 | orientationDirn.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 1380 | |
| | 1381 | if(NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE)) |
| | 1382 | { |
| | 1383 | int distance_to_target = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position,
&sbPtr->DynPtr->Position); |
| | 1384 | |
| | 1385 | if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange) |
| | 1386 | { |
| | 1387 | if (predatorStatusPointer->CloakStatus == PCLOAK_Off) |
| | 1388 | PredatorCloakOn(predatorStatusPointer); |
| | 1389 | |
| | 1390 | PredatorHandleMovingAnimation(sbPtr); |
| | 1391 | |
| | 1392 | const PREDATOR_WEAPON_DATA* test_we = GetThisNPCPredatorWeapon(PNPCW_PlasmaCaster); |
| | 1393 | |
| | 1394 | if(distance_to_target > test_we->MaxRange/2) |
| | 1395 | { |
| | 1396 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 1397 | //Predator_Enter_Swapping_State(sbPtr); |
| | 1398 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 1399 | predatorStatusPointer->enableSwap = 0; |
| | 1400 | } |
| | 1401 | |
| | 1402 | VECTORCH velocityDirection = {0,0,0}; |
| | 1403 | VECTORCH targetPosition; |
| | 1404 | /* See which way we want to go. */ |
| | 1405 | { |
| | 1406 | AIMODULE *targetModule = NULL; |
| | 1407 | |
| | 1408 | MODULE *tcm = predatorStatusPointer->closets_target->containingModule ? |
| | 1409 | predatorStatusPointer->closets_target->containingModule : |
| | 1410 | ModuleFromPosition(&predatorStatusPointer->closets_target->DynPtr->Position, sbPtr->containingModule); |
| | 1411 | |
| | 1412 | if (tcm) |
| | 1413 | targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule, tcm->m_aimodule, 7, 0); |
| | 1414 | |
| | 1415 | if (targetModule == sbPtr->containingModule->m_aimodule) |
| | 1416 | { |
| | 1417 | int targetIsAirduct = 0; |
| | 1418 | /* Try going for it, we still can't see them. */ |
| | 1419 | NPCGetMovementTarget(sbPtr, predatorStatusPointer->closets_target, &targetPosition, &targetIsAirduct, 0); |
| | 1420 | NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition, &predatorStatusPointer->waypointManager); |
| | 1421 | } |
| | 1422 | else if (!targetModule) |
| | 1423 | { |
| | 1424 | /* Must be inaccessible. */ |
| | 1425 | #ifdef SHOWPREDOSTATS |
| | 1426 | if (predatorStatusPointer->closets_target->containingModule) |
| | 1427 | printf("I can see you, but I can't get there!\n"); |
| | 1428 | else |
| | 1429 | printf("Hey, you've got no Containing Module!\n"); |
| | 1430 | #endif |
| | 1431 | } |
| | 1432 | else |
| | 1433 | { |
| | 1434 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); |
| | 1435 | |
| | 1436 | if (thisEp) |
| | 1437 | { |
| | 1438 | predatorStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 1439 | predatorStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx; |
| | 1440 | predatorStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy; |
| | 1441 | predatorStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz; |
| | 1442 | //predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; |
| | 1443 | } |
| | 1444 | else |
| | 1445 | { |
| | 1446 | printf("This assert is a busted adjacency!\nNo EP between %s and %s.", |
| | 1447 | (*(targetModule->m_module_ptrs))->name, sbPtr->containingModule->name); |
| | 1448 | |
| | 1449 | assert(thisEp); |
| | 1450 | //predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE; |
| | 1451 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1452 | //predatorStatusPointer->moveData.lastModule = predatorStatusPointer->lastmodule; |
| | 1453 | NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0); |
| | 1454 | } |
| | 1455 | |
| | 1456 | NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager); |
| | 1457 | |
| | 1458 | /* If that fired, there's a farped adjacency. */ |
| | 1459 | } |
| | 1460 | } |
| | 1461 | |
| | 1462 | /* Should have a velocity set now. */ |
| | 1463 | NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); |
| | 1464 | |
| | 1465 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 1466 | //if (New_NPC_IsObstructed(sbPtr, &predatorStatusPointer->avoidanceManager)) predatorStatusPointer->behaviourState =
PBS_Avoidance; |
| | 1467 | } |
| | 1468 | else |
| | 1469 | { |
| | 1470 | /* if our state timer has run out in approach state, see if we can fire*/ |
| | 1471 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 1472 | |
| | 1473 | if(predatorStatusPointer->stateTimer <= 0) |
| | 1474 | Predator_Enter_Attacking_State(sbPtr); |
| | 1475 | } |
| | 1476 | } |
| | 1477 | else |
| | 1478 | { |
| | 1479 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 1480 | } |
| | 1481 | } |
| | 1482 | else // let's hunt/stalk target |
| | 1483 | { |
| | 1484 | if (PCLOAK_Off == predatorStatusPointer->CloakStatus) |
| | 1485 | PredatorCloakOn(predatorStatusPointer); |
| | 1486 | |
| | 1487 | if (predatorIsNear) |
| | 1488 | { |
| | 1489 | VECTORCH velocityDirection = {0,0,0}; |
| | 1490 | puts("hunt near"); |
| | 1491 | { |
| | 1492 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 0); |
| | 1493 | |
| | 1494 | #ifdef SHOWPREDOSTATS |
| | 1495 | { |
| | 1496 | if (targetModule) |
| | 1497 | printf("closets_target Module %s.\n", (*(targetModule->m_module_ptrs))->name); |
| | 1498 | else |
| | 1499 | printf("closets_target Module NULL.\n"); |
| | 1500 | } |
| | 1501 | #endif |
| | 1502 | |
| | 1503 | if (targetModule == sbPtr->containingModule->m_aimodule) /* Hey, it'll drop through. */ |
| | 1504 | { |
| | 1505 | predatorStatusPointer->behaviourState = predatorStatusPointer->closets_target ? PBS_Engaging : PBS_Wandering; |
| | 1506 | predator_change_behaviour(sbPtr); |
| | 1507 | } |
| | 1508 | else |
| | 1509 | { |
| | 1510 | if (!targetModule) |
| | 1511 | { |
| | 1512 | predatorStatusPointer->behaviourState = PBS_Recovering; |
| | 1513 | predator_change_behaviour(sbPtr); |
| | 1514 | } |
| | 1515 | else |
| | 1516 | { |
| | 1517 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); |
| | 1518 | |
| | 1519 | if (!thisEp) |
| | 1520 | { |
| | 1521 | printf("This assert is a busted adjacency!"); |
| | 1522 | assert(thisEp); |
| | 1523 | } |
| | 1524 | /* If that fired, there's a farped adjacency. */ |
| | 1525 | |
| | 1526 | predatorStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 1527 | predatorStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx; |
| | 1528 | predatorStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy; |
| | 1529 | predatorStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz; |
| | 1530 | } |
| | 1531 | } |
| | 1532 | } |
| | 1533 | |
| | 1534 | /* ok: should have a current target at this stage... */ |
| | 1535 | NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager); |
| | 1536 | NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); |
| | 1537 | |
| | 1538 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 1539 | |
| | 1540 | if (New_NPC_IsObstructed(sbPtr, &predatorStatusPointer->avoidanceManager)) |
| | 1541 | { |
| | 1542 | predatorStatusPointer->behaviourState = PBS_Avoidance; |
| | 1543 | predator_change_behaviour(sbPtr); |
| | 1544 | } |
| | 1545 | } |
| | 1546 | else |
| | 1547 | { |
| | 1548 | puts("hunt FAR"); |
| | 1549 | /* Decrement the Far state timer */ |
| | 1550 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 1551 | /* check if far state timer has timed-out. If so, it is time |
| | 1552 | to do something. Otherwise just return. */ |
| | 1553 | |
| | 1554 | if(predatorStatusPointer->stateTimer < 0) |
| | 1555 | { |
| | 1556 | /* timer has timed-out in hunting mode: */ |
| | 1557 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForHunt(sbPtr, 0); |
| | 1558 | |
| | 1559 | /* if there is no target module, it means that the pred is trapped in an |
| | 1560 | unlinked module. In this case, reset the timer and return. */ |
| | 1561 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 1562 | |
| | 1563 | if(targetModule) |
| | 1564 | { |
| | 1565 | /* NB don't need to check for state changes... will regen health on makenear */ |
| | 1566 | /* Examine target, and decide what to do */ |
| | 1567 | //assert(AIModuleIsPhysical(targetModule)); |
| | 1568 | ProcessFarPredatorTargetAIModule(sbPtr, targetModule); |
| | 1569 | } |
| | 1570 | } |
| | 1571 | } |
| | 1572 | } |
| | 1573 | } |
| | 1574 | } |
| | 1575 | |
| | 1576 | |
| | 1577 | /* |
| | 1578 | predatorStatusPointer->patience -= NormalFrameTime; |
| | 1579 | |
| | 1580 | if (predatorStatusPointer->patience <= 0) |
| | 1581 | { |
| | 1582 | predatorStatusPointer->behaviourState = PBS_Hunting; |
| | 1583 | predator_change_behaviour(sbPtr); |
| | 1584 | } |
| | 1585 | */ |
| | 1586 | |
| | 1587 | switch(predatorStatusPointer->behaviourState) |
| | 1588 | { |
| | 1589 | case PBS_Attacking: |
| | 1590 | { |
| | 1591 | descriptor = "Attacking"; |
| | 1592 | |
| | 1593 | if(0) |
| | 1594 | if (predatorIsNear) |
| | 1595 | { |
| | 1596 | if(predatorStatusPointer->Angry) |
| | 1597 | { |
| | 1598 | /* |
| | 1599 | VECTORCH orientationDirn; |
| | 1600 | //NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 1601 | orientationDirn = sbPtr->DynPtr->Position; |
| | 1602 | |
| | 1603 | //orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; |
| | 1604 | //orientationDirn.vy = 0; |
| | 1605 | //orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; |
| | 1606 | |
| | 1607 | printf("x %d y %d z %d\n", orientationDirn.vx, orientationDirn.vy, orientationDirn.vz); |
| | 1608 | puts("REAL"); |
| | 1609 | */ |
| | 1610 | printf("x %d y %d z %d\n", sbPtr->DynPtr->Position.vx, sbPtr->DynPtr->Position.vy, sbPtr->DynPtr->Position.vz); |
| | 1611 | //if(NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE)) |
| | 1612 | if(NPCOrientateToVector(sbPtr, &predatorStatusPointer->weaponTarget, NPC_TURNRATE)) |
| | 1613 | { |
| | 1614 | predatorStatusPointer->Angry -= NormalFrameTime; |
| | 1615 | |
| | 1616 | if(predatorStatusPointer->Angry < 0) |
| | 1617 | { |
| | 1618 | predatorStatusPointer->Angry = 0; |
| | 1619 | |
| | 1620 | if(sbPtr == predatorStatusPointer->closets_target) |
| | 1621 | predatorStatusPointer->closets_target = NULL; |
| | 1622 | |
| | 1623 | if ((FastRandom() & 65535) < 32767) |
| | 1624 | { |
| | 1625 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_Taunt_One)) |
| | 1626 | { |
| | 1627 | int rand = FastRandom(); |
| | 1628 | int pitch = (rand & 255) - 128; |
| | 1629 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 1630 | predatorStatusPointer->behaviourState = PBS_Taunting; |
| | 1631 | predatorStatusPointer->stateTimer = NPC_AVOIDTIME; |
| | 1632 | /* Become patient again. */ |
| | 1633 | predatorStatusPointer->patience = PRED_PATIENCE_TIME; |
| | 1634 | predatorStatusPointer->enableTaunt = 0; |
| | 1635 | |
| | 1636 | SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Taunt_One, -1, (ONE_FIXED >> 3)); |
| | 1637 | |
| | 1638 | predatorStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 1639 | |
| | 1640 | if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) |
| | 1641 | PlayPredatorSound(0, PSC_Taunt, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position); |
| | 1642 | } |
| | 1643 | } |
| | 1644 | else |
| | 1645 | { |
| | 1646 | predatorStatusPointer->behaviourState = PBS_Wandering; |
| | 1647 | predator_change_behaviour(sbPtr); |
| | 1648 | } |
| | 1649 | } |
| | 1650 | else |
| | 1651 | { |
| | 1652 | if (!predatorStatusPointer->internalState) |
| | 1653 | { |
| | 1654 | if (predatorStatusPointer->HModelController.Tweening == Controller_NoTweening) |
| | 1655 | predatorStatusPointer->HModelController.Playing = 0; |
| | 1656 | } |
| | 1657 | |
| | 1658 | if(0) |
| | 1659 | if ((FastRandom() & 65535) < 2767) |
| | 1660 | { |
| | 1661 | predatorStatusPointer->enableTaunt = 1; |
| | 1662 | predatorStatusPointer->HModelController.Playing = 1; |
| | 1663 | predatorStatusPointer->HModelController.Looped = 0; |
| | 1664 | predatorStatusPointer->HModelController.sequence_timer = 0; |
| | 1665 | predatorStatusPointer->internalState = 2; |
| | 1666 | |
| | 1667 | /* look after the sound */ |
| | 1668 | Sound_Play(SID_PRED_LAUNCHER, "d", &sbPtr->DynPtr->Position); |
| | 1669 | |
| | 1670 | VECTORCH shotVector; |
| | 1671 | SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash"); |
| | 1672 | |
| | 1673 | shotVector.vx = muzzle->SecMat.mat31; |
| | 1674 | shotVector.vy = muzzle->SecMat.mat32; |
| | 1675 | shotVector.vz = muzzle->SecMat.mat33; |
| | 1676 | |
| | 1677 | shotVector.vx += ((FastRandom() % (ONE_FIXED >> 3)) - (ONE_FIXED >> 11)); |
| | 1678 | shotVector.vy += ((FastRandom() % (ONE_FIXED >> 3)) - (ONE_FIXED >> 11)); |
| | 1679 | shotVector.vz += ((FastRandom() % (ONE_FIXED >> 3)) - (ONE_FIXED >> 11)); |
| | 1680 | Normalise(&shotVector); |
| | 1681 | |
| | 1682 | //predatorStatusPointer->weaponTarget = shotVector; |
| | 1683 | |
| | 1684 | InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat, 0,
&TemplateAmmo[AMMO_PLASMACASTER].MaxDamage, 65536); |
| | 1685 | |
| | 1686 | //predatorStatusPointer->stateTimer = ONE_FIXED; |
| | 1687 | } |
| | 1688 | |
| | 1689 | } |
| | 1690 | //puts("YES!!"); |
| | 1691 | } |
| | 1692 | else |
| | 1693 | { |
| | 1694 | //puts("NO!!"); |
| | 1695 | DoPredatorRandomSound(sbPtr); |
| | 1696 | } |
| | 1697 | //return; |
| | 1698 | } |
| | 1699 | else |
| | 1700 | { |
| | 1701 | SetPredatorElevation(sbPtr); |
| | 1702 | |
| | 1703 | VECTORCH orientationDirn; |
| | 1704 | NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 1705 | orientationDirn.vx = predatorStatusPointer->closets_target->DynPtr->Position.vx - sbPtr->DynPtr->Position.vx; |
| | 1706 | orientationDirn.vy = 0; |
| | 1707 | orientationDirn.vz = predatorStatusPointer->closets_target->DynPtr->Position.vz - sbPtr->DynPtr->Position.vz; |
| | 1708 | |
| | 1709 | if(NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE)) |
| | 1710 | { |
| | 1711 | int range = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position, &sbPtr->DynPtr->Position); |
| | 1712 | (*predatorStatusPointer->Selected_Weapon->WeaponFireFunction)(sbPtr, range); |
| | 1713 | } |
| | 1714 | } |
| | 1715 | } |
| | 1716 | else |
| | 1717 | { |
| | 1718 | predatorStatusPointer->behaviourState = PBS_Hunting; |
| | 1719 | predator_change_behaviour(sbPtr); |
| | 1720 | } |
| | 1721 | } |
| | 1722 | break; |
| | 1723 | case PBS_Wandering: |
| | 1724 | { |
| | 1725 | descriptor = "Wandering"; |
| | 1726 | |
| | 1727 | if (predatorIsNear) |
| | 1728 | { |
| | 1729 | VECTORCH velocityDirection = {0,0,0}; |
| | 1730 | |
| | 1731 | //PredatorHandleMovingAnimation(sbPtr); |
| | 1732 | |
| | 1733 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 1734 | { |
| | 1735 | predatorStatusPointer->behaviourState = PBS_Engaging; /* doesn't require a sequence change */ |
| | 1736 | predator_change_behaviour(sbPtr); |
| | 1737 | break; |
| | 1738 | } |
| | 1739 | |
| | 1740 | /* Are we using bimble rules? */ |
| | 1741 | |
| | 1742 | if (predatorStatusPointer->wanderData.currentModule == NPC_BIMBLINGINMODULE) |
| | 1743 | { |
| | 1744 | int range = VectorDistance(&predatorStatusPointer->wanderData.worldPosition, &sbPtr->DynPtr->Position); |
| | 1745 | |
| | 1746 | if (range < 2000) |
| | 1747 | predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE; /* Reset system, try again. */ |
| | 1748 | } |
| | 1749 | else |
| | 1750 | { |
| | 1751 | /* wander target aquisition: if no target, or moved module */ |
| | 1752 | |
| | 1753 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 1754 | { |
| | 1755 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1756 | NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0); |
| | 1757 | } |
| | 1758 | else if(predatorStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index) |
| | 1759 | { |
| | 1760 | NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0); |
| | 1761 | } |
| | 1762 | |
| | 1763 | /* if we still haven't got one, bimble about in this one for a bit. */ |
| | 1764 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 1765 | { |
| | 1766 | NPC_GetBimbleTarget(sbPtr, &predatorStatusPointer->wanderData.worldPosition); |
| | 1767 | predatorStatusPointer->wanderData.currentModule = NPC_BIMBLINGINMODULE; |
| | 1768 | } |
| | 1769 | } |
| | 1770 | |
| | 1771 | /* ok: should have a current target at this stage... */ |
| | 1772 | NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager); |
| | 1773 | NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); |
| | 1774 | |
| | 1775 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 1776 | if (New_NPC_IsObstructed(sbPtr, &predatorStatusPointer->avoidanceManager)) |
| | 1777 | predatorStatusPointer->behaviourState = PBS_Avoidance; |
| | 1778 | |
| | 1779 | CentrePredatorElevation(sbPtr); |
| | 1780 | } |
| | 1781 | else |
| | 1782 | { |
| | 1783 | /* Patrick 4/7/97 -------------------------------------------------- |
| | 1784 | The various far state behaviour execution functions for predator... |
| | 1785 | |
| | 1786 | 1. Wandering is the initial far state, to which the predator never |
| | 1787 | returns: after becoming visible for the first time, it will use only |
| | 1788 | hunt and retreat |
| | 1789 | 2. Hunting is used if the predator feels confident enough to engage |
| | 1790 | the player. |
| | 1791 | 3. Retreating is used if the predator is not confident |
| | 1792 | ---------------------------------------------------------------------*/ |
| | 1793 | |
| | 1794 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 1795 | /* check if far state timer has timed-out. If so, it is time |
| | 1796 | to do something. Otherwise just return. */ |
| | 1797 | |
| | 1798 | if(predatorStatusPointer->stateTimer > 0) |
| | 1799 | break; |
| | 1800 | |
| | 1801 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 1802 | { |
| | 1803 | predatorStatusPointer->behaviourState = PBS_Engaging; /* we should be hunting */ |
| | 1804 | predator_change_behaviour(sbPtr); |
| | 1805 | break; |
| | 1806 | } |
| | 1807 | |
| | 1808 | /* Preds NEVER camp. I mean, get tired of wandering. */ |
| | 1809 | |
| | 1810 | /* timer has timed-out in roving mode */ |
| | 1811 | AIMODULE *targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr, NULL, 0); |
| | 1812 | |
| | 1813 | /* if there is no target module, it means that the pred is trapped in an |
| | 1814 | unlinked module. In this case, reset the timer and return. */ |
| | 1815 | |
| | 1816 | if(!targetModule) |
| | 1817 | { |
| | 1818 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 1819 | break; |
| | 1820 | } |
| | 1821 | |
| | 1822 | /* Examine target, and decide what to do */ |
| | 1823 | //assert(AIModuleIsPhysical(targetModule)); |
| | 1824 | ProcessFarPredatorTargetAIModule(sbPtr, targetModule); |
| | 1825 | /* reset timer */ |
| | 1826 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 1827 | } |
| | 1828 | } |
| | 1829 | break; |
| | 1830 | case PBS_Avoidance: |
| | 1831 | { |
| | 1832 | switch (predatorStatusPointer->avoidanceManager.substate) |
| | 1833 | { |
| | 1834 | default: |
| | 1835 | case AvSS_FreeMovement: |
| | 1836 | descriptor = "Avoidance Level 0"; |
| | 1837 | break; |
| | 1838 | case AvSS_FirstAvoidance: |
| | 1839 | descriptor = "Avoidance Level 1"; |
| | 1840 | break; |
| | 1841 | case AvSS_SecondAvoidance: |
| | 1842 | descriptor = "Avoidance Level 2"; |
| | 1843 | break; |
| | 1844 | case AvSS_ThirdAvoidance: |
| | 1845 | descriptor = "Avoidance Level 3"; |
| | 1846 | } |
| | 1847 | |
| | 1848 | if (predatorIsNear) |
| | 1849 | { |
| | 1850 | /* first check for a close attack... */ |
| | 1851 | //if(VectorDistance(&PlayerStatus.sbptr->DynPtr->Position, &sbPtr->DynPtr->Position) < PRED_CLOSE_ATTACK_RANGE) return
PRC_Request_Attack; |
| | 1852 | |
| | 1853 | NPCSetVelocity(sbPtr, &predatorStatusPointer->avoidanceManager.avoidanceDirection, predatorStatusPointer->nearSpeed); |
| | 1854 | |
| | 1855 | /* Velocity CANNOT be zero, unless deliberately so! */ |
| | 1856 | |
| | 1857 | //PredatorHandleMovingAnimation(sbPtr); |
| | 1858 | |
| | 1859 | if (AllNewAvoidanceKernel(sbPtr, &predatorStatusPointer->avoidanceManager) != AvRC_Avoidance) |
| | 1860 | { |
| | 1861 | /* Better exit. */ |
| | 1862 | switch (predatorStatusPointer->lastState) |
| | 1863 | { |
| | 1864 | case PBS_Avoidance: |
| | 1865 | default: |
| | 1866 | /* switch to approach */ |
| | 1867 | if(predatorStatusPointer->health > predatorCV[predatorStatusPointer->personalNumber].defenceHealth) |
| | 1868 | { |
| | 1869 | /* go to approach */ |
| | 1870 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1871 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 1872 | } |
| | 1873 | else |
| | 1874 | { |
| | 1875 | /* go to retreat */ |
| | 1876 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 1877 | predatorStatusPointer->behaviourState = PBS_Withdrawing; |
| | 1878 | } |
| | 1879 | break; |
| | 1880 | case PBS_Wandering: |
| | 1881 | case PBS_Hunting: |
| | 1882 | case PBS_Withdrawing: |
| | 1883 | case PBS_Returning: |
| | 1884 | case PBS_Pathfinding: |
| | 1885 | predatorStatusPointer->behaviourState = predatorStatusPointer->lastState; |
| | 1886 | break; |
| | 1887 | case PBS_Engaging: |
| | 1888 | case PBS_Attacking: |
| | 1889 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 1890 | } |
| | 1891 | predator_change_behaviour(sbPtr); |
| | 1892 | } |
| | 1893 | |
| | 1894 | CentrePredatorElevation(sbPtr); |
| | 1895 | } |
| | 1896 | else |
| | 1897 | { |
| | 1898 | /* High on the list of Things Not To Be Doing. */ |
| | 1899 | |
| | 1900 | Initialise_AvoidanceManager(&predatorStatusPointer->avoidanceManager); |
| | 1901 | |
| | 1902 | switch (predatorStatusPointer->lastState) |
| | 1903 | { |
| | 1904 | case PBS_Recovering: |
| | 1905 | case PBS_Hunting: |
| | 1906 | case PBS_Engaging: |
| | 1907 | /* Go directly to approach. Do not pass GO. Do not collect 200 zorkmids. */ |
| | 1908 | predatorStatusPointer->behaviourState = predatorStatusPointer->lastState; |
| | 1909 | break; |
| | 1910 | default: |
| | 1911 | predatorStatusPointer->behaviourState = PBS_Wandering; |
| | 1912 | } |
| | 1913 | |
| | 1914 | predator_change_behaviour(sbPtr); |
| | 1915 | } |
| | 1916 | } |
| | 1917 | break; |
| | 1918 | case PBS_SwapWeapon: |
| | 1919 | { |
| | 1920 | descriptor = "Swapping"; |
| | 1921 | |
| | 1922 | Verify_Positions_In_HModel(sbPtr, &predatorStatusPointer->HModelController, "Predator Swap Weapon Start"); |
| | 1923 | |
| | 1924 | if (!predatorStatusPointer->stateTimer) |
| | 1925 | { |
| | 1926 | /* Haven't started yet. */ |
| | 1927 | |
| | 1928 | #ifdef SHOWPREDOSTATS |
| | 1929 | printf("Part one "); |
| | 1930 | #endif |
| | 1931 | |
| | 1932 | /* Right. Is there a 'deselect' anim? */ |
| | 1933 | if (predatorStatusPointer->IAmCrouched) |
| | 1934 | { |
| | 1935 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon)) |
| | 1936 | { |
| | 1937 | /* It's there! */ |
| | 1938 | if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0) |
| | 1939 | { |
| | 1940 | /* Valid swap time, too. */ |
| | 1941 | InitHModelTweening_Backwards(&predatorStatusPointer->HModelController, (ONE_FIXED >> 2), |
| | 1942 | (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon, predatorStatusPointer->Selected_Weapon->SwappingTime,0); |
| | 1943 | predatorStatusPointer->HModelController.Looped = 0; |
| | 1944 | predatorStatusPointer->stateTimer = 1; /* Swapping Out. */ |
| | 1945 | } |
| | 1946 | } |
| | 1947 | } |
| | 1948 | else if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon)) |
| | 1949 | { |
| | 1950 | /* It's there! */ |
| | 1951 | if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0) |
| | 1952 | { |
| | 1953 | /* Valid swap time, too. */ |
| | 1954 | InitHModelTweening_Backwards(&predatorStatusPointer->HModelController,
(ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon, |
| | 1955 | predatorStatusPointer->Selected_Weapon->SwappingTime,0); |
| | 1956 | predatorStatusPointer->HModelController.Looped = 0; |
| | 1957 | predatorStatusPointer->stateTimer = 1; /* Swapping Out. */ |
| | 1958 | } |
| | 1959 | } |
| | 1960 | |
| | 1961 | /* If you're still here, there must be no swapping out sequence. */ |
| | 1962 | predatorStatusPointer->stateTimer = 2; |
| | 1963 | /* Ah well, go directly to the middle. */ |
| | 1964 | } |
| | 1965 | else if (predatorStatusPointer->stateTimer == 1) |
| | 1966 | { |
| | 1967 | /* You are in the process of swapping out. */ |
| | 1968 | |
| | 1969 | #ifdef SHOWPREDOSTATS |
| | 1970 | printf("Part two "); |
| | 1971 | #endif |
| | 1972 | |
| | 1973 | if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) |
| | 1974 | predatorStatusPointer->stateTimer = 2; |
| | 1975 | } |
| | 1976 | else if (predatorStatusPointer->stateTimer == 2) |
| | 1977 | { |
| | 1978 | /* In the middle! */ |
| | 1979 | const PREDATOR_WEAPON_DATA *targetWeapon = GetThisNPCPredatorWeapon(predatorStatusPointer->ChangeToWeapon); |
| | 1980 | |
| | 1981 | #ifdef SHOWPREDOSTATS |
| | 1982 | printf("Part three "); |
| | 1983 | #endif |
| | 1984 | |
| | 1985 | predatorStatusPointer->Selected_Weapon = targetWeapon; |
| | 1986 | |
| | 1987 | SECTION *root_section = GetNamedHierarchyFromLibrary("hnpcpredator", predatorStatusPointer->Selected_Weapon->HierarchyName); |
| | 1988 | assert(root_section); |
| | 1989 | |
| | 1990 | /* Strip out HitDelta for now, if any... */ |
| | 1991 | { |
| | 1992 | DELTA_CONTROLLER *delta = Get_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); |
| | 1993 | |
| | 1994 | if (delta) |
| | 1995 | Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"HitDelta"); |
| | 1996 | } |
| | 1997 | |
| | 1998 | /* Strip off elevation too. */ |
| | 1999 | { |
| | 2000 | DELTA_CONTROLLER *delta = Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); |
| | 2001 | |
| | 2002 | if (delta) |
| | 2003 | Remove_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation"); |
| | 2004 | } |
| | 2005 | |
| | 2006 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Two"); |
| | 2007 | |
| | 2008 | /* In the interests of getting the new sections right... */ |
| | 2009 | predatorStatusPointer->HModelController.Sequence_Type = (int)HMSQT_PredatorStand; |
| | 2010 | predatorStatusPointer->HModelController.Sub_Sequence = (int)PSSS_Get_Weapon; |
| | 2011 | |
| | 2012 | Transmogrify_HModels(sbPtr, &predatorStatusPointer->HModelController, root_section, 0, 1, 0); |
| | 2013 | |
| | 2014 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,(int)PSSS_HitChestFront)) |
| | 2015 | { |
| | 2016 | /* This ritual in case _one_ of the hierarchies doesn't have hitdeltas. */ |
| | 2017 | DELTA_CONTROLLER *delta = Add_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta",
(int)HMSQT_PredatorStand, (int)PSSS_HitChestFront, -1); |
| | 2018 | assert(delta); |
| | 2019 | delta->Playing = 0; |
| | 2020 | } |
| | 2021 | |
| | 2022 | /* Replace elevation. */ |
| | 2023 | if (predatorStatusPointer->Selected_Weapon->UseElevation) |
| | 2024 | { |
| | 2025 | if (Get_Delta_Sequence(&predatorStatusPointer->HModelController,"Elevation") == NULL) |
| | 2026 | { |
| | 2027 | DELTA_CONTROLLER *delta = Add_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation",
(int)HMSQT_PredatorStand, (int)PSSS_Elevation, 0); |
| | 2028 | assert(delta); |
| | 2029 | delta->timer = 32767; |
| | 2030 | } |
| | 2031 | } |
| | 2032 | else |
| | 2033 | { |
| | 2034 | /* Better make sure it's gone... */ |
| | 2035 | Remove_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation"); |
| | 2036 | } |
| | 2037 | |
| | 2038 | Verify_Positions_In_HModel(sbPtr, &predatorStatusPointer->HModelController, "Predator Swap Weapon Two A"); |
| | 2039 | |
| | 2040 | DeInitialise_HModel(&predatorStatusPointer->HModelController); |
| | 2041 | ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); |
| | 2042 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Three"); |
| | 2043 | |
| | 2044 | predatorStatusPointer->My_Elevation_Section =
GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName); |
| | 2045 | |
| | 2046 | /* Now go for the Get_Weapon sequence. */ |
| | 2047 | if (predatorStatusPointer->IAmCrouched) |
| | 2048 | { |
| | 2049 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorCrouch,(int)PCrSS_Get_Weapon)) |
| | 2050 | { |
| | 2051 | /* It's there! */ |
| | 2052 | if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0) |
| | 2053 | { |
| | 2054 | /* Valid swap time, too. */ |
| | 2055 | predatorStatusPointer->HModelController.Sequence_Type = (int)HMSQT_PredatorCrouch; |
| | 2056 | predatorStatusPointer->HModelController.Sub_Sequence = (int)PCrSS_Get_Weapon; |
| | 2057 | predatorStatusPointer->HModelController.Seconds_For_Sequence = predatorStatusPointer->Selected_Weapon->SwappingTime; |
| | 2058 | /* That to get the new sections right. */ |
| | 2059 | InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>2), (int)HMSQT_PredatorCrouch, (int)PCrSS_Get_Weapon,
predatorStatusPointer->Selected_Weapon->SwappingTime, 0); |
| | 2060 | predatorStatusPointer->HModelController.Looped = 0; |
| | 2061 | predatorStatusPointer->stateTimer = 3; /* Swapping In. */ |
| | 2062 | |
| | 2063 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Three A"); |
| | 2064 | ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); |
| | 2065 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Four"); |
| | 2066 | } |
| | 2067 | } |
| | 2068 | } |
| | 2069 | else |
| | 2070 | { |
| | 2071 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_Get_Weapon)) |
| | 2072 | { |
| | 2073 | /* It's there! */ |
| | 2074 | if (predatorStatusPointer->Selected_Weapon->SwappingTime != 0) |
| | 2075 | { |
| | 2076 | /* Valid swap time, too. */ |
| | 2077 | predatorStatusPointer->HModelController.Sequence_Type = (int)HMSQT_PredatorStand; |
| | 2078 | predatorStatusPointer->HModelController.Sub_Sequence = (int)PSSS_Get_Weapon; |
| | 2079 | predatorStatusPointer->HModelController.Seconds_For_Sequence = predatorStatusPointer->Selected_Weapon->SwappingTime; |
| | 2080 | /* That to get the new sections right. */ |
| | 2081 | InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>2),(int)HMSQT_PredatorStand,(int)PSSS_Get_Weapon,
predatorStatusPointer->Selected_Weapon->SwappingTime,0); |
| | 2082 | predatorStatusPointer->HModelController.Looped = 0; |
| | 2083 | predatorStatusPointer->stateTimer = 3; /* Swapping In. */ |
| | 2084 | |
| | 2085 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Four A"); |
| | 2086 | ProveHModel_Far(&predatorStatusPointer->HModelController,sbPtr); |
| | 2087 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Five"); |
| | 2088 | } |
| | 2089 | } |
| | 2090 | } |
| | 2091 | |
| | 2092 | /* If you're still here, there must be no swapping in sequence. */ |
| | 2093 | predatorStatusPointer->stateTimer = 4; |
| | 2094 | /* Ah well, go directly to the end. */ |
| | 2095 | |
| | 2096 | Verify_Positions_In_HModel(sbPtr,&predatorStatusPointer->HModelController, "Predator Swap Weapon Six"); |
| | 2097 | } |
| | 2098 | else if (predatorStatusPointer->stateTimer == 3) |
| | 2099 | { |
| | 2100 | /* You are in the process of swapping in. */ |
| | 2101 | |
| | 2102 | #ifdef SHOWPREDOSTATS |
| | 2103 | printf("Part four "); |
| | 2104 | #endif |
| | 2105 | |
| | 2106 | if (HModelAnimation_IsFinished(&predatorStatusPointer->HModelController)) |
| | 2107 | predatorStatusPointer->stateTimer = 4; |
| | 2108 | } |
| | 2109 | else if (predatorStatusPointer->stateTimer == 4) |
| | 2110 | { |
| | 2111 | /* All (valid) conclusions arrive here. */ |
| | 2112 | |
| | 2113 | #ifdef SHOWPREDOSTATS |
| | 2114 | printf("Part five "); |
| | 2115 | #endif |
| | 2116 | |
| | 2117 | predatorStatusPointer->ChangeToWeapon = PNPCW_End; |
| | 2118 | |
| | 2119 | if(predatorStatusPointer->Angry) |
| | 2120 | predatorStatusPointer->behaviourState = PBS_Attacking; |
| | 2121 | else |
| | 2122 | predatorStatusPointer->behaviourState = (predatorStatusPointer->Selected_Weapon->id == PNPCW_Medicomp) ? PBS_Recovering :
PBS_Engaging; |
| | 2123 | |
| | 2124 | predator_change_behaviour(sbPtr); |
| | 2125 | } |
| | 2126 | |
| | 2127 | #ifdef SHOWPREDOSTATS |
| | 2128 | printf("No Part %d ", predatorStatusPointer->stateTimer); |
| | 2129 | #endif |
| | 2130 | |
| | 2131 | if (predatorIsNear) |
| | 2132 | CentrePredatorElevation(sbPtr); |
| | 2133 | else |
| | 2134 | ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr); |
| | 2135 | } |
| | 2136 | break; |
| | 2137 | case PBS_Withdrawing: |
| | 2138 | { |
| | 2139 | descriptor = "Withdrawing"; |
| | 2140 | |
| | 2141 | if (predatorIsNear) |
| | 2142 | { |
| | 2143 | VECTORCH velocityDirection = {0,0,0}; |
| | 2144 | |
| | 2145 | /* Your mission: to advance out of trouble, even if near. */ |
| | 2146 | |
| | 2147 | //PredatorHandleMovingAnimation(sbPtr); |
| | 2148 | |
| | 2149 | AIMODULE *old_fearmodule = predatorStatusPointer->fearmodule; |
| | 2150 | |
| | 2151 | if (!(predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule))) |
| | 2152 | { |
| | 2153 | predatorStatusPointer->behaviourState = PBS_Recovering; /* What am I running from? */ |
| | 2154 | predator_change_behaviour(sbPtr); |
| | 2155 | break; |
| | 2156 | } |
| | 2157 | else |
| | 2158 | { |
| | 2159 | predatorStatusPointer->fearmodule = predatorStatusPointer->closets_target->containingModule->m_aimodule; |
| | 2160 | |
| | 2161 | if (predatorStatusPointer->fearmodule == NULL) |
| | 2162 | predatorStatusPointer->fearmodule = sbPtr->containingModule->m_aimodule; |
| | 2163 | } |
| | 2164 | |
| | 2165 | if ((predatorStatusPointer->missionmodule == NULL) || (predatorStatusPointer->fearmodule != old_fearmodule)) |
| | 2166 | { |
| | 2167 | /* Recompute mission module. */ |
| | 2168 | if (predatorStatusPointer->fearmodule) |
| | 2169 | predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5); |
| | 2170 | else |
| | 2171 | predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,PlayerStatus.sbptr->containingModule->m_aimodule,
5); |
| | 2172 | } |
| | 2173 | |
| | 2174 | { |
| | 2175 | if (predatorStatusPointer->missionmodule == NULL) |
| | 2176 | { |
| | 2177 | predatorStatusPointer->behaviourState = PBS_Recovering; /* Hey, it'll drop through. */ |
| | 2178 | break; |
| | 2179 | } |
| | 2180 | |
| | 2181 | AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule, predatorStatusPointer->missionmodule, 6, 0); |
| | 2182 | |
| | 2183 | #ifdef SHOWPREDOSTATS |
| | 2184 | |
| | 2185 | printf("closets_target Module %s.\n",(*(predatorStatusPointer->missionmodule->m_module_ptrs))->name); |
| | 2186 | |
| | 2187 | if (targetModule) |
| | 2188 | printf("Next Module is %s.\n", (*(targetModule->m_module_ptrs))->name); |
| | 2189 | else |
| | 2190 | printf("Next Module is NULL!\n"); |
| | 2191 | #endif |
| | 2192 | |
| | 2193 | if ((targetModule == sbPtr->containingModule->m_aimodule) || (targetModule == NULL)) |
| | 2194 | { |
| | 2195 | predatorStatusPointer->behaviourState = PBS_Recovering; /* Hey, it'll drop through. */ |
| | 2196 | predator_change_behaviour(sbPtr); |
| | 2197 | break; |
| | 2198 | } |
| | 2199 | |
| | 2200 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); |
| | 2201 | |
| | 2202 | if (!thisEp) |
| | 2203 | { |
| | 2204 | printf("This assert is a busted adjacency!"); |
| | 2205 | assert(thisEp); |
| | 2206 | } |
| | 2207 | /* If that fired, there's a farped adjacency. */ |
| | 2208 | |
| | 2209 | predatorStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 2210 | predatorStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx; |
| | 2211 | predatorStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy; |
| | 2212 | predatorStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz; |
| | 2213 | } |
| | 2214 | |
| | 2215 | /* ok: should have a current target at this stage... */ |
| | 2216 | NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager); |
| | 2217 | NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); |
| | 2218 | |
| | 2219 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 2220 | if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) |
| | 2221 | predatorStatusPointer->behaviourState = PBS_Avoidance; /* Go to all new avoidance. */ |
| | 2222 | |
| | 2223 | CentrePredatorElevation(sbPtr); |
| | 2224 | } |
| | 2225 | else |
| | 2226 | { |
| | 2227 | AIMODULE *old_fearmodule = predatorStatusPointer->fearmodule; |
| | 2228 | |
| | 2229 | /* Decrement the state timer */ |
| | 2230 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 2231 | |
| | 2232 | /* check for state changes: randomly decide to switch to recover... */ |
| | 2233 | if(!(predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 2234 | || (predatorStatusPointer->incidentFlag && !NPCCanSeeTarget(sbPtr, predatorStatusPointer->closets_target))) |
| | 2235 | { |
| | 2236 | predatorStatusPointer->behaviourState = PBS_Recovering; /* What am I running from? */ |
| | 2237 | predator_change_behaviour(sbPtr); |
| | 2238 | break; |
| | 2239 | } |
| | 2240 | |
| | 2241 | if(predatorStatusPointer->stateTimer > 0) |
| | 2242 | break; |
| | 2243 | |
| | 2244 | /* timer has timed-out in retreat mode: */ |
| | 2245 | |
| | 2246 | /* Yeah, from where _am_ I running? */ |
| | 2247 | |
| | 2248 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 2249 | { |
| | 2250 | predatorStatusPointer->fearmodule = predatorStatusPointer->closets_target->containingModule->m_aimodule; |
| | 2251 | } |
| | 2252 | else if (predatorStatusPointer->fearmodule == NULL) |
| | 2253 | { |
| | 2254 | predatorStatusPointer->fearmodule = sbPtr->containingModule->m_aimodule; |
| | 2255 | } |
| | 2256 | |
| | 2257 | if ((predatorStatusPointer->missionmodule == NULL) || (predatorStatusPointer->fearmodule != old_fearmodule)) |
| | 2258 | { |
| | 2259 | /* Recompute mission module. */ |
| | 2260 | if (predatorStatusPointer->fearmodule) |
| | 2261 | predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,predatorStatusPointer->fearmodule,5); |
| | 2262 | else |
| | 2263 | predatorStatusPointer->missionmodule = General_GetAIModuleForRetreat(sbPtr,PlayerStatus.sbptr->containingModule->m_aimodule,5); |
| | 2264 | } |
| | 2265 | |
| | 2266 | if (predatorStatusPointer->missionmodule == NULL) |
| | 2267 | { |
| | 2268 | predatorStatusPointer->behaviourState = PBS_Recovering; /* Hey, it'll drop through. */ |
| | 2269 | predator_change_behaviour(sbPtr); |
| | 2270 | break; |
| | 2271 | } |
| | 2272 | |
| | 2273 | AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,6,0); |
| | 2274 | |
| | 2275 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 2276 | |
| | 2277 | if(!targetModule) |
| | 2278 | { |
| | 2279 | predatorStatusPointer->behaviourState = PBS_Recovering; |
| | 2280 | predator_change_behaviour(sbPtr); |
| | 2281 | break; |
| | 2282 | } |
| | 2283 | |
| | 2284 | /* Examine target, and decide what to do */ |
| | 2285 | //assert(AIModuleIsPhysical(targetModule)); |
| | 2286 | ProcessFarPredatorTargetAIModule(sbPtr, targetModule); |
| | 2287 | } |
| | 2288 | } |
| | 2289 | break; |
| | 2290 | case PBS_Returning: |
| | 2291 | { |
| | 2292 | descriptor = "Returning"; |
| | 2293 | |
| | 2294 | if (predatorIsNear) |
| | 2295 | { |
| | 2296 | VECTORCH velocityDirection = {0,0,0}; |
| | 2297 | |
| | 2298 | //PredatorHandleMovingAnimation(sbPtr); |
| | 2299 | |
| | 2300 | /* should we change to approach state? */ |
| | 2301 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 2302 | { |
| | 2303 | predatorStatusPointer->behaviourState = PBS_Engaging; /* doesn't require a sequence change */ |
| | 2304 | predator_change_behaviour(sbPtr); |
| | 2305 | break; |
| | 2306 | } |
| | 2307 | |
| | 2308 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 2309 | |
| | 2310 | /* Are we there yet? */ |
| | 2311 | if (sbPtr->containingModule->m_aimodule == predatorStatusPointer->missionmodule) |
| | 2312 | { |
| | 2313 | predatorStatusPointer->behaviourState = PBS_Pathfinding; |
| | 2314 | } |
| | 2315 | |
| | 2316 | /* closets_target module aquisition. */ |
| | 2317 | |
| | 2318 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2319 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 2320 | |
| | 2321 | if ((predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2322 | ||(predatorStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index)) |
| | 2323 | { |
| | 2324 | AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,predatorStatusPointer->missionmodule,7,0); |
| | 2325 | |
| | 2326 | if (targetModule) |
| | 2327 | { |
| | 2328 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); |
| | 2329 | |
| | 2330 | if(thisEp) |
| | 2331 | { |
| | 2332 | /* aha. an ep!... */ |
| | 2333 | VECTORCH thisEpWorld = thisEp->position; |
| | 2334 | |
| | 2335 | thisEpWorld.vx += targetModule->m_world.vx; |
| | 2336 | thisEpWorld.vy += targetModule->m_world.vy; |
| | 2337 | thisEpWorld.vz += targetModule->m_world.vz; |
| | 2338 | |
| | 2339 | predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; |
| | 2340 | predatorStatusPointer->wanderData.worldPosition = thisEpWorld; |
| | 2341 | } |
| | 2342 | else |
| | 2343 | { |
| | 2344 | /* Failure case. */ |
| | 2345 | predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE; |
| | 2346 | } |
| | 2347 | } |
| | 2348 | else |
| | 2349 | { |
| | 2350 | /* Another failure case. */ |
| | 2351 | predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE; |
| | 2352 | } |
| | 2353 | } |
| | 2354 | |
| | 2355 | /* if we still haven't got one, bimble about in this one for a bit. */ |
| | 2356 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2357 | { |
| | 2358 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 2359 | NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0); |
| | 2360 | |
| | 2361 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2362 | { |
| | 2363 | predatorStatusPointer->behaviourState = PBS_Wandering; /* STILL broken! Okay, just... wander, then. */ |
| | 2364 | predator_change_behaviour(sbPtr); |
| | 2365 | break; |
| | 2366 | } |
| | 2367 | } |
| | 2368 | |
| | 2369 | /* ok: should have a current target at this stage... */ |
| | 2370 | NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager); |
| | 2371 | NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); |
| | 2372 | |
| | 2373 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 2374 | if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) |
| | 2375 | { |
| | 2376 | predatorStatusPointer->behaviourState = PBS_Avoidance; |
| | 2377 | predator_change_behaviour(sbPtr); |
| | 2378 | } |
| | 2379 | |
| | 2380 | CentrePredatorElevation(sbPtr); |
| | 2381 | } |
| | 2382 | else |
| | 2383 | { |
| | 2384 | /* Decrement the Far state timer */ |
| | 2385 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 2386 | /* check if far state timer has timed-out. If so, it is time |
| | 2387 | to do something. Otherwise just return. */ |
| | 2388 | |
| | 2389 | if(predatorStatusPointer->stateTimer > 0) |
| | 2390 | break; |
| | 2391 | |
| | 2392 | /* check for state changes */ |
| | 2393 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 2394 | { |
| | 2395 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 2396 | predator_change_behaviour(sbPtr); |
| | 2397 | break; |
| | 2398 | } |
| | 2399 | |
| | 2400 | if (sbPtr->containingModule->m_aimodule == predatorStatusPointer->missionmodule) |
| | 2401 | { |
| | 2402 | predatorStatusPointer->behaviourState = PBS_Pathfinding; |
| | 2403 | predator_change_behaviour(sbPtr); |
| | 2404 | } |
| | 2405 | |
| | 2406 | /* get the target module... */ |
| | 2407 | |
| | 2408 | AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule, predatorStatusPointer->missionmodule, 7, 0); |
| | 2409 | |
| | 2410 | /* If there is no target module, we're way out there. Better wander a bit more. */ |
| | 2411 | |
| | 2412 | if(!targetModule) |
| | 2413 | targetModule = FarNPC_GetTargetAIModuleForWander(sbPtr, NULL, 0); |
| | 2414 | |
| | 2415 | /* Examine target, and decide what to do */ |
| | 2416 | |
| | 2417 | //assert(AIModuleIsPhysical(targetModule)); |
| | 2418 | |
| | 2419 | ProcessFarPredatorTargetAIModule(sbPtr, targetModule); |
| | 2420 | |
| | 2421 | /* reset timer */ |
| | 2422 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 2423 | } |
| | 2424 | } |
| | 2425 | break; |
| | 2426 | case PBS_Pathfinding: |
| | 2427 | { |
| | 2428 | descriptor = "Pathfinding"; |
| | 2429 | |
| | 2430 | if (predatorIsNear) |
| | 2431 | { |
| | 2432 | VECTORCH velocityDirection = {0,0,0}; |
| | 2433 | |
| | 2434 | //PredatorHandleMovingAnimation(sbPtr); |
| | 2435 | |
| | 2436 | /* should we change to approach state? */ |
| | 2437 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 2438 | { |
| | 2439 | predatorStatusPointer->behaviourState = PBS_Engaging; /* doesn't require a sequence change */ |
| | 2440 | predator_change_behaviour(sbPtr); |
| | 2441 | break; |
| | 2442 | } |
| | 2443 | |
| | 2444 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 2445 | |
| | 2446 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2447 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 2448 | |
| | 2449 | if ((predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2450 | || (predatorStatusPointer->wanderData.currentModule != sbPtr->containingModule->m_aimodule->m_index)) |
| | 2451 | { |
| | 2452 | /* Okay, so where are we exactly? */ |
| | 2453 | |
| | 2454 | if ((predatorStatusPointer->stepnumber < 0) || (predatorStatusPointer->path < 0)) |
| | 2455 | { |
| | 2456 | predatorStatusPointer->behaviourState = PBS_Wandering; /* Get OUT! */ |
| | 2457 | predator_change_behaviour(sbPtr); |
| | 2458 | break; |
| | 2459 | } |
| | 2460 | |
| | 2461 | AIMODULE *targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber, predatorStatusPointer->path); |
| | 2462 | |
| | 2463 | if (targetModule == NULL) |
| | 2464 | { |
| | 2465 | predatorStatusPointer->behaviourState = PBS_Wandering; /* Oh, to heck with this. Try to wander. */ |
| | 2466 | } |
| | 2467 | |
| | 2468 | /* Right, so there is a somewhere to get to. */ |
| | 2469 | |
| | 2470 | if (targetModule != sbPtr->containingModule->m_aimodule) |
| | 2471 | { |
| | 2472 | /* But we're nowhere near it. Geeze... */ |
| | 2473 | predatorStatusPointer->missionmodule=targetModule; |
| | 2474 | predatorStatusPointer->behaviourState = PBS_Returning; |
| | 2475 | predator_change_behaviour(sbPtr); |
| | 2476 | break; |
| | 2477 | } |
| | 2478 | |
| | 2479 | /* Okay, so now we need to know where to go now. */ |
| | 2480 | |
| | 2481 | int nextModuleIndex = GetNextModuleInPath(predatorStatusPointer->stepnumber,predatorStatusPointer->path); |
| | 2482 | assert(nextModuleIndex>=0); |
| | 2483 | /* If that fires, it's Richard's fault. */ |
| | 2484 | targetModule = TranslatePathIndex(nextModuleIndex, predatorStatusPointer->path); |
| | 2485 | assert(targetModule); |
| | 2486 | /* Ditto. */ |
| | 2487 | predatorStatusPointer->stepnumber= nextModuleIndex; |
| | 2488 | |
| | 2489 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule, sbPtr->containingModule->m_aimodule); |
| | 2490 | |
| | 2491 | if(thisEp) |
| | 2492 | { |
| | 2493 | /* aha. an ep!... */ |
| | 2494 | VECTORCH thisEpWorld = thisEp->position; |
| | 2495 | |
| | 2496 | thisEpWorld.vx += targetModule->m_world.vx; |
| | 2497 | thisEpWorld.vy += targetModule->m_world.vy; |
| | 2498 | thisEpWorld.vz += targetModule->m_world.vz; |
| | 2499 | |
| | 2500 | predatorStatusPointer->wanderData.currentModule = sbPtr->containingModule->m_aimodule->m_index; |
| | 2501 | predatorStatusPointer->wanderData.worldPosition = thisEpWorld; |
| | 2502 | } |
| | 2503 | else |
| | 2504 | { |
| | 2505 | /* Failure case. */ |
| | 2506 | predatorStatusPointer->wanderData.currentModule = NPC_NOWANDERMODULE; |
| | 2507 | } |
| | 2508 | } |
| | 2509 | |
| | 2510 | /* if we still haven't got one, wander for a bit. */ |
| | 2511 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2512 | { |
| | 2513 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 2514 | NPC_FindAIWanderTarget(sbPtr, &predatorStatusPointer->wanderData, &predatorStatusPointer->moveData, 0); |
| | 2515 | |
| | 2516 | if(predatorStatusPointer->wanderData.currentModule == NPC_NOWANDERMODULE) |
| | 2517 | { |
| | 2518 | predatorStatusPointer->behaviourState = PBS_Wandering; /* STILL broken! Okay, just... wander forever, then. */ |
| | 2519 | predator_change_behaviour(sbPtr); |
| | 2520 | break; |
| | 2521 | } |
| | 2522 | } |
| | 2523 | |
| | 2524 | /* ok: should have a current target at this stage... */ |
| | 2525 | NPCGetMovementDirection(sbPtr, &velocityDirection, &predatorStatusPointer->wanderData.worldPosition,
&predatorStatusPointer->waypointManager); |
| | 2526 | NPCSetVelocity(sbPtr, &velocityDirection, predatorStatusPointer->nearSpeed); |
| | 2527 | |
| | 2528 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 2529 | if (New_NPC_IsObstructed(sbPtr,&predatorStatusPointer->avoidanceManager)) |
| | 2530 | { |
| | 2531 | predatorStatusPointer->behaviourState = PBS_Avoidance; |
| | 2532 | predator_change_behaviour(sbPtr); |
| | 2533 | } |
| | 2534 | |
| | 2535 | CentrePredatorElevation(sbPtr); |
| | 2536 | } |
| | 2537 | else |
| | 2538 | { |
| | 2539 | /* Okay, so you're a LocalGuard or Pathfinder who's gotten lost. */ |
| | 2540 | |
| | 2541 | /* Decrement the Far state timer */ |
| | 2542 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 2543 | |
| | 2544 | /* check if far state timer has timed-out. If so, it is time |
| | 2545 | to do something. Otherwise just return. */ |
| | 2546 | if(predatorStatusPointer->stateTimer > 0) |
| | 2547 | break; |
| | 2548 | |
| | 2549 | /* check for state changes */ /* Hack! */ |
| | 2550 | if (predatorStatusPointer->closets_target && IsModuleVisibleFromModule(sbPtr->containingModule,
predatorStatusPointer->closets_target->containingModule)) |
| | 2551 | { |
| | 2552 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 2553 | predator_change_behaviour(sbPtr); |
| | 2554 | break; |
| | 2555 | } |
| | 2556 | |
| | 2557 | /* Ignore alerts. */ |
| | 2558 | |
| | 2559 | /* Never break out of pathfinder unless your life is in danger! */ |
| | 2560 | |
| | 2561 | /* Okay, so where are we exactly? */ |
| | 2562 | |
| | 2563 | if ((predatorStatusPointer->stepnumber < 0) || (predatorStatusPointer->path < 0)) |
| | 2564 | { |
| | 2565 | predatorStatusPointer->behaviourState = PBS_Wandering; /* Get OUT! */ |
| | 2566 | predator_change_behaviour(sbPtr); |
| | 2567 | break; |
| | 2568 | } |
| | 2569 | |
| | 2570 | AIMODULE *targetModule = TranslatePathIndex(predatorStatusPointer->stepnumber,predatorStatusPointer->path); |
| | 2571 | |
| | 2572 | if (targetModule == NULL) |
| | 2573 | { |
| | 2574 | predatorStatusPointer->behaviourState = PBS_Wandering; /* Oh, to heck with this. Try to wander. */ |
| | 2575 | predator_change_behaviour(sbPtr); |
| | 2576 | break; |
| | 2577 | } |
| | 2578 | |
| | 2579 | /* Right, so there is a somewhere to get to. */ |
| | 2580 | |
| | 2581 | if (targetModule != sbPtr->containingModule->m_aimodule) |
| | 2582 | { |
| | 2583 | /* But we're nowhere near it. Geeze... */ |
| | 2584 | predatorStatusPointer->missionmodule = targetModule; |
| | 2585 | predatorStatusPointer->behaviourState = PBS_Returning; |
| | 2586 | predator_change_behaviour(sbPtr); |
| | 2587 | break; |
| | 2588 | } |
| | 2589 | |
| | 2590 | /* Okay, so now we need to know where to go now. */ |
| | 2591 | |
| | 2592 | int nextModuleIndex = GetNextModuleInPath(predatorStatusPointer->stepnumber, predatorStatusPointer->path); |
| | 2593 | assert(nextModuleIndex >= 0); |
| | 2594 | |
| | 2595 | /* If that fires, it's Richard's fault. */ |
| | 2596 | |
| | 2597 | targetModule = TranslatePathIndex(nextModuleIndex, predatorStatusPointer->path); |
| | 2598 | |
| | 2599 | assert(targetModule); |
| | 2600 | /* Ditto. */ |
| | 2601 | predatorStatusPointer->stepnumber = nextModuleIndex; |
| | 2602 | |
| | 2603 | /* Examine target, and decide what to do */ |
| | 2604 | |
| | 2605 | //assert(AIModuleIsPhysical(targetModule)); |
| | 2606 | |
| | 2607 | ProcessFarPredatorTargetAIModule(sbPtr, targetModule); |
| | 2608 | |
| | 2609 | /* reset timer */ |
| | 2610 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 2611 | } |
| | 2612 | } |
| | 2613 | break; |
| | 2614 | default: |
| | 2615 | { |
| | 2616 | assert(1==0); |
| | 2617 | break; |
| | 2618 | } |
| | 2619 | } |
| | 2620 | |
| | 2621 | HModel_Regen(&predatorStatusPointer->HModelController, PRED_REGEN_TIME); |
| | 2622 | |
| | 2623 | /* Update delta playing flag. */ |
| | 2624 | { |
| | 2625 | DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta"); |
| | 2626 | |
| | 2627 | if (hitdelta && DeltaAnimation_IsFinished(hitdelta)) |
| | 2628 | hitdelta->Playing = 0; |
| | 2629 | } |
| | 2630 | |
| | 2631 | #ifdef SHOWPREDOSTATS |
| | 2632 | switch (predatorStatusPointer->CloakStatus) |
| | 2633 | { |
| | 2634 | case PCLOAK_Off: |
| | 2635 | printf("DeCloaked "); |
| | 2636 | break; |
| | 2637 | case PCLOAK_On: |
| | 2638 | printf("Cloaked "); |
| | 2639 | break; |
| | 2640 | case PCLOAK_Activating: |
| | 2641 | printf("Cloaking (%d) ",predatorStatusPointer->CloakTimer); |
| | 2642 | break; |
| | 2643 | case PCLOAK_Deactivating: |
| | 2644 | printf("DeCloaking (%d) ",predatorStatusPointer->CloakTimer); |
| | 2645 | default: |
| | 2646 | break; |
| | 2647 | } |
| | 2648 | |
| | 2649 | printf("%s Predator in %s: %d,%d\n",descriptor,sbPtr->containingModule->name,
(sbPtr->DamageBlock.Health>>ONE_FIXED_SHIFT),(sbPtr->DamageBlock.Armour>>ONE_FIXED_SHIFT)); |
| | 2650 | #endif |
| | 2651 | printf("%s Predator in %s: %d,%d\n",descriptor,sbPtr->containingModule->name,
(sbPtr->DamageBlock.Health>>ONE_FIXED_SHIFT),(sbPtr->DamageBlock.Armour>>ONE_FIXED_SHIFT)); // jadda |
| | 2652 | printf("prdator STATE %d\n", predatorStatusPointer->behaviourState); // jadda |
| | 2653 | } |
| | 2654 | |
| | 2655 | void MakePredatorFar(STRATEGYBLOCK *sbPtr) |
| | 2656 | { |
| | 2657 | /* get the predator's status block */ |
| | 2658 | |
| | 2659 | assert(sbPtr); |
| | 2660 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2661 | assert(predatorStatusPointer); |
| | 2662 | |
| | 2663 | /* get rid of the displayblock */ |
| | 2664 | DestroyActiveObject(&sbPtr->DisplayBlock); |
| | 2665 | |
| | 2666 | predatorStatusPointer->CloakStatus = PCLOAK_Off; |
| | 2667 | predatorStatusPointer->CloakingEffectiveness = 0; |
| | 2668 | predatorStatusPointer->CloakTimer = 0; |
| | 2669 | |
| | 2670 | /* status block init */ |
| | 2671 | switch(predatorStatusPointer->behaviourState) |
| | 2672 | { |
| | 2673 | case PBS_SwapWeapon: |
| | 2674 | case PBS_SelfDestruct: |
| | 2675 | break; |
| | 2676 | default: |
| | 2677 | { |
| | 2678 | predatorStatusPointer->stateTimer = PRED_FAR_MOVE_TIME; |
| | 2679 | } |
| | 2680 | } |
| | 2681 | } |
| | 2682 | |
| | 2683 | void PredatorIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, SECTION_DATA *Section, VECTORCH *incoming) |
| | 2684 | { |
| | 2685 | assert(sbPtr); |
| | 2686 | assert(sbPtr->DynPtr); |
| | 2687 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2688 | assert(predatorStatusPointer); |
| | 2689 | |
| | 2690 | if(!sbPtr->DisplayBlock) |
| | 2691 | { |
| | 2692 | sbPtr->please_destroy_me = 1; |
| | 2693 | return; |
| | 2694 | } |
| | 2695 | |
| | 2696 | if(sbPtr->DamageBlock.Health <= 0) |
| | 2697 | { |
| | 2698 | int deathtype = 0; |
| | 2699 | |
| | 2700 | if (AvP.PlayerType != I_Predator) |
| | 2701 | CurrentGameStats_CreatureKilled(sbPtr, Section); |
| | 2702 | |
| | 2703 | /*notify death target ,if predator has one*/ |
| | 2704 | if(predatorStatusPointer->death_target_sbptr) |
| | 2705 | RequestState(predatorStatusPointer->death_target_sbptr, predatorStatusPointer->death_target_request, 0); |
| | 2706 | |
| | 2707 | /* Set deathtype */ |
| | 2708 | { |
| | 2709 | int tkd = TotalKineticDamage(damage); |
| | 2710 | |
| | 2711 | /* |
| | 2712 | if (damage->ExplosivePower == 1) |
| | 2713 | { |
| | 2714 | if (MUL_FIXED(tkd, (multiple & ((ONE_FIXED<<1)-1))) > 20) |
| | 2715 | { |
| | 2716 | // Okay, you can... splat now. |
| | 2717 | predatorStatusPointer->GibbFactor = -(ONE_FIXED >> 1); |
| | 2718 | deathtype = 2; |
| | 2719 | } |
| | 2720 | } |
| | 2721 | else |
| | 2722 | */ |
| | 2723 | |
| | 2724 | if (damage->ExplosivePower) |
| | 2725 | { |
| | 2726 | predatorStatusPointer->GibbFactor = ONE_FIXED; |
| | 2727 | deathtype = 3; |
| | 2728 | } |
| | 2729 | else if ((tkd < 40) && ((multiple >> 16) > 1)) |
| | 2730 | { |
| | 2731 | int newmult = DIV_FIXED(multiple, NormalFrameTime); |
| | 2732 | |
| | 2733 | if (MUL_FIXED(tkd,newmult) > 500) |
| | 2734 | { |
| | 2735 | predatorStatusPointer->GibbFactor = -(ONE_FIXED >> 2); |
| | 2736 | deathtype = 2; |
| | 2737 | } |
| | 2738 | } |
| | 2739 | } |
| | 2740 | |
| | 2741 | if (damage->ForceBoom) |
| | 2742 | deathtype += damage->ForceBoom; |
| | 2743 | |
| | 2744 | { |
| | 2745 | SECTION_DATA *chest = GetThisSectionData(predatorStatusPointer->HModelController.section_data,"chest"); |
| | 2746 | |
| | 2747 | if (chest == NULL) |
| | 2748 | { |
| | 2749 | /* I'm impressed. */ |
| | 2750 | deathtype += 2; |
| | 2751 | } |
| | 2752 | else if ((chest->flags & section_data_notreal) && (chest->flags & section_data_terminate_here)) |
| | 2753 | { |
| | 2754 | /* That's gotta hurt. */ |
| | 2755 | deathtype++; |
| | 2756 | } |
| | 2757 | } |
| | 2758 | |
| | 2759 | if (!predatorStatusPointer->GibbFactor) |
| | 2760 | { |
| | 2761 | /* make a sound... if you have a head. */ |
| | 2762 | SECTION_DATA *head = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "head"); |
| | 2763 | |
| | 2764 | /* Is it still attached? */ |
| | 2765 | if (head && !(head->flags & section_data_notreal)) |
| | 2766 | { |
| | 2767 | if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) |
| | 2768 | { |
| | 2769 | int rand = FastRandom(); |
| | 2770 | int pitch = (rand & 255) - 128; |
| | 2771 | |
| | 2772 | PlayPredatorSound(0, PSC_Scream_Dying, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position); |
| | 2773 | } |
| | 2774 | } |
| | 2775 | } |
| | 2776 | else |
| | 2777 | { |
| | 2778 | if (predatorStatusPointer->GibbFactor > 0) |
| | 2779 | Extreme_Gibbing(sbPtr, predatorStatusPointer->HModelController.section_data, predatorStatusPointer->GibbFactor, incoming); |
| | 2780 | |
| | 2781 | predatorStatusPointer->GibbFactor = 0; |
| | 2782 | } |
| | 2783 | |
| | 2784 | { |
| | 2785 | HIT_FACING facing = { 0,0,0,0 }; |
| | 2786 | int burning = 0; |
| | 2787 | int wounds = 0; |
| | 2788 | |
| | 2789 | SECTION *root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template"); |
| | 2790 | |
| | 2791 | if (incoming) |
| | 2792 | { |
| | 2793 | if (incoming->vz > 0) |
| | 2794 | facing.Back = 1; |
| | 2795 | else |
| | 2796 | facing.Front = 1; |
| | 2797 | |
| | 2798 | if (incoming->vx > 0) |
| | 2799 | facing.Right = 1; |
| | 2800 | else |
| | 2801 | facing.Left = 1; |
| | 2802 | } |
| | 2803 | |
| | 2804 | if (!damage->Impact |
| | 2805 | &&!damage->Cutting |
| | 2806 | &&!damage->Penetrative |
| | 2807 | &&damage->Fire |
| | 2808 | &&!damage->Electrical |
| | 2809 | &&!damage->Acid) |
| | 2810 | { |
| | 2811 | burning = 1; |
| | 2812 | } |
| | 2813 | |
| | 2814 | if (Section) |
| | 2815 | wounds = (Section->flags & section_flags_wounding); |
| | 2816 | |
| | 2817 | DEATH_DATA *this_death = GetPredatorDeathSequence(&predatorStatusPointer->HModelController, root, wounds, |
| | 2818 | wounds, deathtype, &facing, burning, predatorStatusPointer->IAmCrouched, 0); |
| | 2819 | |
| | 2820 | assert(this_death); |
| | 2821 | |
| | 2822 | Remove_Delta_Sequence(&predatorStatusPointer->HModelController, "Elevation"); |
| | 2823 | Remove_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta"); |
| | 2824 | |
| | 2825 | Convert_Predator_To_Corpse(sbPtr, this_death); |
| | 2826 | } |
| | 2827 | } |
| | 2828 | else |
| | 2829 | { |
| | 2830 | /* If not dead, play a hit delta. */ |
| | 2831 | int frontback = 1; |
| | 2832 | |
| | 2833 | if (!damage->Impact |
| | 2834 | &&!damage->Cutting |
| | 2835 | &&!damage->Penetrative |
| | 2836 | &&!damage->Fire |
| | 2837 | &&!damage->Electrical |
| | 2838 | && damage->Acid) |
| | 2839 | { |
| | 2840 | if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) |
| | 2841 | { |
| | 2842 | int pitch = (FastRandom() & 255) - 128; |
| | 2843 | PlayPredatorSound(0, PSC_Acid, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position); |
| | 2844 | } |
| | 2845 | } |
| | 2846 | else |
| | 2847 | { |
| | 2848 | if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) |
| | 2849 | { |
| | 2850 | int pitch = (FastRandom() & 255) - 128; |
| | 2851 | PlayPredatorSound(0, PSC_Scream_Hurt, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position); |
| | 2852 | } |
| | 2853 | } |
| | 2854 | |
| | 2855 | DELTA_CONTROLLER *hitdelta = Get_Delta_Sequence(&predatorStatusPointer->HModelController, "HitDelta"); |
| | 2856 | |
| | 2857 | if (incoming) |
| | 2858 | { |
| | 2859 | if (incoming->vz >= 0) |
| | 2860 | { |
| | 2861 | frontback = 0; |
| | 2862 | |
| | 2863 | if(damage->Impact > 40) |
| | 2864 | { |
| | 2865 | if(PNPCW_PlasmaCaster == predatorStatusPointer->Selected_Weapon->id) |
| | 2866 | { |
| | 2867 | predatorStatusPointer->Angry = ONE_FIXED * 10; |
| | 2868 | predatorStatusPointer->weaponTarget.vx = -sbPtr->DynPtr->Position.vx; |
| | 2869 | predatorStatusPointer->weaponTarget.vy = -sbPtr->DynPtr->Position.vy; |
| | 2870 | predatorStatusPointer->weaponTarget.vz = -sbPtr->DynPtr->Position.vz; |
| | 2871 | Normalise(&predatorStatusPointer->weaponTarget); |
| | 2872 | |
| | 2873 | predatorStatusPointer->weaponTarget.vx >>= 3; |
| | 2874 | predatorStatusPointer->weaponTarget.vy >>= 3; |
| | 2875 | predatorStatusPointer->weaponTarget.vz >>= 3; |
| | 2876 | |
| | 2877 | if(NULL == predatorStatusPointer->closets_target) |
| | 2878 | predatorStatusPointer->closets_target = sbPtr; |
| | 2879 | |
| | 2880 | if(PCLOAK_Off == predatorStatusPointer->CloakStatus) |
| | 2881 | predatorStatusPointer->Angry /= 2; |
| | 2882 | |
| | 2883 | predatorStatusPointer->behaviourState = PBS_Attacking; |
| | 2884 | } |
| | 2885 | } |
| | 2886 | } |
| | 2887 | } |
| | 2888 | |
| | 2889 | if (hitdelta) |
| | 2890 | { |
| | 2891 | /* A hierarchy with hit deltas! */ |
| | 2892 | if (!hitdelta->Playing) |
| | 2893 | { |
| | 2894 | int CrouchSubSequence; |
| | 2895 | int StandSubSequence; |
| | 2896 | |
| | 2897 | if (Section == NULL) |
| | 2898 | { |
| | 2899 | if (!frontback) |
| | 2900 | { |
| | 2901 | CrouchSubSequence = PCrSS_HitChestBack; |
| | 2902 | StandSubSequence = PSSS_HitChestBack; |
| | 2903 | } |
| | 2904 | else |
| | 2905 | { |
| | 2906 | CrouchSubSequence = PCrSS_HitChestFront; |
| | 2907 | StandSubSequence = PSSS_HitChestFront; |
| | 2908 | } |
| | 2909 | } |
| | 2910 | else if (Section->sempai->flags & section_flag_head) |
| | 2911 | { |
| | 2912 | if (!frontback) |
| | 2913 | { |
| | 2914 | CrouchSubSequence = PCrSS_HitHeadBack; |
| | 2915 | StandSubSequence = PSSS_HitHeadBack; |
| | 2916 | } |
| | 2917 | else |
| | 2918 | { |
| | 2919 | CrouchSubSequence = PCrSS_HitHeadFront; |
| | 2920 | StandSubSequence = PSSS_HitHeadFront; |
| | 2921 | } |
| | 2922 | } |
| | 2923 | else if ((Section->sempai->flags & section_flag_left_arm) || (Section->sempai->flags & section_flag_left_hand)) |
| | 2924 | { |
| | 2925 | if (!frontback) |
| | 2926 | { |
| | 2927 | CrouchSubSequence = PCrSS_HitRightArm; |
| | 2928 | StandSubSequence = PSSS_HitRightArm; |
| | 2929 | } |
| | 2930 | else |
| | 2931 | { |
| | 2932 | CrouchSubSequence = PCrSS_HitLeftArm; |
| | 2933 | StandSubSequence = PSSS_HitLeftArm; |
| | 2934 | } |
| | 2935 | } |
| | 2936 | else if ((Section->sempai->flags & section_flag_right_arm) || (Section->sempai->flags & section_flag_right_hand)) |
| | 2937 | { |
| | 2938 | if (!frontback) |
| | 2939 | { |
| | 2940 | CrouchSubSequence = PCrSS_HitLeftArm; |
| | 2941 | StandSubSequence = PSSS_HitLeftArm; |
| | 2942 | } |
| | 2943 | else |
| | 2944 | { |
| | 2945 | CrouchSubSequence = PCrSS_HitRightArm; |
| | 2946 | StandSubSequence = PSSS_HitRightArm; |
| | 2947 | } |
| | 2948 | } |
| | 2949 | else if ((Section->sempai->flags & section_flag_left_leg) ||(Section->sempai->flags & section_flag_left_foot)) |
| | 2950 | { |
| | 2951 | if (!frontback) |
| | 2952 | { |
| | 2953 | CrouchSubSequence = PCrSS_HitRightLeg; |
| | 2954 | StandSubSequence = PSSS_HitRightLeg; |
| | 2955 | } |
| | 2956 | else |
| | 2957 | { |
| | 2958 | CrouchSubSequence = PCrSS_HitLeftLeg; |
| | 2959 | StandSubSequence = PSSS_HitLeftLeg; |
| | 2960 | } |
| | 2961 | } |
| | 2962 | else if ((Section->sempai->flags & section_flag_right_leg) ||(Section->sempai->flags & section_flag_right_foot)) |
| | 2963 | { |
| | 2964 | if (!frontback) |
| | 2965 | { |
| | 2966 | CrouchSubSequence = PCrSS_HitLeftLeg; |
| | 2967 | StandSubSequence = PSSS_HitLeftLeg; |
| | 2968 | } |
| | 2969 | else |
| | 2970 | { |
| | 2971 | CrouchSubSequence = PCrSS_HitRightLeg; |
| | 2972 | StandSubSequence = PSSS_HitRightLeg; |
| | 2973 | } |
| | 2974 | } |
| | 2975 | else |
| | 2976 | { |
| | 2977 | /* Chest or misc. hit. */ |
| | 2978 | if (!frontback) |
| | 2979 | { |
| | 2980 | CrouchSubSequence = PCrSS_HitChestBack; |
| | 2981 | StandSubSequence = PSSS_HitChestBack; |
| | 2982 | } |
| | 2983 | else |
| | 2984 | { |
| | 2985 | CrouchSubSequence = PCrSS_HitChestFront; |
| | 2986 | StandSubSequence = PSSS_HitChestFront; |
| | 2987 | } |
| | 2988 | } |
| | 2989 | |
| | 2990 | if(predatorStatusPointer->IAmCrouched) |
| | 2991 | { |
| | 2992 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorCrouch,CrouchSubSequence)) |
| | 2993 | Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorCrouch,CrouchSubSequence,-1); |
| | 2994 | } |
| | 2995 | else |
| | 2996 | { |
| | 2997 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController,(int)HMSQT_PredatorStand,StandSubSequence)) |
| | 2998 | Start_Delta_Sequence(hitdelta,(int)HMSQT_PredatorStand,StandSubSequence,-1); |
| | 2999 | } |
| | 3000 | |
| | 3001 | hitdelta->Playing = 1; |
| | 3002 | /* Not looped. */ |
| | 3003 | } |
| | 3004 | } |
| | 3005 | |
| | 3006 | if (predatorStatusPointer->behaviourState != PBS_SelfDestruct) |
| | 3007 | { |
| | 3008 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator]; |
| | 3009 | |
| | 3010 | /* 12.5% health? */ |
| | 3011 | if (sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-3))) |
| | 3012 | { |
| | 3013 | /* Switch to template. */ |
| | 3014 | SECTION *root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template"); |
| | 3015 | assert(root); |
| | 3016 | RemoveAllDeltas(&predatorStatusPointer->HModelController); |
| | 3017 | /* Set 'new' sequence. */ |
| | 3018 | predatorStatusPointer->HModelController.Sequence_Type = HMSQT_PredatorCrouch; |
| | 3019 | predatorStatusPointer->HModelController.Sub_Sequence = PCrSS_Det_Prog; |
| | 3020 | Transmogrify_HModels(sbPtr, &predatorStatusPointer->HModelController, root, 1, 0, 0); |
| | 3021 | ProveHModel_Far(&predatorStatusPointer->HModelController, sbPtr); |
| | 3022 | |
| | 3023 | InitHModelTweening(&predatorStatusPointer->HModelController, (ONE_FIXED>>3), HMSQT_PredatorCrouch, PCrSS_Det_Prog, -1, 0); |
| | 3024 | |
| | 3025 | if (predatorStatusPointer->CloakStatus == PCLOAK_Off) |
| | 3026 | PredatorCloakOn(predatorStatusPointer); |
| | 3027 | |
| | 3028 | NPC_InitMovementData(&predatorStatusPointer->moveData); |
| | 3029 | NPC_InitWanderData(&predatorStatusPointer->wanderData); |
| | 3030 | InitWaypointManager(&predatorStatusPointer->waypointManager); |
| | 3031 | predatorStatusPointer->volleySize = 0; |
| | 3032 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 3033 | predatorStatusPointer->behaviourState = PBS_SelfDestruct; |
| | 3034 | predatorStatusPointer->stateTimer = 0; |
| | 3035 | predatorStatusPointer->Pred_Laser_On = 0; |
| | 3036 | predatorStatusPointer->internalState = 0; /* Not yet primed. */ |
| | 3037 | predatorStatusPointer->IAmCrouched = 1; |
| | 3038 | } |
| | 3039 | if(0) |
| | 3040 | if (predatorStatusPointer->behaviourState == PBS_Recovering) |
| | 3041 | { |
| | 3042 | int range = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->Position, &sbPtr->DynPtr->Position); |
| | 3043 | |
| | 3044 | if (range > predatorStatusPointer->MeleeWeapon->MaxRange * 8) |
| | 3045 | { |
| | 3046 | if (PNPCW_PlasmaCaster != predatorStatusPointer->Selected_Weapon->id) |
| | 3047 | { |
| | 3048 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 3049 | //Predator_Enter_Swapping_State(sbPtr); |
| | 3050 | } |
| | 3051 | } |
| | 3052 | else |
| | 3053 | { |
| | 3054 | if (predatorStatusPointer->MeleeWeapon != predatorStatusPointer->Selected_Weapon) |
| | 3055 | { |
| | 3056 | predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->MeleeWeapon->id; |
| | 3057 | //Predator_Enter_Swapping_State(sbPtr); |
| | 3058 | } |
| | 3059 | } |
| | 3060 | } |
| | 3061 | else |
| | 3062 | { |
| | 3063 | STRATEGYBLOCK *closest_target = Predator_GetNewTarget(sbPtr); |
| | 3064 | puts("HELLO"); |
| | 3065 | printf("vehave %d\n", predatorStatusPointer->behaviourState); |
| | 3066 | |
| | 3067 | if (NULL != closest_target) |
| | 3068 | { |
| | 3069 | printf("target %d\n", predatorStatusPointer->closets_target->type); |
| | 3070 | puts("new TAGET"); |
| | 3071 | int range = VectorDistance(&closest_target->DynPtr->Position, &sbPtr->DynPtr->Position); |
| | 3072 | |
| | 3073 | if (range > predatorStatusPointer->MeleeWeapon->MaxRange * 10) |
| | 3074 | { |
| | 3075 | if (PNPCW_PlasmaCaster != predatorStatusPointer->Selected_Weapon->id) |
| | 3076 | { |
| | 3077 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 3078 | //Predator_Enter_Swapping_State(sbPtr); |
| | 3079 | } |
| | 3080 | } |
| | 3081 | else |
| | 3082 | { |
| | 3083 | if (predatorStatusPointer->MeleeWeapon != predatorStatusPointer->Selected_Weapon) |
| | 3084 | { |
| | 3085 | predatorStatusPointer->ChangeToWeapon = predatorStatusPointer->MeleeWeapon->id; |
| | 3086 | //Predator_Enter_Swapping_State(sbPtr); |
| | 3087 | } |
| | 3088 | } |
| | 3089 | |
| | 3090 | /* |
| | 3091 | if (range > predatorStatusPointer->MeleeWeapon->MaxRange * 10) |
| | 3092 | { |
| | 3093 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 3094 | //Predator_Enter_Swapping_State(sbPtr); |
| | 3095 | } |
| | 3096 | */ |
| | 3097 | |
| | 3098 | if(closest_target != predatorStatusPointer->closets_target) |
| | 3099 | { |
| | 3100 | predatorStatusPointer->closets_target = closest_target; |
| | 3101 | COPY_NAME(predatorStatusPointer->Target_SBname, predatorStatusPointer->closets_target->SBname); |
| | 3102 | } |
| | 3103 | } |
| | 3104 | |
| | 3105 | if(predatorStatusPointer->CloakStatus == PCLOAK_Off) |
| | 3106 | PredatorCloakOn(predatorStatusPointer); |
| | 3107 | } |
| | 3108 | } |
| | 3109 | } |
| | 3110 | } |
| | 3111 | |
| | 3112 | static void Execute_PNS_AttackWithMeleeWeapon(STRATEGYBLOCK *sbPtr, int distance_to_target) |
| | 3113 | { |
| | 3114 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3115 | |
| | 3116 | if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange) |
| | 3117 | { |
| | 3118 | int target_previous_distance = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position); |
| | 3119 | |
| | 3120 | if(distance_to_target < target_previous_distance) |
| | 3121 | { |
| | 3122 | if(PNPCW_Pistol == predatorStatusPointer->SecondaryWeapon) |
| | 3123 | { |
| | 3124 | switch(predatorStatusPointer->closets_target->type) |
| | 3125 | { |
| | 3126 | case I_BehaviourAlien: |
| | 3127 | case I_BehaviourAlienPlayer: |
| | 3128 | case I_BehaviourFaceHugger: |
| | 3129 | if ((distance_to_target > 9000) && (distance_to_target < 20000)) |
| | 3130 | { |
| | 3131 | if ((FastRandom() & 65535) > 32767) |
| | 3132 | { |
| | 3133 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3134 | predator_change_behaviour(sbPtr); |
| | 3135 | return; |
| | 3136 | } |
| | 3137 | } |
| | 3138 | default: |
| | 3139 | break; |
| | 3140 | } |
| | 3141 | } |
| | 3142 | else if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange * 10) |
| | 3143 | { |
| | 3144 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 3145 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3146 | predator_change_behaviour(sbPtr); |
| | 3147 | return; |
| | 3148 | } |
| | 3149 | } |
| | 3150 | else |
| | 3151 | { |
| | 3152 | if ((FastRandom() & 65535) > 32767/2) |
| | 3153 | if(distance_to_target > predatorStatusPointer->Selected_Weapon->MaxRange * 8) |
| | 3154 | { |
| | 3155 | if(predatorStatusPointer->CloakStatus == PCLOAK_Off) |
| | 3156 | PredatorCloakOn(predatorStatusPointer); |
| | 3157 | |
| | 3158 | if(PNPCW_Pistol == predatorStatusPointer->SecondaryWeapon) |
| | 3159 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 3160 | |
| | 3161 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3162 | predator_change_behaviour(sbPtr); |
| | 3163 | return; |
| | 3164 | } |
| | 3165 | } |
| | 3166 | |
| | 3167 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 3168 | } |
| | 3169 | else |
| | 3170 | { |
| | 3171 | /* Decrement the near state timer */ |
| | 3172 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 3173 | |
| | 3174 | PredatorNearDamageShell(sbPtr); |
| | 3175 | |
| | 3176 | if (predatorStatusPointer->HModelController.keyframe_flags & 1) |
| | 3177 | { |
| | 3178 | predatorStatusPointer->stateTimer = PRED_NEAR_CLOSEATTACK_TIME; |
| | 3179 | Predator_Enter_Attacking_State(sbPtr); |
| | 3180 | } |
| | 3181 | } |
| | 3182 | } |
| | 3183 | |
| | 3184 | static int DoPredatorLaserTargeting(STRATEGYBLOCK *sbPtr) |
| | 3185 | { |
| | 3186 | static const VECTORCH offset[3] = { {0,-50,0}, {43,25,0}, {-43,25,0}, }; |
| | 3187 | VECTORCH z_vec; |
| | 3188 | int hits = 0; |
| | 3189 | STRATEGYBLOCK *laserhits[3]; |
| | 3190 | |
| | 3191 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3192 | |
| | 3193 | predatorStatusPointer->Pred_Laser_On = 1; |
| | 3194 | |
| | 3195 | SECTION_DATA *plasma_muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash"); |
| | 3196 | |
| | 3197 | MATRIXCH matrix = plasma_muzzle->SecMat; |
| | 3198 | |
| | 3199 | z_vec.vx = matrix.mat31; |
| | 3200 | z_vec.vy = matrix.mat32; |
| | 3201 | z_vec.vz = matrix.mat33; |
| | 3202 | |
| | 3203 | TransposeMatrixCH(&matrix); |
| | 3204 | |
| | 3205 | predatorStatusPointer->Pred_Laser_Sight.LightSource = plasma_muzzle->World_Offset; |
| | 3206 | |
| | 3207 | int i; |
| | 3208 | |
| | 3209 | for (i = 0; i < 3; i++) |
| | 3210 | { |
| | 3211 | VECTORCH position = offset[i]; |
| | 3212 | |
| | 3213 | RotateVector(&position, &matrix); |
| | 3214 | position.vx += plasma_muzzle->World_Offset.vx; |
| | 3215 | position.vy += plasma_muzzle->World_Offset.vy; |
| | 3216 | position.vz += plasma_muzzle->World_Offset.vz; |
| | 3217 | FindPolygonInLineOfSight(&z_vec, &position, 0, sbPtr->DisplayBlock); |
| | 3218 | |
| | 3219 | predatorStatusPointer->Pred_Laser_Sight.Normal[i] = LOS_ObjectNormal; |
| | 3220 | predatorStatusPointer->Pred_Laser_Sight.Position[i] = LOS_Point; |
| | 3221 | |
| | 3222 | if (LOS_ObjectHitPtr) |
| | 3223 | { |
| | 3224 | if (LOS_ObjectHitPtr == PlayerStatus.DisplayBlock) |
| | 3225 | predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer = 1; |
| | 3226 | |
| | 3227 | laserhits[i] = LOS_ObjectHitPtr->ObStrategyBlock; |
| | 3228 | hits++; |
| | 3229 | } |
| | 3230 | else |
| | 3231 | { |
| | 3232 | laserhits[i] = NULL; |
| | 3233 | } |
| | 3234 | |
| | 3235 | } |
| | 3236 | |
| | 3237 | if(hits && (laserhits[0] == laserhits[1]) && (laserhits[1] == laserhits[2])) |
| | 3238 | { |
| | 3239 | if (laserhits[0] == PlayerStatus.sbptr) |
| | 3240 | predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer = 1; |
| | 3241 | |
| | 3242 | return (laserhits[0] == predatorStatusPointer->closets_target); |
| | 3243 | } |
| | 3244 | |
| | 3245 | predatorStatusPointer->Pred_Laser_Sight.DotIsOnPlayer = 0; |
| | 3246 | return 0; |
| | 3247 | } |
| | 3248 | |
| | 3249 | static void Execute_PNS_AttackWithPlasmaCaster(STRATEGYBLOCK *sbPtr, int distance_to_target) |
| | 3250 | { |
| | 3251 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3252 | |
| | 3253 | if (!predatorStatusPointer->internalState) |
| | 3254 | { |
| | 3255 | if (predatorStatusPointer->HModelController.Tweening == Controller_NoTweening) |
| | 3256 | predatorStatusPointer->HModelController.Playing = 0; |
| | 3257 | } |
| | 3258 | |
| | 3259 | /* Always turn to face... */ |
| | 3260 | NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 3261 | |
| | 3262 | VECTORCH orientationDirn; |
| | 3263 | /* orientate to firing point first */ |
| | 3264 | if (predatorStatusPointer->My_Elevation_Section) |
| | 3265 | { |
| | 3266 | /* Assume range large w.r.t. half shoulder width... */ |
| | 3267 | orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; |
| | 3268 | orientationDirn.vy = 0; |
| | 3269 | orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; |
| | 3270 | } |
| | 3271 | else |
| | 3272 | { |
| | 3273 | orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; |
| | 3274 | orientationDirn.vy = 0; |
| | 3275 | orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; |
| | 3276 | } |
| | 3277 | |
| | 3278 | int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 3279 | |
| | 3280 | if(!correctlyOrientated) |
| | 3281 | return; |
| | 3282 | |
| | 3283 | if (predatorStatusPointer->closets_target->type == I_BehaviourAutoGun) |
| | 3284 | predatorStatusPointer->stateTimer -= NormalFrameTime << 2; |
| | 3285 | else |
| | 3286 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 3287 | |
| | 3288 | if (predatorStatusPointer->internalState == 1) |
| | 3289 | { |
| | 3290 | /* Using stateTimer, thanks! */ |
| | 3291 | } |
| | 3292 | else if(predatorStatusPointer->stateTimer > 0) |
| | 3293 | { |
| | 3294 | return; |
| | 3295 | } |
| | 3296 | |
| | 3297 | /* State timed out - try to fire! */ |
| | 3298 | |
| | 3299 | /* we are not correctly orientated to the target: this could happen because we have |
| | 3300 | just entered this state, or the target has moved during firing*/ |
| | 3301 | |
| | 3302 | if ((predatorStatusPointer->internalState != 2) && (predatorStatusPointer->internalState != 1)) |
| | 3303 | { |
| | 3304 | predatorStatusPointer->internalState = 1; |
| | 3305 | /* Pausing. */ |
| | 3306 | predatorStatusPointer->stateTimer = ONE_FIXED; |
| | 3307 | } |
| | 3308 | |
| | 3309 | int onTarget = DoPredatorLaserTargeting(sbPtr); |
| | 3310 | |
| | 3311 | if ((predatorStatusPointer->internalState == 1) && (predatorStatusPointer->stateTimer <= 0)) |
| | 3312 | { |
| | 3313 | if (onTarget) |
| | 3314 | { |
| | 3315 | /* If you are correctly oriented, you can now fire! Or taunt instead? */ |
| | 3316 | /* Fire at least once! */ |
| | 3317 | predatorStatusPointer->enableTaunt = 1; |
| | 3318 | predatorStatusPointer->HModelController.Playing = 1; |
| | 3319 | predatorStatusPointer->HModelController.Looped = 0; |
| | 3320 | predatorStatusPointer->HModelController.sequence_timer = 0; |
| | 3321 | predatorStatusPointer->internalState = 2; |
| | 3322 | |
| | 3323 | /* look after the sound */ |
| | 3324 | Sound_Play(SID_PRED_LAUNCHER, "d", &sbPtr->DynPtr->Position); |
| | 3325 | |
| | 3326 | /* Now fire a bolt. */ |
| | 3327 | |
| | 3328 | { |
| | 3329 | SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash"); |
| | 3330 | |
| | 3331 | InitialiseEnergyBoltBehaviourKernel(&muzzle->World_Offset, &muzzle->SecMat, 0, &TemplateAmmo[AMMO_PLASMACASTER].MaxDamage,
65536); |
| | 3332 | predatorStatusPointer->volleySize++; |
| | 3333 | } |
| | 3334 | |
| | 3335 | if (predatorStatusPointer->CloakStatus == PCLOAK_Off) |
| | 3336 | if (((FastRandom() & 65535) < 32767) && predatorStatusPointer->enableTaunt &&
(predatorStatusPointer->closets_target->type != I_BehaviourAutoGun)) |
| | 3337 | { |
| | 3338 | if (HModelSequence_Exists(&predatorStatusPointer->HModelController, (int)HMSQT_PredatorStand, (int)PSSS_Taunt_One)) |
| | 3339 | { |
| | 3340 | int rand = FastRandom(); |
| | 3341 | int pitch = (rand & 255) - 128; |
| | 3342 | predatorStatusPointer->lastState = predatorStatusPointer->behaviourState; |
| | 3343 | predatorStatusPointer->behaviourState = PBS_Taunting; |
| | 3344 | predatorStatusPointer->stateTimer = NPC_AVOIDTIME; |
| | 3345 | predatorStatusPointer->enableTaunt = 0; |
| | 3346 | |
| | 3347 | SetPredatorAnimationSequence(sbPtr, HMSQT_PredatorStand, PSSS_Taunt_One, -1, (ONE_FIXED >> 3)); |
| | 3348 | |
| | 3349 | predatorStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 3350 | |
| | 3351 | if (predatorStatusPointer->soundHandle == SOUND_NOACTIVEINDEX) |
| | 3352 | PlayPredatorSound(0, PSC_Taunt, pitch, &predatorStatusPointer->soundHandle, &sbPtr->DynPtr->Position); |
| | 3353 | } |
| | 3354 | } |
| | 3355 | |
| | 3356 | predatorStatusPointer->patience = PRED_PATIENCE_TIME; |
| | 3357 | predatorStatusPointer->stateTimer = ONE_FIXED; |
| | 3358 | predatorStatusPointer->enableSwap = 1; |
| | 3359 | return; |
| | 3360 | } |
| | 3361 | else |
| | 3362 | { |
| | 3363 | if (distance_to_target < predatorStatusPointer->MeleeWeapon->MaxRange * 4) |
| | 3364 | { |
| | 3365 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3366 | predator_change_behaviour(sbPtr); |
| | 3367 | return; |
| | 3368 | } |
| | 3369 | else |
| | 3370 | { |
| | 3371 | /* You think you're correctly orientated - but you're still not hitting. */ |
| | 3372 | predatorStatusPointer->patience -= NormalFrameTime; |
| | 3373 | |
| | 3374 | if (predatorStatusPointer->patience <= 0) |
| | 3375 | { |
| | 3376 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3377 | predator_change_behaviour(sbPtr); |
| | 3378 | return; |
| | 3379 | } |
| | 3380 | |
| | 3381 | if (predatorStatusPointer->stateTimer <= 0) |
| | 3382 | { |
| | 3383 | /* Oh, just give up. */ |
| | 3384 | predatorStatusPointer->HModelController.Playing = 1; |
| | 3385 | predatorStatusPointer->HModelController.Looped = 0; |
| | 3386 | predatorStatusPointer->HModelController.sequence_timer = 0; |
| | 3387 | predatorStatusPointer->internalState = 2; |
| | 3388 | } |
| | 3389 | else |
| | 3390 | { |
| | 3391 | return; |
| | 3392 | } |
| | 3393 | } |
| | 3394 | } |
| | 3395 | } |
| | 3396 | |
| | 3397 | if (predatorStatusPointer->internalState == 2) |
| | 3398 | { |
| | 3399 | /* After shot. */ |
| | 3400 | if (predatorStatusPointer->HModelController.sequence_timer < (ONE_FIXED - 1)) |
| | 3401 | return; /* Still playing. */ |
| | 3402 | |
| | 3403 | if(distance_to_target < predatorStatusPointer->MeleeWeapon->MaxRange * 2) |
| | 3404 | { |
| | 3405 | if(PCLOAK_On == predatorStatusPointer->CloakStatus) |
| | 3406 | PredatorCloakOff(predatorStatusPointer); |
| | 3407 | |
| | 3408 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3409 | predator_change_behaviour(sbPtr); |
| | 3410 | } |
| | 3411 | else |
| | 3412 | { |
| | 3413 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator]; |
| | 3414 | |
| | 3415 | if (sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-1))) |
| | 3416 | { |
| | 3417 | if(distance_to_target > 15000) |
| | 3418 | { |
| | 3419 | int target_previous_distance = VectorDistance(&predatorStatusPointer->closets_target->DynPtr->PrevPosition,
&sbPtr->DynPtr->Position); // target retreating? |
| | 3420 | |
| | 3421 | switch(predatorStatusPointer->closets_target->type) |
| | 3422 | { |
| | 3423 | case I_BehaviourMarinePlayer: |
| | 3424 | case I_BehaviourMarine: |
| | 3425 | case I_BehaviourAlienPlayer: |
| | 3426 | if(PCLOAK_Off == predatorStatusPointer->CloakStatus) |
| | 3427 | PredatorCloakOn(predatorStatusPointer); |
| | 3428 | //break; |
| | 3429 | //case I_BehaviourAlien: |
| | 3430 | default: |
| | 3431 | break; |
| | 3432 | |
| | 3433 | } |
| | 3434 | |
| | 3435 | if(distance_to_target > target_previous_distance) |
| | 3436 | { |
| | 3437 | predatorStatusPointer->behaviourState = PBS_Recovering; |
| | 3438 | } |
| | 3439 | } |
| | 3440 | else |
| | 3441 | { |
| | 3442 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 3443 | predatorStatusPointer->internalState = 0; |
| | 3444 | } |
| | 3445 | } |
| | 3446 | else |
| | 3447 | { |
| | 3448 | if (predatorStatusPointer->volleySize >= predatorStatusPointer->Selected_Weapon->VolleySize) |
| | 3449 | { |
| | 3450 | predatorStatusPointer->behaviourState = (distance_to_target < predatorStatusPointer->MeleeWeapon->MaxRange * 2) ? PBS_SwapWeapon
: PBS_Engaging; |
| | 3451 | predator_change_behaviour(sbPtr); |
| | 3452 | } |
| | 3453 | else |
| | 3454 | { |
| | 3455 | /* And another! */ |
| | 3456 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 3457 | predatorStatusPointer->internalState = 0; |
| | 3458 | } |
| | 3459 | } |
| | 3460 | } |
| | 3461 | } |
| | 3462 | } |
| | 3463 | |
| | 3464 | static void Execute_PNS_DischargeSpeargun(STRATEGYBLOCK *sbPtr, int distance_to_target) |
| | 3465 | { |
| | 3466 | VECTORCH orientationDirn; |
| | 3467 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3468 | |
| | 3469 | /* Always turn to face... */ |
| | 3470 | NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 3471 | |
| | 3472 | /* Fix weapon target! */ |
| | 3473 | predatorStatusPointer->weaponTarget.vx -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat21, 300); |
| | 3474 | predatorStatusPointer->weaponTarget.vy -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat22, 300); |
| | 3475 | predatorStatusPointer->weaponTarget.vz -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat23, 300); |
| | 3476 | |
| | 3477 | /* orientate to firing point first */ |
| | 3478 | if (predatorStatusPointer->My_Elevation_Section) |
| | 3479 | { |
| | 3480 | /* Assume range large w.r.t. half shoulder width... */ |
| | 3481 | orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; |
| | 3482 | orientationDirn.vy = 0; |
| | 3483 | orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; |
| | 3484 | } |
| | 3485 | else |
| | 3486 | { |
| | 3487 | orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; |
| | 3488 | orientationDirn.vy = 0; |
| | 3489 | orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; |
| | 3490 | } |
| | 3491 | |
| | 3492 | /* closets_target shift? */ |
| | 3493 | int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 3494 | |
| | 3495 | /* If still tweening, pause. */ |
| | 3496 | if (predatorStatusPointer->HModelController.Tweening != Controller_NoTweening) |
| | 3497 | return; |
| | 3498 | |
| | 3499 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 3500 | |
| | 3501 | /* You must have fired already. */ |
| | 3502 | |
| | 3503 | if(predatorStatusPointer->stateTimer > 0) |
| | 3504 | return; |
| | 3505 | |
| | 3506 | //if (predatorStatusPointer->stateTimer == predatorStatusPointer->Selected_Weapon->FiringRate) |
| | 3507 | if (predatorStatusPointer->stateTimer < 0) |
| | 3508 | { |
| | 3509 | predatorStatusPointer->HModelController.Playing = 0; |
| | 3510 | |
| | 3511 | /* we are not correctly orientated to the target: this could happen because we have |
| | 3512 | just entered this state, or the target has moved during firing*/ |
| | 3513 | |
| | 3514 | if(!correctlyOrientated) |
| | 3515 | return; |
| | 3516 | |
| | 3517 | /* If you are correctly oriented, you can now fire! */ |
| | 3518 | |
| | 3519 | predatorStatusPointer->HModelController.Playing = 1; |
| | 3520 | predatorStatusPointer->HModelController.sequence_timer = 0; |
| | 3521 | |
| | 3522 | /* look after the sound */ |
| | 3523 | Sound_Play(SID_PRED_LASER, "d", &sbPtr->DynPtr->Position); |
| | 3524 | |
| | 3525 | /* Now fire a spear... */ |
| | 3526 | { |
| | 3527 | VECTORCH shotVector; |
| | 3528 | SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash"); |
| | 3529 | |
| | 3530 | shotVector.vx = muzzle->SecMat.mat31; |
| | 3531 | shotVector.vy = muzzle->SecMat.mat32; |
| | 3532 | shotVector.vz = muzzle->SecMat.mat33; |
| | 3533 | |
| | 3534 | FindPolygonInLineOfSight(&shotVector, &muzzle->World_Offset, 0, sbPtr->DisplayBlock); |
| | 3535 | |
| | 3536 | /* Now deal with LOS_ObjectHitPtr. */ |
| | 3537 | if (LOS_ObjectHitPtr) |
| | 3538 | ShotPredRifleArrow(&muzzle->World_Offset, &muzzle->SecMat); |
| | 3539 | |
| | 3540 | predatorStatusPointer->volleySize++; |
| | 3541 | } |
| | 3542 | |
| | 3543 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate * 5; |
| | 3544 | |
| | 3545 | if(predatorStatusPointer->RifleArrows-- < 0) |
| | 3546 | { |
| | 3547 | predatorStatusPointer->ChangeToWeapon = PNPCW_PlasmaCaster; |
| | 3548 | predatorStatusPointer->SecondaryWeapon = PNPCW_PlasmaCaster; |
| | 3549 | predatorStatusPointer->RifleArrows = 0; |
| | 3550 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3551 | predator_change_behaviour(sbPtr); |
| | 3552 | return; |
| | 3553 | } |
| | 3554 | } |
| | 3555 | |
| | 3556 | if(distance_to_target < 1000) |
| | 3557 | { |
| | 3558 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3559 | predator_change_behaviour(sbPtr); |
| | 3560 | } |
| | 3561 | else |
| | 3562 | { |
| | 3563 | /* we are far enough away, so return to approach? */ |
| | 3564 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator]; |
| | 3565 | |
| | 3566 | if (sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-1))) |
| | 3567 | { |
| | 3568 | /* 50% health? */ |
| | 3569 | if (General_GetAIModuleForRetreat(sbPtr, predatorStatusPointer->closets_target->containingModule->m_aimodule, 5)) |
| | 3570 | predatorStatusPointer->behaviourState = PBS_Withdrawing; |
| | 3571 | else |
| | 3572 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 3573 | return; |
| | 3574 | } |
| | 3575 | |
| | 3576 | if (predatorStatusPointer->volleySize >= predatorStatusPointer->Selected_Weapon->VolleySize) |
| | 3577 | { |
| | 3578 | if (predatorStatusPointer->enableSwap && ((FastRandom() & 65535) > 32767)) |
| | 3579 | { |
| | 3580 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3581 | predator_change_behaviour(sbPtr); |
| | 3582 | return; |
| | 3583 | } |
| | 3584 | } |
| | 3585 | else |
| | 3586 | { |
| | 3587 | /* And another! */ |
| | 3588 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 3589 | } |
| | 3590 | } |
| | 3591 | } |
| | 3592 | |
| | 3593 | static void Execute_PNS_DischargePistol(STRATEGYBLOCK *sbPtr, int distance_to_target) |
| | 3594 | { |
| | 3595 | VECTORCH orientationDirn; |
| | 3596 | PREDATOR_STATUS_BLOCK *predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3597 | |
| | 3598 | /* Always turn to face... */ |
| | 3599 | NPCGetTargetPosition(&predatorStatusPointer->weaponTarget, predatorStatusPointer->closets_target); |
| | 3600 | |
| | 3601 | /* Fix weapon target! */ |
| | 3602 | { |
| | 3603 | predatorStatusPointer->weaponTarget.vx -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat11, 200); |
| | 3604 | predatorStatusPointer->weaponTarget.vy -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat12, 200); |
| | 3605 | predatorStatusPointer->weaponTarget.vz -= MUL_FIXED(sbPtr->DynPtr->OrientMat.mat13, 200); |
| | 3606 | } |
| | 3607 | |
| | 3608 | /* Aim up a little? */ |
| | 3609 | int range = VectorDistance(&predatorStatusPointer->weaponTarget, &sbPtr->DynPtr->Position); |
| | 3610 | |
| | 3611 | if (range > 5000) |
| | 3612 | { |
| | 3613 | /* Out of range? */ |
| | 3614 | if(range > 20000) |
| | 3615 | { |
| | 3616 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 3617 | predator_change_behaviour(sbPtr); |
| | 3618 | return; |
| | 3619 | } |
| | 3620 | |
| | 3621 | predatorStatusPointer->weaponTarget.vy -= range / 6; |
| | 3622 | } |
| | 3623 | else |
| | 3624 | { |
| | 3625 | /* I'm afraid it just won't work. */ |
| | 3626 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3627 | predator_change_behaviour(sbPtr); |
| | 3628 | return; |
| | 3629 | } |
| | 3630 | |
| | 3631 | /* orientate to firing point first */ |
| | 3632 | if (predatorStatusPointer->My_Elevation_Section) |
| | 3633 | { |
| | 3634 | /* Assume range large w.r.t. half shoulder width... */ |
| | 3635 | orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - predatorStatusPointer->My_Elevation_Section->World_Offset.vx; |
| | 3636 | orientationDirn.vy = 0; |
| | 3637 | orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - predatorStatusPointer->My_Elevation_Section->World_Offset.vz; |
| | 3638 | } |
| | 3639 | else |
| | 3640 | { |
| | 3641 | orientationDirn.vx = predatorStatusPointer->weaponTarget.vx - sbPtr->DynPtr->Position.vx; |
| | 3642 | orientationDirn.vy = 0; |
| | 3643 | orientationDirn.vz = predatorStatusPointer->weaponTarget.vz - sbPtr->DynPtr->Position.vz; |
| | 3644 | } |
| | 3645 | |
| | 3646 | /* closets_target shift? */ |
| | 3647 | int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 3648 | |
| | 3649 | /* If still tweening, pause. */ |
| | 3650 | if (predatorStatusPointer->HModelController.Tweening != Controller_NoTweening) |
| | 3651 | return; |
| | 3652 | |
| | 3653 | predatorStatusPointer->stateTimer -= NormalFrameTime; |
| | 3654 | |
| | 3655 | /* You must have fired already. */ |
| | 3656 | |
| | 3657 | if(predatorStatusPointer->stateTimer > 0) |
| | 3658 | return; |
| | 3659 | |
| | 3660 | if (predatorStatusPointer->stateTimer == predatorStatusPointer->Selected_Weapon->FiringRate) |
| | 3661 | { |
| | 3662 | predatorStatusPointer->HModelController.Playing = 0; |
| | 3663 | |
| | 3664 | /* Only terminate if you haven't fired yet... */ |
| | 3665 | if (!NPCCanSeeTarget(sbPtr, predatorStatusPointer->closets_target)) |
| | 3666 | { |
| | 3667 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 3668 | predator_change_behaviour(sbPtr); |
| | 3669 | return; |
| | 3670 | } |
| | 3671 | |
| | 3672 | /* we are not correctly orientated to the target: this could happen because we have |
| | 3673 | just entered this state, or the target has moved during firing*/ |
| | 3674 | |
| | 3675 | if(!correctlyOrientated) |
| | 3676 | return; |
| | 3677 | |
| | 3678 | /* If you are correctly oriented, you can now fire! */ |
| | 3679 | |
| | 3680 | predatorStatusPointer->HModelController.Playing = 1; |
| | 3681 | predatorStatusPointer->HModelController.sequence_timer = 0; |
| | 3682 | |
| | 3683 | /* Now fire a bolt. */ |
| | 3684 | |
| | 3685 | { |
| | 3686 | SECTION_DATA *muzzle = GetThisSectionData(predatorStatusPointer->HModelController.section_data, "dum flash"); |
| | 3687 | |
| | 3688 | Pred_Pistol_Bolt(&muzzle->World_Offset, &muzzle->SecMat, 0); |
| | 3689 | predatorStatusPointer->volleySize++; |
| | 3690 | } |
| | 3691 | |
| | 3692 | Sound_Play(SID_PRED_PISTOL, "d", &sbPtr->DynPtr->Position); |
| | 3693 | |
| | 3694 | if (predatorStatusPointer->volleySize > 3) |
| | 3695 | predatorStatusPointer->enableSwap = 1; |
| | 3696 | } |
| | 3697 | |
| | 3698 | { |
| | 3699 | /* we are far enough away, so return to approach? */ |
| | 3700 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Predator]; |
| | 3701 | |
| | 3702 | if ((sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-1))) && (sbPtr->DamageBlock.Health >
0)) |
| | 3703 | { |
| | 3704 | /* 50% health? */ |
| | 3705 | if (General_GetAIModuleForRetreat(sbPtr, predatorStatusPointer->closets_target->containingModule->m_aimodule, 5)) |
| | 3706 | predatorStatusPointer->behaviourState = PBS_Withdrawing; |
| | 3707 | else |
| | 3708 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 3709 | } |
| | 3710 | else if (predatorStatusPointer->volleySize >= predatorStatusPointer->Selected_Weapon->VolleySize) |
| | 3711 | { |
| | 3712 | if (((FastRandom() & 65535) > 32767) && predatorStatusPointer->enableSwap) |
| | 3713 | predatorStatusPointer->behaviourState = PBS_SwapWeapon; |
| | 3714 | else |
| | 3715 | predatorStatusPointer->behaviourState = PBS_Engaging; |
| | 3716 | |
| | 3717 | predator_change_behaviour(sbPtr); |
| | 3718 | } |
| | 3719 | else |
| | 3720 | { |
| | 3721 | /* And another! */ |
| | 3722 | predatorStatusPointer->stateTimer = predatorStatusPointer->Selected_Weapon->FiringRate; |
| | 3723 | } |
| | 3724 | } |
| | 3725 | } |
| | 3726 | |
| | 3727 | static const PREDATOR_WEAPON_DATA NPC_Predator_Weapons[] = |
| | 3728 | { |
| | 3729 | { |
| | 3730 | PNPCW_Wristblade, /* ID */ |
| | 3731 | Execute_PNS_AttackWithMeleeWeapon, /* Fire Func. */ |
| | 3732 | "pred with wristblade", /* HierarchyName */ |
| | 3733 | NULL, /* GunName */ |
| | 3734 | "R shoulder", /* ElevationName */ |
| | 3735 | "predator", /* HitLocationTableName */ |
| | 3736 | 0, // MinRange |
| | 3737 | 1500, // MaxRange |
| | 3738 | 65536<<1, /* Firing Rate */ |
| | 3739 | 10, /* VolleySize */ |
| | 3740 | 65536>>1, /* SwappingTime */ |
| | 3741 | 1, /* UseElevation */ |
| | 3742 | }, |
| | 3743 | { |
| | 3744 | PNPCW_Medicomp, /* ID */ |
| | 3745 | Execute_PNS_DischargePistol, /* Fire Func. */ |
| | 3746 | "medicomp", /* HierarchyName */ |
| | 3747 | "P caster box", /* GunName */ |
| | 3748 | "R shoulder", /* ElevationName */ |
| | 3749 | "predator", /* HitLocationTableName */ |
| | 3750 | 15000, // MinRange |
| | 3751 | 0, // MaxRange |
| | 3752 | 65536>>3, /* Firing Rate */ |
| | 3753 | 8, /* VolleySize */ |
| | 3754 | 65536>>1, /* SwappingTime */ |
| | 3755 | 1, /* UseElevation */ |
| | 3756 | }, |
| | 3757 | { |
| | 3758 | PNPCW_PlasmaCaster, /* ID */ |
| | 3759 | Execute_PNS_AttackWithPlasmaCaster, /* Fire Func. */ |
| | 3760 | "pred with Plasma Caster", /* HierarchyName */ |
| | 3761 | "Plasma caster", /* GunName */ |
| | 3762 | "Plasma caster", /* ElevationName */ |
| | 3763 | "predator", /* HitLocationTableName */ |
| | 3764 | 0, // MinRange |
| | 3765 | 40000, // MaxRange |
| | 3766 | 65536, /* Firing Rate */ |
| | 3767 | 10, /* VolleySize */ |
| | 3768 | 65536, /* SwappingTime */ |
| | 3769 | 1, /* UseElevation */ |
| | 3770 | }, |
| | 3771 | { |
| | 3772 | PNPCW_Staff, /* ID */ |
| | 3773 | Execute_PNS_AttackWithMeleeWeapon, /* Fire Func. */ |
| | 3774 | "pred with staff", /* HierarchyName */ |
| | 3775 | NULL, /* GunName */ |
| | 3776 | "R shoulder", /* ElevationName */ |
| | 3777 | "predator", /* HitLocationTableName */ |
| | 3778 | 0, // MinRange |
| | 3779 | 2000, // MaxRange |
| | 3780 | 65536<<1, /* Firing Rate */ |
| | 3781 | 10, /* VolleySize */ |
| | 3782 | 65536>>1, /* SwappingTime */ |
| | 3783 | 0, /* UseElevation */ |
| | 3784 | }, |
| | 3785 | { |
| | 3786 | PNPCW_Speargun, /* ID */ |
| | 3787 | Execute_PNS_DischargeSpeargun, /* Fire Func. */ |
| | 3788 | "Speargun", /* HierarchyName */ |
| | 3789 | "staff gun root", /* GunName */ |
| | 3790 | "R shoulder", /* ElevationName */ |
| | 3791 | "predator", /* HitLocationTableName */ |
| | 3792 | 0, // MinRange |
| | 3793 | 50000, // MaxRange |
| | 3794 | 65536>>2, /* Firing Rate */ |
| | 3795 | 10, /* VolleySize */ |
| | 3796 | 65536>>1, /* SwappingTime */ |
| | 3797 | 1, /* UseElevation */ |
| | 3798 | }, |
| | 3799 | { |
| | 3800 | PNPCW_Pistol, /* ID */ |
| | 3801 | Execute_PNS_DischargePistol, /* Fire Func. */ |
| | 3802 | "pred + pistol", /* HierarchyName */ |
| | 3803 | "pistol", /* GunName */ |
| | 3804 | "R shoulder", /* ElevationName */ |
| | 3805 | "predator", /* HitLocationTableName */ |
| | 3806 | 5000, // MinRange |
| | 3807 | 20000, // MaxRange |
| | 3808 | 65536, /* Firing Rate */ |
| | 3809 | 8, /* VolleySize */ |
| | 3810 | 65536>>1, /* SwappingTime */ |
| | 3811 | 1, /* UseElevation */ |
| | 3812 | } |
| | 3813 | }; |
| | 3814 | |
| | 3815 | const PREDATOR_WEAPON_DATA *GetThisNPCPredatorWeapon(PREDATOR_NPC_WEAPONS this_id) |
| | 3816 | { |
| | 3817 | return &NPC_Predator_Weapons[this_id]; |
| | 3818 | } |
| | 3819 | |
| | 3820 | /*--------------------** |
| | 3821 | ** Loading and Saving ** |
| | 3822 | **--------------------*/ |
| | 3823 | #include "savegame.h" |
| | 3824 | typedef struct predator_save_block |
| | 3825 | { |
| | 3826 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 3827 | |
| | 3828 | //behaviour block stuff |
| | 3829 | signed int health; |
| | 3830 | PRED_BHSTATE behaviourState; |
| | 3831 | PRED_BHSTATE lastState; |
| | 3832 | |
| | 3833 | int stateTimer; |
| | 3834 | int internalState; |
| | 3835 | int patience; |
| | 3836 | int enableSwap; |
| | 3837 | int enableTaunt; |
| | 3838 | VECTORCH weaponTarget; /* target position for firing weapon at */ |
| | 3839 | int volleySize; /* used for weapon control */ |
| | 3840 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 3841 | NPC_WANDERDATA wanderData; |
| | 3842 | |
| | 3843 | int IAmCrouched; |
| | 3844 | int personalNumber; /* for predator personalisation */ |
| | 3845 | int nearSpeed; |
| | 3846 | int GibbFactor; |
| | 3847 | int incidentFlag; |
| | 3848 | int incidentTimer; |
| | 3849 | |
| | 3850 | PREDATOR_NPC_WEAPONS MeleeWeapon; |
| | 3851 | PREDATOR_NPC_WEAPONS SecondaryWeapon; |
| | 3852 | PREDATOR_NPC_WEAPONS ChangeToWeapon; |
| | 3853 | |
| | 3854 | /* these are for cloaking... */ |
| | 3855 | PRED_CLOAKSTATE CloakStatus; |
| | 3856 | int CloakingEffectiveness; |
| | 3857 | int CloakTimer; |
| | 3858 | |
| | 3859 | /* And these for the laser dots. */ |
| | 3860 | THREE_LASER_DOT_DESC Pred_Laser_Sight; |
| | 3861 | int Pred_Laser_On:1; |
| | 3862 | int Angry; |
| | 3863 | int RifleArrows; |
| | 3864 | int path; |
| | 3865 | int stepnumber; |
| | 3866 | |
| | 3867 | //annoying pointer related things |
| | 3868 | |
| | 3869 | int weapon_id; |
| | 3870 | int currentAttackCode; |
| | 3871 | char Target_SBname[SB_NAME_LENGTH]; |
| | 3872 | |
| | 3873 | int missionmodule_index; |
| | 3874 | int fearmodule_index; |
| | 3875 | |
| | 3876 | //strategyblock stuff |
| | 3877 | DAMAGEBLOCK DamageBlock; |
| | 3878 | DYNAMICSBLOCK dynamics; |
| | 3879 | |
| | 3880 | } PREDATOR_SAVE_BLOCK; |
| | 3881 | |
| | 3882 | //defines for load/save macros |
| | 3883 | #define SAVELOAD_BLOCK block |
| | 3884 | #define SAVELOAD_BEHAV predatorStatusPointer |
| | 3885 | |
| | 3886 | void LoadStrategy_Predator(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 3887 | { |
| | 3888 | PREDATOR_SAVE_BLOCK* block = (PREDATOR_SAVE_BLOCK*) header; |
| | 3889 | |
| | 3890 | //check the size of the save block |
| | 3891 | if(header->size != sizeof(*block)) |
| | 3892 | return; |
| | 3893 | |
| | 3894 | //find the existing strategy block |
| | 3895 | STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname); |
| | 3896 | |
| | 3897 | if(!sbPtr) |
| | 3898 | return; |
| | 3899 | /* |
| | 3900 | Check the strategy type. |
| | 3901 | Slight complication here , since it might be a dormant predator |
| | 3902 | (assuming that they are actually used in any of the levels) |
| | 3903 | */ |
| | 3904 | |
| | 3905 | switch(sbPtr->type) |
| | 3906 | { |
| | 3907 | case I_BehaviourDormantPredator: |
| | 3908 | { |
| | 3909 | //best make it un-dormant then |
| | 3910 | ActivateDormantPredator(sbPtr); |
| | 3911 | } |
| | 3912 | case I_BehaviourPredator: |
| | 3913 | break; |
| | 3914 | default: |
| | 3915 | return; |
| | 3916 | } |
| | 3917 | |
| | 3918 | PREDATOR_STATUS_BLOCK* predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->dataptr; |
| | 3919 | |
| | 3920 | COPYELEMENT_LOAD(health) |
| | 3921 | COPYELEMENT_LOAD(behaviourState) |
| | 3922 | COPYELEMENT_LOAD(lastState) |
| | 3923 | COPYELEMENT_LOAD(stateTimer) |
| | 3924 | COPYELEMENT_LOAD(internalState) |
| | 3925 | COPYELEMENT_LOAD(patience) |
| | 3926 | COPYELEMENT_LOAD(enableSwap) |
| | 3927 | COPYELEMENT_LOAD(enableTaunt) |
| | 3928 | COPYELEMENT_LOAD(weaponTarget) /* target position for firing weapon at */ |
| | 3929 | COPYELEMENT_LOAD(volleySize) /* used for weapon control */ |
| | 3930 | COPYELEMENT_LOAD(obstruction) |
| | 3931 | COPYELEMENT_LOAD(wanderData) |
| | 3932 | COPYELEMENT_LOAD(IAmCrouched) |
| | 3933 | COPYELEMENT_LOAD(personalNumber) /* for predator personalisation */ |
| | 3934 | COPYELEMENT_LOAD(nearSpeed) |
| | 3935 | COPYELEMENT_LOAD(GibbFactor) |
| | 3936 | COPYELEMENT_LOAD(incidentFlag) |
| | 3937 | COPYELEMENT_LOAD(incidentTimer) |
| | 3938 | COPYELEMENT_LOAD(SecondaryWeapon) |
| | 3939 | COPYELEMENT_LOAD(ChangeToWeapon) |
| | 3940 | COPYELEMENT_LOAD(CloakStatus) |
| | 3941 | COPYELEMENT_LOAD(CloakingEffectiveness) |
| | 3942 | COPYELEMENT_LOAD(CloakTimer) |
| | 3943 | COPYELEMENT_LOAD(Pred_Laser_Sight) |
| | 3944 | COPYELEMENT_LOAD(Pred_Laser_On) |
| | 3945 | COPYELEMENT_LOAD(Angry) |
| | 3946 | COPYELEMENT_LOAD(RifleArrows) |
| | 3947 | COPYELEMENT_LOAD(path) |
| | 3948 | COPYELEMENT_LOAD(stepnumber) |
| | 3949 | |
| | 3950 | predatorStatusPointer->MeleeWeapon = GetThisNPCPredatorWeapon(block->MeleeWeapon); |
| | 3951 | |
| | 3952 | //load ai module pointers |
| | 3953 | predatorStatusPointer->missionmodule = GetPointerFromAIModuleIndex(block->missionmodule_index); |
| | 3954 | predatorStatusPointer->fearmodule = GetPointerFromAIModuleIndex(block->fearmodule_index); |
| | 3955 | |
| | 3956 | //load target |
| | 3957 | COPY_NAME(predatorStatusPointer->Target_SBname,block->Target_SBname); |
| | 3958 | predatorStatusPointer->closets_target = FindSBWithName(predatorStatusPointer->Target_SBname); |
| | 3959 | |
| | 3960 | //get the predator's attack from the attack code |
| | 3961 | predatorStatusPointer->current_attack = GetThisAttack_FromUniqueCode(block->currentAttackCode); |
| | 3962 | |
| | 3963 | predatorStatusPointer->Selected_Weapon = GetThisNPCPredatorWeapon(block->weapon_id); |
| | 3964 | |
| | 3965 | //copy strategy block stuff |
| | 3966 | *sbPtr->DynPtr = block->dynamics; |
| | 3967 | sbPtr->DamageBlock = block->DamageBlock; |
| | 3968 | |
| | 3969 | //load hierarchy |
| | 3970 | { |
| | 3971 | SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); |
| | 3972 | if(hier_header) |
| | 3973 | LoadHierarchy(hier_header,&predatorStatusPointer->HModelController); |
| | 3974 | } |
| | 3975 | |
| | 3976 | //sort out section pointers |
| | 3977 | predatorStatusPointer->My_Elevation_Section =
GetThisSectionData(predatorStatusPointer->HModelController.section_data,predatorStatusPointer->Selected_Weapon->ElevationName); |
| | 3978 | |
| | 3979 | Load_SoundState(&predatorStatusPointer->soundHandle); |
| | 3980 | } |
| | 3981 | |
| | 3982 | void SaveStrategy_Predator(STRATEGYBLOCK* sbPtr) |
| | 3983 | { |
| | 3984 | PREDATOR_SAVE_BLOCK *block; |
| | 3985 | |
| | 3986 | GET_STRATEGY_SAVE_BLOCK(block, sbPtr); |
| | 3987 | PREDATOR_STATUS_BLOCK* predatorStatusPointer = (PREDATOR_STATUS_BLOCK*) sbPtr->dataptr; |
| | 3988 | |
| | 3989 | //start copying stuff |
| | 3990 | |
| | 3991 | COPYELEMENT_SAVE(health) |
| | 3992 | COPYELEMENT_SAVE(behaviourState) |
| | 3993 | COPYELEMENT_SAVE(lastState) |
| | 3994 | COPYELEMENT_SAVE(stateTimer) |
| | 3995 | COPYELEMENT_SAVE(internalState) |
| | 3996 | COPYELEMENT_SAVE(patience) |
| | 3997 | COPYELEMENT_SAVE(enableSwap) |
| | 3998 | COPYELEMENT_SAVE(enableTaunt) |
| | 3999 | COPYELEMENT_SAVE(weaponTarget) /* target position for firing weapon at */ |
| | 4000 | COPYELEMENT_SAVE(volleySize) /* used for weapon control */ |
| | 4001 | COPYELEMENT_SAVE(obstruction) |
| | 4002 | COPYELEMENT_SAVE(wanderData) |
| | 4003 | COPYELEMENT_SAVE(IAmCrouched) |
| | 4004 | COPYELEMENT_SAVE(personalNumber) /* for predator personalisation */ |
| | 4005 | COPYELEMENT_SAVE(nearSpeed) |
| | 4006 | COPYELEMENT_SAVE(GibbFactor) |
| | 4007 | COPYELEMENT_SAVE(incidentFlag) |
| | 4008 | COPYELEMENT_SAVE(incidentTimer) |
| | 4009 | COPYELEMENT_SAVE(SecondaryWeapon) |
| | 4010 | COPYELEMENT_SAVE(ChangeToWeapon) |
| | 4011 | COPYELEMENT_SAVE(CloakStatus) |
| | 4012 | COPYELEMENT_SAVE(CloakingEffectiveness) |
| | 4013 | COPYELEMENT_SAVE(CloakTimer) |
| | 4014 | COPYELEMENT_SAVE(Pred_Laser_Sight) |
| | 4015 | COPYELEMENT_SAVE(Pred_Laser_On) |
| | 4016 | COPYELEMENT_SAVE(Angry) |
| | 4017 | COPYELEMENT_SAVE(RifleArrows) |
| | 4018 | COPYELEMENT_SAVE(path) |
| | 4019 | COPYELEMENT_SAVE(stepnumber) |
| | 4020 | block->MeleeWeapon = predatorStatusPointer->MeleeWeapon->id; |
| | 4021 | |
| | 4022 | //save ai module pointers |
| | 4023 | block->missionmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->missionmodule); |
| | 4024 | block->fearmodule_index = GetIndexFromAIModulePointer(predatorStatusPointer->fearmodule); |
| | 4025 | |
| | 4026 | //save target |
| | 4027 | COPY_NAME(block->Target_SBname, predatorStatusPointer->Target_SBname); |
| | 4028 | |
| | 4029 | if(predatorStatusPointer->current_attack) |
| | 4030 | block->currentAttackCode = predatorStatusPointer->current_attack->Unique_Code; |
| | 4031 | else |
| | 4032 | block->currentAttackCode = -1; |
| | 4033 | |
| | 4034 | //save predator's weapon |
| | 4035 | if(predatorStatusPointer->Selected_Weapon) |
| | 4036 | block->weapon_id = predatorStatusPointer->Selected_Weapon->id; |
| | 4037 | else |
| | 4038 | block->weapon_id = -1; |
| | 4039 | |
| | 4040 | //copy strategy block stuff |
| | 4041 | block->dynamics = *sbPtr->DynPtr; |
| | 4042 | block->dynamics.CollisionReportPtr = 0; |
| | 4043 | block->DamageBlock = sbPtr->DamageBlock; |
| | 4044 | |
| | 4045 | //save the hierarchy |
| | 4046 | SaveHierarchy(&predatorStatusPointer->HModelController); |
| | 4047 | |
| | 4048 | Save_SoundState(&predatorStatusPointer->soundHandle); |
| | 4049 | } |