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