| | 1 | #include "system.h" |
| | 2 | #include "npc_common.h" |
| | 3 | #include "npc_xenoborg.h" |
| | 4 | #include "bh_far.h" |
| | 5 | #include "game_statistics.h" |
| | 6 | #include <stdlib.h> |
| | 7 | |
| | 8 | #define ShowXenoStats 0 |
| | 9 | #define XENO_SENTRYTIME (20) |
| | 10 | #define FAR_XENO_ACTIVITY 0 |
| | 11 | #define FIRING_RATE_LEFT 25 |
| | 12 | #define FIRING_RATE_RIGHT 25 |
| | 13 | #define XENO_WALKING_ANIM_SPEED (ONE_FIXED<<1) |
| | 14 | #define XENO_TURNING_ANIM_SPEED (ONE_FIXED<<1) |
| | 15 | |
| | 16 | static void HandleWeaponImpact1(VECTORCH *positionPtr, STRATEGYBLOCK *sbPtr, VECTORCH *directionPtr, int multiple, SECTION_DATA *this_section_data) |
| | 17 | { |
| | 18 | VECTORCH incoming,*invec; |
| | 19 | |
| | 20 | /* 'multiple' is now in FIXED POINT! */ |
| | 21 | |
| | 22 | if(sbPtr) |
| | 23 | { |
| | 24 | if (sbPtr->DynPtr) |
| | 25 | { |
| | 26 | MATRIXCH WtoLMat = sbPtr->DynPtr->OrientMat; |
| | 27 | /* Consider incoming hit direction. */ |
| | 28 | TransposeMatrixCH(&WtoLMat); |
| | 29 | RotateAndCopyVector(directionPtr, &incoming, &WtoLMat); |
| | 30 | invec = &incoming; |
| | 31 | } |
| | 32 | else |
| | 33 | { |
| | 34 | invec = NULL; |
| | 35 | } |
| | 36 | |
| | 37 | if (this_section_data && sbPtr->DisplayBlock && sbPtr->DisplayBlock->HModelControlBlock) |
| | 38 | { |
| | 39 | /* Netghost case now handled properly. */ |
| | 40 | AddDecalToHModel(&LOS_ObjectNormal, &LOS_Point, this_section_data); |
| | 41 | |
| | 42 | assert(sbPtr->DisplayBlock->HModelControlBlock == this_section_data->my_controller); |
| | 43 | CauseDamageToHModel(sbPtr->DisplayBlock->HModelControlBlock, sbPtr, &TemplateAmmo[AMMO_XENOBORG].MaxDamage, multiple, this_section_data,
invec, positionPtr, 0); |
| | 44 | } |
| | 45 | else |
| | 46 | { |
| | 47 | CauseDamageToObject(sbPtr, &TemplateAmmo[AMMO_XENOBORG].MaxDamage, multiple,invec); |
| | 48 | } |
| | 49 | |
| | 50 | if (sbPtr->DynPtr) |
| | 51 | { |
| | 52 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 53 | EULER rotation; |
| | 54 | int magnitudeOfForce = (5000 * TotalKineticDamage(&TemplateAmmo[AMMO_XENOBORG].MaxDamage)) / dynPtr->Mass; |
| | 55 | /* okay, not too sure yet what this should do */ |
| | 56 | dynPtr->LinImpulse.vx += MUL_FIXED(directionPtr->vx, magnitudeOfForce); |
| | 57 | dynPtr->LinImpulse.vy += MUL_FIXED(directionPtr->vy, magnitudeOfForce); |
| | 58 | dynPtr->LinImpulse.vz += MUL_FIXED(directionPtr->vz, magnitudeOfForce); |
| | 59 | } |
| | 60 | } |
| | 61 | |
| | 62 | /* KJL 10:44:49 02/03/98 - add bullet hole to world */ |
| | 63 | if (LOS_ObjectHitPtr) |
| | 64 | { |
| | 65 | /* only add to the landscape, ie. modules */ |
| | 66 | if (LOS_ObjectHitPtr->Module && !LOS_ObjectHitPtr->ObMorphCtrl) |
| | 67 | { |
| | 68 | /* bad idea to put bullethole on a morphing object */ |
| | 69 | MakeDecal(DECAL_BULLETHOLE, &LOS_ObjectNormal, positionPtr, LOS_ObjectHitPtr->Module->m_index); |
| | 70 | } |
| | 71 | } |
| | 72 | } |
| | 73 | |
| | 74 | int RATweak = 40; |
| | 75 | |
| | 76 | static void Xeno_SwitchLED(STRATEGYBLOCK *sbPtr,int state) |
| | 77 | { |
| | 78 | assert(sbPtr); |
| | 79 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 80 | assert(xenoStatusPointer); |
| | 81 | |
| | 82 | SECTION_DATA *led = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "led"); |
| | 83 | |
| | 84 | if (led && led->tac_ptr) |
| | 85 | { |
| | 86 | led->tac_ptr->tac_sequence = state ; |
| | 87 | led->tac_ptr->tac_txah_s = GetTxAnimHeaderFromShape(led->tac_ptr, led->ShapeNum); |
| | 88 | } |
| | 89 | } |
| | 90 | |
| | 91 | static int make_new_xenoborg(STRATEGYBLOCK *sbPtr) |
| | 92 | { |
| | 93 | sbPtr->dataptr = malloc(sizeof(XENO_STATUS_BLOCK)); |
| | 94 | sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL); |
| | 95 | |
| | 96 | if(NULL == sbPtr->dataptr) |
| | 97 | { |
| | 98 | RemoveBehaviourStrategy(sbPtr); |
| | 99 | return 0; |
| | 100 | } |
| | 101 | |
| | 102 | sbPtr->maintainVisibility = 1; |
| | 103 | |
| | 104 | { |
| | 105 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Xenoborg]; |
| | 106 | sbPtr->DamageBlock = NpcData->StartingStats; |
| | 107 | sbPtr->DamageBlock.Health = NpcData->StartingStats.Health << ONE_FIXED_SHIFT; |
| | 108 | sbPtr->DamageBlock.Armour = NpcData->StartingStats.Armour << ONE_FIXED_SHIFT; |
| | 109 | } |
| | 110 | |
| | 111 | XENO_STATUS_BLOCK *new_xenoborg = (XENO_STATUS_BLOCK *)sbPtr->dataptr; |
| | 112 | |
| | 113 | NPC_InitMovementData(&new_xenoborg->moveData); |
| | 114 | NPC_InitWanderData(&new_xenoborg->wanderData); |
| | 115 | InitWaypointManager(&new_xenoborg->waypointManager); |
| | 116 | |
| | 117 | new_xenoborg->HModelController.Deltas = NULL; |
| | 118 | new_xenoborg->HModelController.Root_Section = NULL; |
| | 119 | new_xenoborg->HModelController.section_data = NULL; |
| | 120 | new_xenoborg->behaviourState = XS_Inactive; |
| | 121 | new_xenoborg->lastState = XS_Inactive; |
| | 122 | new_xenoborg->stateTimer = XENO_POWERDOWN_TIME; |
| | 123 | |
| | 124 | new_xenoborg->obstruction.environment = 0; |
| | 125 | new_xenoborg->obstruction.destructableObject = 0; |
| | 126 | new_xenoborg->obstruction.otherCharacter = 0; |
| | 127 | new_xenoborg->obstruction.anySingleObstruction = 0; |
| | 128 | |
| | 129 | new_xenoborg->my_module = sbPtr->containingModule->m_aimodule; |
| | 130 | new_xenoborg->my_spot_therin = sbPtr->DynPtr->Position; |
| | 131 | |
| | 132 | { |
| | 133 | /* Pull out my_orientdir_therin. */ |
| | 134 | new_xenoborg->my_orientdir_therin.vx = 0; |
| | 135 | new_xenoborg->my_orientdir_therin.vx = 0; |
| | 136 | new_xenoborg->my_orientdir_therin.vz = 1000; |
| | 137 | |
| | 138 | RotateVector(&new_xenoborg->my_orientdir_therin, &sbPtr->DynPtr->OrientMat); |
| | 139 | } |
| | 140 | |
| | 141 | new_xenoborg->module_range = 7; |
| | 142 | new_xenoborg->UpTime = XENO_SENTRYTIME * ONE_FIXED; |
| | 143 | new_xenoborg->Wounds = 0; |
| | 144 | |
| | 145 | new_xenoborg->head_pan = NULL; |
| | 146 | new_xenoborg->head_tilt = NULL; |
| | 147 | new_xenoborg->left_arm_pan = NULL; |
| | 148 | new_xenoborg->left_arm_tilt = NULL; |
| | 149 | new_xenoborg->right_arm_pan = NULL; |
| | 150 | new_xenoborg->right_arm_tilt = NULL; |
| | 151 | new_xenoborg->torso_twist = NULL; |
| | 152 | |
| | 153 | new_xenoborg->Target = NULL; |
| | 154 | COPY_NAME(new_xenoborg->Target_SBname, Null_Name); |
| | 155 | |
| | 156 | new_xenoborg->targetTrackPos.vx = 0; |
| | 157 | new_xenoborg->targetTrackPos.vy = 0; |
| | 158 | new_xenoborg->targetTrackPos.vz = 0; |
| | 159 | |
| | 160 | new_xenoborg->Head_Pan = 0; |
| | 161 | new_xenoborg->Head_Tilt = 0; |
| | 162 | new_xenoborg->Left_Arm_Pan = 0; |
| | 163 | new_xenoborg->Left_Arm_Tilt = 0; |
| | 164 | new_xenoborg->Right_Arm_Pan = 0; |
| | 165 | new_xenoborg->Right_Arm_Tilt = 0; |
| | 166 | new_xenoborg->Torso_Twist = 0; |
| | 167 | |
| | 168 | new_xenoborg->Old_Head_Pan = 0; |
| | 169 | new_xenoborg->Old_Head_Tilt = 0; |
| | 170 | new_xenoborg->Old_Left_Arm_Pan = 0; |
| | 171 | new_xenoborg->Old_Left_Arm_Tilt = 0; |
| | 172 | new_xenoborg->Old_Right_Arm_Pan = 0; |
| | 173 | new_xenoborg->Old_Right_Arm_Tilt = 0; |
| | 174 | new_xenoborg->Old_Torso_Twist = 0; |
| | 175 | |
| | 176 | new_xenoborg->LeftMainBeam.BeamIsOn = 0; |
| | 177 | new_xenoborg->LeftMainBeam.BeamHasHitPlayer = 0; |
| | 178 | new_xenoborg->LeftMainBeam.SourcePosition = null_vec; |
| | 179 | new_xenoborg->LeftMainBeam.TargetPosition = null_vec; |
| | 180 | |
| | 181 | new_xenoborg->RightMainBeam.BeamIsOn = 0; |
| | 182 | new_xenoborg->RightMainBeam.BeamHasHitPlayer = 0; |
| | 183 | new_xenoborg->RightMainBeam.SourcePosition = null_vec; |
| | 184 | new_xenoborg->RightMainBeam.TargetPosition = null_vec; |
| | 185 | |
| | 186 | new_xenoborg->TargetingLaser[0].BeamIsOn= 0; |
| | 187 | new_xenoborg->TargetingLaser[0].BeamHasHitPlayer = 0; |
| | 188 | new_xenoborg->TargetingLaser[0].SourcePosition = null_vec; |
| | 189 | new_xenoborg->TargetingLaser[0].TargetPosition = null_vec; |
| | 190 | |
| | 191 | new_xenoborg->TargetingLaser[1].BeamIsOn = 0; |
| | 192 | new_xenoborg->TargetingLaser[1].BeamHasHitPlayer = 0; |
| | 193 | new_xenoborg->TargetingLaser[1].SourcePosition = null_vec; |
| | 194 | new_xenoborg->TargetingLaser[1].TargetPosition = null_vec; |
| | 195 | |
| | 196 | new_xenoborg->TargetingLaser[2].BeamIsOn = 0; |
| | 197 | new_xenoborg->TargetingLaser[2].BeamHasHitPlayer = 0; |
| | 198 | new_xenoborg->TargetingLaser[2].SourcePosition = null_vec; |
| | 199 | new_xenoborg->TargetingLaser[2].TargetPosition = null_vec; |
| | 200 | |
| | 201 | new_xenoborg->headpandir = 0; |
| | 202 | new_xenoborg->headtiltdir = 0; |
| | 203 | new_xenoborg->leftarmpandir = 0; |
| | 204 | new_xenoborg->leftarmtiltdir = 0; |
| | 205 | new_xenoborg->rightarmpandir = 0; |
| | 206 | new_xenoborg->rightarmtiltdir = 0; |
| | 207 | new_xenoborg->torsotwistdir = 0; |
| | 208 | |
| | 209 | new_xenoborg->headLock = 0; |
| | 210 | new_xenoborg->leftArmLock = 0; |
| | 211 | new_xenoborg->rightArmLock = 0; |
| | 212 | new_xenoborg->targetSightTest = 0; |
| | 213 | new_xenoborg->IAmFar = 0; |
| | 214 | //new_xenoborg->IAmFar = 1; |
| | 215 | new_xenoborg->ShotThisFrame = 0; |
| | 216 | |
| | 217 | new_xenoborg->FiringLeft = 0; |
| | 218 | new_xenoborg->FiringRight = 0; |
| | 219 | |
| | 220 | new_xenoborg->UseHeadLaser = 0; |
| | 221 | new_xenoborg->UseLALaser = 0; |
| | 222 | new_xenoborg->UseRALaser = 0; |
| | 223 | |
| | 224 | new_xenoborg->HeadLaserOnTarget = 0; |
| | 225 | new_xenoborg->LALaserOnTarget = 0; |
| | 226 | new_xenoborg->RALaserOnTarget = 0; |
| | 227 | |
| | 228 | new_xenoborg->head_moving = 0; |
| | 229 | new_xenoborg->la_moving = 0; |
| | 230 | new_xenoborg->ra_moving = 0; |
| | 231 | new_xenoborg->torso_moving = 0; |
| | 232 | |
| | 233 | new_xenoborg->soundHandle1 = SOUND_NOACTIVEINDEX; |
| | 234 | new_xenoborg->soundHandle2 = SOUND_NOACTIVEINDEX; |
| | 235 | |
| | 236 | new_xenoborg->incidentFlag = 0; |
| | 237 | new_xenoborg->incidentTimer = 0; |
| | 238 | |
| | 239 | new_xenoborg->head_whirr = SOUND_NOACTIVEINDEX; |
| | 240 | new_xenoborg->left_arm_whirr = SOUND_NOACTIVEINDEX; |
| | 241 | new_xenoborg->right_arm_whirr = SOUND_NOACTIVEINDEX; |
| | 242 | new_xenoborg->torso_whirr = SOUND_NOACTIVEINDEX; |
| | 243 | |
| | 244 | { |
| | 245 | int i; |
| | 246 | for(i=0; i < SB_NAME_LENGTH;i++) |
| | 247 | new_xenoborg->death_target_ID[i] = 0; |
| | 248 | } |
| | 249 | |
| | 250 | new_xenoborg->death_target_sbptr = NULL; |
| | 251 | new_xenoborg->death_target_request = 0; |
| | 252 | |
| | 253 | SECTION *root_section = GetNamedHierarchyFromLibrary("hnpc_xenoborg", "xenobasic"); |
| | 254 | |
| | 255 | if (!root_section || !sbPtr->containingModule) |
| | 256 | { |
| | 257 | RemoveBehaviourStrategy(sbPtr); |
| | 258 | return 0; |
| | 259 | } |
| | 260 | |
| | 261 | Create_HModel(&new_xenoborg->HModelController, root_section); |
| | 262 | InitHModelSequence(&new_xenoborg->HModelController, HMSQT_Xenoborg, XBSS_Powered_Down_Standard, ONE_FIXED); |
| | 263 | |
| | 264 | { |
| | 265 | DELTA_CONTROLLER *delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "HeadTilt", (int)HMSQT_Xenoborg,
(int)XBSS_Head_Vertical_Delta, 0); |
| | 266 | assert(delta); |
| | 267 | delta->timer = 32767; |
| | 268 | delta->Active = 0; |
| | 269 | |
| | 270 | delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "HeadPan", (int)HMSQT_Xenoborg, (int)XBSS_Head_Horizontal_Delta, 0); |
| | 271 | assert(delta); |
| | 272 | delta->timer = 32767; |
| | 273 | delta->Active = 0; |
| | 274 | |
| | 275 | delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "LeftArmTilt", (int)HMSQT_Xenoborg, (int)XBSS_LeftArm_Vertical_Delta, 0); |
| | 276 | assert(delta); |
| | 277 | delta->timer = 32767; |
| | 278 | delta->Active = 0; |
| | 279 | |
| | 280 | delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "LeftArmPan", (int)HMSQT_Xenoborg, (int)XBSS_LeftArm_Horizontal_Delta, 0); |
| | 281 | assert(delta); |
| | 282 | delta->timer = 32767; |
| | 283 | delta->Active = 0; |
| | 284 | |
| | 285 | delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "RightArmTilt", (int)HMSQT_Xenoborg, (int)XBSS_RightArm_Vertical_Delta ,0); |
| | 286 | assert(delta); |
| | 287 | delta->timer = 32767; |
| | 288 | delta->Active = 0; |
| | 289 | |
| | 290 | delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "RightArmPan", (int)HMSQT_Xenoborg, (int)XBSS_RightArm_Horizontal_Delta,
0); |
| | 291 | assert(delta); |
| | 292 | delta->timer = 32767; |
| | 293 | delta->Active = 0; |
| | 294 | |
| | 295 | delta = Add_Delta_Sequence(&new_xenoborg->HModelController, "TorsoTwist", (int)HMSQT_Xenoborg, (int)XBSS_Torso_Delta, 0); |
| | 296 | assert(delta); |
| | 297 | delta->timer = 32767; |
| | 298 | delta->Active = 0; |
| | 299 | } |
| | 300 | Xeno_SwitchLED(sbPtr, 0); |
| | 301 | return 1; |
| | 302 | } |
| | 303 | |
| | 304 | void MakeXenoborgNear(STRATEGYBLOCK *sbPtr) |
| | 305 | { |
| | 306 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 307 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 308 | |
| | 309 | DISPLAYBLOCK *dPtr = CreateActiveObject(); |
| | 310 | |
| | 311 | if(dPtr == NULL) |
| | 312 | return; /* if cannot create displayblock, leave far */ |
| | 313 | |
| | 314 | sbPtr->DisplayBlock = dPtr; |
| | 315 | dPtr->ObStrategyBlock = sbPtr; |
| | 316 | |
| | 317 | /* need to initialise positional information in the new display block */ |
| | 318 | dPtr->ObWorld = dynPtr->Position; |
| | 319 | dPtr->ObEuler = dynPtr->OrientEuler; |
| | 320 | dPtr->ObMat = dynPtr->OrientMat; |
| | 321 | |
| | 322 | /* state and sequence init */ |
| | 323 | NPC_InitMovementData(&xenoStatusPointer->moveData); |
| | 324 | InitWaypointManager(&xenoStatusPointer->waypointManager); |
| | 325 | |
| | 326 | dPtr->HModelControlBlock = &xenoStatusPointer->HModelController; |
| | 327 | |
| | 328 | ProveHModel(dPtr->HModelControlBlock, dPtr); |
| | 329 | |
| | 330 | xenoStatusPointer->IAmFar = 0; |
| | 331 | } |
| | 332 | |
| | 333 | void CreateXenoborg(VECTORCH *Position, int type) |
| | 334 | { |
| | 335 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourXenoborg); |
| | 336 | |
| | 337 | if(!sbPtr) |
| | 338 | { |
| | 339 | GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); |
| | 340 | return; |
| | 341 | } |
| | 342 | |
| | 343 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 344 | |
| | 345 | if(sbPtr->DynPtr) |
| | 346 | { |
| | 347 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 348 | AssignNewSBName(sbPtr); |
| | 349 | dynPtr->PrevPosition = dynPtr->Position = *Position; |
| | 350 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 351 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 352 | dynPtr->Mass = 200; |
| | 353 | make_new_xenoborg(sbPtr); |
| | 354 | } |
| | 355 | else |
| | 356 | { |
| | 357 | RemoveBehaviourStrategy(sbPtr); |
| | 358 | GADGET_NewOnScreenMessage("FAILED TO CREATE BOT: DYNBLOCK CREATION FAILURE"); |
| | 359 | } |
| | 360 | } |
| | 361 | |
| | 362 | void CastXenoborgBot() |
| | 363 | { |
| | 364 | #define BOTRANGE 2000 |
| | 365 | |
| | 366 | VECTORCH position = PlayerStatus.sbptr->DynPtr->Position; |
| | 367 | |
| | 368 | position.vx += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat31, BOTRANGE); |
| | 369 | position.vy += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat32, BOTRANGE); |
| | 370 | position.vz += MUL_FIXED(PlayerStatus.sbptr->DynPtr->OrientMat.mat33, BOTRANGE); |
| | 371 | |
| | 372 | CreateXenoborg(&position, 0); |
| | 373 | } |
| | 374 | |
| | 375 | static void VerifyDeltaControllers(STRATEGYBLOCK *sbPtr) |
| | 376 | { |
| | 377 | assert(sbPtr); |
| | 378 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 379 | assert(xenoStatusPointer); |
| | 380 | |
| | 381 | /* Nothing has deltas like a xenoborg does. */ |
| | 382 | |
| | 383 | xenoStatusPointer->head_pan = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"HeadPan"); |
| | 384 | assert(xenoStatusPointer->head_pan); |
| | 385 | |
| | 386 | xenoStatusPointer->head_tilt = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"HeadTilt"); |
| | 387 | assert(xenoStatusPointer->head_tilt); |
| | 388 | |
| | 389 | xenoStatusPointer->left_arm_pan = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"LeftArmPan"); |
| | 390 | assert(xenoStatusPointer->left_arm_pan); |
| | 391 | |
| | 392 | xenoStatusPointer->left_arm_tilt = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"LeftArmTilt"); |
| | 393 | assert(xenoStatusPointer->left_arm_tilt); |
| | 394 | |
| | 395 | xenoStatusPointer->right_arm_pan = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"RightArmPan"); |
| | 396 | assert(xenoStatusPointer->right_arm_pan); |
| | 397 | |
| | 398 | xenoStatusPointer->right_arm_tilt = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"RightArmTilt"); |
| | 399 | assert(xenoStatusPointer->right_arm_tilt); |
| | 400 | |
| | 401 | xenoStatusPointer->torso_twist = Get_Delta_Sequence(&xenoStatusPointer->HModelController,"TorsoTwist"); |
| | 402 | assert(xenoStatusPointer->torso_twist); |
| | 403 | } |
| | 404 | |
| | 405 | /* Patrick 4/7/97 ---------------------------------------------------- |
| | 406 | Xenoborg initialiser, visibility management, behaviour shell, and |
| | 407 | damage functions |
| | 408 | |
| | 409 | ChrisF 6/7/98. I don't think so... |
| | 410 | --------------------------------------------------------------------*/ |
| | 411 | void InitXenoborgBehaviour(void* bhdata, STRATEGYBLOCK *sbPtr) |
| | 412 | { |
| | 413 | int i; |
| | 414 | |
| | 415 | TOOLS_DATA_XENO *toolsData = (TOOLS_DATA_XENO *)bhdata; |
| | 416 | |
| | 417 | for(i=0; i < SB_NAME_LENGTH; i++) |
| | 418 | sbPtr->SBname[i] = toolsData->nameID[i]; |
| | 419 | |
| | 420 | /* create, initialise and attach a dynamics block */ |
| | 421 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 422 | |
| | 423 | if(sbPtr->DynPtr) |
| | 424 | { |
| | 425 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 426 | assert(dynPtr); |
| | 427 | dynPtr->PrevPosition = dynPtr->Position = toolsData->position; |
| | 428 | dynPtr->OrientEuler = toolsData->starteuler; |
| | 429 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 430 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 431 | |
| | 432 | dynPtr->Mass = 500; /* As opposed to 160. */ |
| | 433 | |
| | 434 | if(make_new_xenoborg(sbPtr)) |
| | 435 | { |
| | 436 | XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)sbPtr->dataptr; |
| | 437 | |
| | 438 | xenoStatus->module_range = toolsData->ModuleRange; |
| | 439 | xenoStatus->UpTime = toolsData->UpTime * ONE_FIXED; |
| | 440 | |
| | 441 | for(i=0; i < SB_NAME_LENGTH;i++) |
| | 442 | xenoStatus->death_target_ID[i] = toolsData->death_target_ID[i]; |
| | 443 | |
| | 444 | xenoStatus->death_target_request = toolsData->death_target_request; |
| | 445 | } |
| | 446 | } |
| | 447 | else |
| | 448 | { |
| | 449 | RemoveBehaviourStrategy(sbPtr); |
| | 450 | } |
| | 451 | } |
| | 452 | |
| | 453 | static void ComputeDeltaValues(STRATEGYBLOCK *sbPtr) |
| | 454 | { |
| | 455 | assert(sbPtr); |
| | 456 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 457 | assert(xenoStatusPointer); |
| | 458 | |
| | 459 | /* Interpret all status block values, and apply to deltas. */ |
| | 460 | /* Head Pan first. */ |
| | 461 | |
| | 462 | int angle = xenoStatusPointer->Head_Pan >> 4; |
| | 463 | |
| | 464 | if (angle >= 3072) |
| | 465 | angle -= 4096; |
| | 466 | |
| | 467 | if (angle >= 2048) |
| | 468 | angle = angle-4096; |
| | 469 | |
| | 470 | /* Now, we have an angle. */ |
| | 471 | |
| | 472 | if (angle > XENO_HEADPAN_GIMBALL) |
| | 473 | { |
| | 474 | angle = XENO_HEADPAN_GIMBALL; |
| | 475 | } |
| | 476 | else if (angle<-XENO_HEADPAN_GIMBALL) |
| | 477 | { |
| | 478 | angle = -XENO_HEADPAN_GIMBALL; |
| | 479 | } |
| | 480 | |
| | 481 | assert(xenoStatusPointer->head_pan); |
| | 482 | |
| | 483 | { |
| | 484 | int fake_timer = DIV_FIXED(angle, (XENO_HEADPAN_GIMBALL<<1)); |
| | 485 | |
| | 486 | fake_timer += 32767; |
| | 487 | fake_timer = 65536 - fake_timer; |
| | 488 | |
| | 489 | if (fake_timer > 65536) |
| | 490 | fake_timer = 65535; |
| | 491 | |
| | 492 | if (fake_timer < 0) |
| | 493 | fake_timer = 0; |
| | 494 | |
| | 495 | xenoStatusPointer->head_pan->timer = fake_timer; |
| | 496 | } |
| | 497 | |
| | 498 | /* Head tilt next. */ |
| | 499 | angle = xenoStatusPointer->Head_Tilt >> 4; |
| | 500 | |
| | 501 | if (angle >= 3072) |
| | 502 | angle -= 4096; |
| | 503 | |
| | 504 | if (angle >= 2048) |
| | 505 | angle = angle-3072; |
| | 506 | |
| | 507 | if (angle> 1024) |
| | 508 | angle = 2048 - angle; |
| | 509 | |
| | 510 | /* Now, we have an angle. */ |
| | 511 | |
| | 512 | if (angle > XENO_HEADTILT_GIMBALL) |
| | 513 | { |
| | 514 | angle = XENO_HEADTILT_GIMBALL; |
| | 515 | } |
| | 516 | else if (angle<-XENO_HEADTILT_GIMBALL) |
| | 517 | { |
| | 518 | angle = -XENO_HEADTILT_GIMBALL; |
| | 519 | } |
| | 520 | |
| | 521 | angle = angle*2; |
| | 522 | |
| | 523 | assert(angle >= -1024); |
| | 524 | assert(angle <= 1024); |
| | 525 | |
| | 526 | assert(xenoStatusPointer->head_tilt); |
| | 527 | |
| | 528 | { |
| | 529 | int fake_timer = 1024-angle; |
| | 530 | fake_timer <<= 5; |
| | 531 | |
| | 532 | if (fake_timer > 65536) |
| | 533 | fake_timer = 65535; |
| | 534 | |
| | 535 | assert(fake_timer >= 0); |
| | 536 | |
| | 537 | xenoStatusPointer->head_tilt->timer = fake_timer; |
| | 538 | } |
| | 539 | |
| | 540 | /* Left Arm Pan now. */ |
| | 541 | |
| | 542 | angle = xenoStatusPointer->Left_Arm_Pan>>4; |
| | 543 | |
| | 544 | if (angle >= 3072) |
| | 545 | angle -= 4096; |
| | 546 | |
| | 547 | if (angle >= 2048) |
| | 548 | angle = angle-4096; |
| | 549 | |
| | 550 | assert(xenoStatusPointer->left_arm_pan); |
| | 551 | |
| | 552 | /* Now, we have an angle. */ |
| | 553 | |
| | 554 | if (angle > XENO_LEFTARM_ACW_GIMBALL) |
| | 555 | { |
| | 556 | angle = XENO_LEFTARM_ACW_GIMBALL; |
| | 557 | } |
| | 558 | else if (angle<-XENO_LEFTARM_CW_GIMBALL) |
| | 559 | { |
| | 560 | angle = -XENO_LEFTARM_CW_GIMBALL; |
| | 561 | } |
| | 562 | |
| | 563 | { |
| | 564 | int fake_timer; |
| | 565 | |
| | 566 | if (angle > 0) |
| | 567 | { |
| | 568 | fake_timer = DIV_FIXED(angle,(XENO_LEFTARM_ACW_GIMBALL<<1)); |
| | 569 | fake_timer += 32767; |
| | 570 | fake_timer = 65536-fake_timer; |
| | 571 | |
| | 572 | if (fake_timer > 65536) |
| | 573 | fake_timer = 65535; |
| | 574 | |
| | 575 | if (fake_timer < 0) |
| | 576 | fake_timer = 0; |
| | 577 | } |
| | 578 | else |
| | 579 | { |
| | 580 | fake_timer = DIV_FIXED(angle,(XENO_LEFTARM_CW_GIMBALL<<1)); |
| | 581 | fake_timer += 32767; |
| | 582 | fake_timer = 65536-fake_timer; |
| | 583 | |
| | 584 | if (fake_timer > 65536) |
| | 585 | fake_timer = 65535; |
| | 586 | |
| | 587 | if (fake_timer < 0) |
| | 588 | fake_timer = 0; |
| | 589 | } |
| | 590 | |
| | 591 | xenoStatusPointer->left_arm_pan->timer = fake_timer; |
| | 592 | } |
| | 593 | |
| | 594 | /* Left Arm Tilt... */ |
| | 595 | |
| | 596 | angle = xenoStatusPointer->Left_Arm_Tilt>>4; |
| | 597 | |
| | 598 | if (angle >= 3072) |
| | 599 | angle -= 4096; |
| | 600 | |
| | 601 | if (angle >= 2048) |
| | 602 | angle = angle-3072; |
| | 603 | |
| | 604 | if (angle > 1024) |
| | 605 | angle = 2048-angle; |
| | 606 | |
| | 607 | assert(xenoStatusPointer->left_arm_tilt); |
| | 608 | |
| | 609 | /* Now, we have an angle. */ |
| | 610 | |
| | 611 | if (angle > XENO_ARM_PITCH_GIMBALL) |
| | 612 | { |
| | 613 | angle = XENO_ARM_PITCH_GIMBALL; |
| | 614 | } |
| | 615 | else if (angle<-XENO_ARM_PITCH_GIMBALL) |
| | 616 | { |
| | 617 | angle = -XENO_ARM_PITCH_GIMBALL; |
| | 618 | } |
| | 619 | |
| | 620 | assert(angle >= -1024); |
| | 621 | assert(angle <= 1024); |
| | 622 | |
| | 623 | { |
| | 624 | int fake_timer = 1024-angle; |
| | 625 | fake_timer <<= 5; |
| | 626 | |
| | 627 | if (fake_timer > 65536) |
| | 628 | fake_timer = 65535; |
| | 629 | |
| | 630 | assert(fake_timer >= 0); |
| | 631 | |
| | 632 | xenoStatusPointer->left_arm_tilt->timer = fake_timer; |
| | 633 | } |
| | 634 | |
| | 635 | /* Right Arm Pan now. */ |
| | 636 | |
| | 637 | angle = xenoStatusPointer->Right_Arm_Pan>>4; |
| | 638 | |
| | 639 | if (angle >= 3072) |
| | 640 | angle -= 4096; |
| | 641 | |
| | 642 | if (angle >= 2048) |
| | 643 | angle = angle-4096; |
| | 644 | |
| | 645 | assert(xenoStatusPointer->right_arm_pan); |
| | 646 | |
| | 647 | /* Now, we have an angle. */ |
| | 648 | |
| | 649 | if (angle > XENO_RIGHTARM_ACW_GIMBALL) |
| | 650 | { |
| | 651 | angle = XENO_RIGHTARM_ACW_GIMBALL; |
| | 652 | } |
| | 653 | else if (angle<-XENO_RIGHTARM_CW_GIMBALL) |
| | 654 | { |
| | 655 | angle = -XENO_RIGHTARM_CW_GIMBALL; |
| | 656 | } |
| | 657 | |
| | 658 | { |
| | 659 | int fake_timer; |
| | 660 | |
| | 661 | if (angle > 0) |
| | 662 | { |
| | 663 | fake_timer = DIV_FIXED(angle,(XENO_RIGHTARM_ACW_GIMBALL<<1)); |
| | 664 | fake_timer += 32767; |
| | 665 | |
| | 666 | if (fake_timer > 65536) |
| | 667 | fake_timer = 65535; |
| | 668 | } |
| | 669 | else |
| | 670 | { |
| | 671 | fake_timer = DIV_FIXED(angle,(XENO_RIGHTARM_CW_GIMBALL<<1)); |
| | 672 | fake_timer += 32767; |
| | 673 | |
| | 674 | if (fake_timer < 0) |
| | 675 | fake_timer = 0; |
| | 676 | } |
| | 677 | |
| | 678 | assert(fake_timer >= 0); |
| | 679 | assert(fake_timer < 65536); |
| | 680 | |
| | 681 | xenoStatusPointer->right_arm_pan->timer = fake_timer; |
| | 682 | } |
| | 683 | |
| | 684 | /* Right Arm Tilt... */ |
| | 685 | |
| | 686 | angle = xenoStatusPointer->Right_Arm_Tilt>>4; |
| | 687 | |
| | 688 | if (angle >= 3072) |
| | 689 | angle -= 4096; |
| | 690 | |
| | 691 | if (angle >= 2048) |
| | 692 | angle = angle-3072; |
| | 693 | |
| | 694 | if (angle > 1024) |
| | 695 | angle = 2048-angle; |
| | 696 | |
| | 697 | assert(xenoStatusPointer->right_arm_pan); |
| | 698 | |
| | 699 | /* Now, we have an angle. */ |
| | 700 | |
| | 701 | if (angle > XENO_ARM_PITCH_GIMBALL) |
| | 702 | { |
| | 703 | angle = XENO_ARM_PITCH_GIMBALL; |
| | 704 | } |
| | 705 | else if (angle<-XENO_ARM_PITCH_GIMBALL) |
| | 706 | { |
| | 707 | angle = -XENO_ARM_PITCH_GIMBALL; |
| | 708 | } |
| | 709 | |
| | 710 | assert(angle >= -1024); |
| | 711 | assert(angle <= 1024); |
| | 712 | |
| | 713 | { |
| | 714 | int fake_timer = 1024-angle; |
| | 715 | |
| | 716 | fake_timer <<= 5; |
| | 717 | |
| | 718 | if (fake_timer > 65536) |
| | 719 | fake_timer = 65535; |
| | 720 | |
| | 721 | assert(fake_timer >= 0); |
| | 722 | |
| | 723 | xenoStatusPointer->right_arm_tilt->timer = fake_timer; |
| | 724 | } |
| | 725 | |
| | 726 | /* ... and Torso Twist. */ |
| | 727 | |
| | 728 | angle = xenoStatusPointer->Torso_Twist>>4; |
| | 729 | |
| | 730 | if (angle >= 3072) |
| | 731 | angle -= 4096; |
| | 732 | |
| | 733 | if (angle >= 2048) |
| | 734 | angle = angle-4096; |
| | 735 | |
| | 736 | assert(xenoStatusPointer->torso_twist); |
| | 737 | |
| | 738 | /* Now, we have an angle. */ |
| | 739 | |
| | 740 | if (angle > XENO_TORSO_GIMBALL) |
| | 741 | { |
| | 742 | angle = XENO_TORSO_GIMBALL; |
| | 743 | } |
| | 744 | else if (angle<-XENO_TORSO_GIMBALL) |
| | 745 | { |
| | 746 | angle = -XENO_TORSO_GIMBALL; |
| | 747 | } |
| | 748 | |
| | 749 | { |
| | 750 | int fake_timer; |
| | 751 | |
| | 752 | if (angle > 0) |
| | 753 | { |
| | 754 | fake_timer = DIV_FIXED(angle,(XENO_TORSO_GIMBALL<<1)); |
| | 755 | fake_timer += 32767; |
| | 756 | |
| | 757 | if (fake_timer > 65536) |
| | 758 | fake_timer = 65535; |
| | 759 | } |
| | 760 | else |
| | 761 | { |
| | 762 | fake_timer = DIV_FIXED(angle,(XENO_TORSO_GIMBALL<<1)); |
| | 763 | fake_timer += 32767; |
| | 764 | |
| | 765 | if (fake_timer < 0) |
| | 766 | fake_timer = 0; |
| | 767 | } |
| | 768 | |
| | 769 | assert(fake_timer >= 0); |
| | 770 | assert(fake_timer < 65536); |
| | 771 | |
| | 772 | xenoStatusPointer->torso_twist->timer = fake_timer; |
| | 773 | } |
| | 774 | } |
| | 775 | |
| | 776 | static int Xenoborg_TargetFilter(STRATEGYBLOCK *candidate) |
| | 777 | { |
| | 778 | /* Let's face it, Xenos shoot everything but other xenos. */ |
| | 779 | switch (candidate->type) |
| | 780 | { |
| | 781 | case I_BehaviourAlien: |
| | 782 | case I_BehaviourMarine: |
| | 783 | case I_BehaviourMarinePlayer: |
| | 784 | case I_BehaviourAlienPlayer: |
| | 785 | case I_BehaviourPredatorPlayer: |
| | 786 | case I_BehaviourDummy: |
| | 787 | case I_BehaviourQueenAlien: |
| | 788 | case I_BehaviourFaceHugger: |
| | 789 | case I_BehaviourPredator: |
| | 790 | case I_BehaviourNetGhost: |
| | 791 | return 1; |
| | 792 | default: |
| | 793 | return 0; |
| | 794 | } |
| | 795 | } |
| | 796 | |
| | 797 | STRATEGYBLOCK *Xenoborg_GetNewTarget(VECTORCH *xenopos, STRATEGYBLOCK *me) |
| | 798 | { |
| | 799 | int a; |
| | 800 | int neardist = ONE_FIXED; |
| | 801 | STRATEGYBLOCK *nearest = NULL; |
| | 802 | |
| | 803 | MODULE *dmod = ModuleFromPosition(xenopos, PlayerStatus.sbptr->containingModule); |
| | 804 | assert(dmod); |
| | 805 | |
| | 806 | for (a=0; a < NumActiveStBlocks; a++) |
| | 807 | { |
| | 808 | STRATEGYBLOCK *candidate = ActiveStBlockList[a]; |
| | 809 | |
| | 810 | if (Xenoborg_TargetFilter(candidate)) |
| | 811 | { |
| | 812 | VECTORCH offset; |
| | 813 | |
| | 814 | offset.vx = xenopos->vx-candidate->DynPtr->Position.vx; |
| | 815 | offset.vy = xenopos->vy-candidate->DynPtr->Position.vy; |
| | 816 | offset.vz = xenopos->vz-candidate->DynPtr->Position.vz; |
| | 817 | |
| | 818 | if (Approximate3dMagnitude(&offset) < neardist) |
| | 819 | { |
| | 820 | /* Check visibility? */ |
| | 821 | if(!NPC_IsDead(candidate) && NPCCanSeeTarget(me, candidate) && IsModuleVisibleFromModule(dmod, candidate->containingModule)) |
| | 822 | nearest = candidate; |
| | 823 | } |
| | 824 | } |
| | 825 | } |
| | 826 | |
| | 827 | return nearest; |
| | 828 | } |
| | 829 | |
| | 830 | void Xeno_MaintainSounds(STRATEGYBLOCK *sbPtr) |
| | 831 | { |
| | 832 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 833 | |
| | 834 | /* First, the two big system sounds. */ |
| | 835 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 836 | Sound_Update3d(xenoStatusPointer->soundHandle1,&sbPtr->DynPtr->Position); |
| | 837 | |
| | 838 | if (xenoStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) |
| | 839 | Sound_Update3d(xenoStatusPointer->soundHandle2,&sbPtr->DynPtr->Position); |
| | 840 | |
| | 841 | /* Now, all the lesser sounds: */ |
| | 842 | SECTION_DATA *sec = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"head"); |
| | 843 | |
| | 844 | if (sec == NULL) |
| | 845 | { |
| | 846 | /* No sound. */ |
| | 847 | if (xenoStatusPointer->head_whirr != SOUND_NOACTIVEINDEX) |
| | 848 | Sound_Stop(xenoStatusPointer->head_whirr); |
| | 849 | } |
| | 850 | else |
| | 851 | { |
| | 852 | if (!xenoStatusPointer->head_moving) |
| | 853 | { |
| | 854 | /* Stationary. */ |
| | 855 | if (xenoStatusPointer->head_whirr != SOUND_NOACTIVEINDEX) |
| | 856 | { |
| | 857 | Sound_Stop(xenoStatusPointer->head_whirr); |
| | 858 | Sound_Play(SID_ARMEND,"d",&sec->World_Offset); |
| | 859 | } |
| | 860 | } |
| | 861 | else |
| | 862 | { |
| | 863 | /* Moving! */ |
| | 864 | if (xenoStatusPointer->head_whirr == SOUND_NOACTIVEINDEX) |
| | 865 | { |
| | 866 | Sound_Play(SID_ARMSTART,"d",&sec->World_Offset); |
| | 867 | Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->head_whirr); |
| | 868 | } |
| | 869 | else |
| | 870 | { |
| | 871 | Sound_Update3d(xenoStatusPointer->head_whirr,&sec->World_Offset); |
| | 872 | } |
| | 873 | } |
| | 874 | } |
| | 875 | |
| | 876 | /* Left Arm. */ |
| | 877 | sec = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "left bicep"); |
| | 878 | |
| | 879 | if (sec == NULL) |
| | 880 | { |
| | 881 | /* No sound. */ |
| | 882 | if (xenoStatusPointer->left_arm_whirr != SOUND_NOACTIVEINDEX) |
| | 883 | Sound_Stop(xenoStatusPointer->left_arm_whirr); |
| | 884 | } |
| | 885 | else |
| | 886 | { |
| | 887 | if (!xenoStatusPointer->la_moving) |
| | 888 | { |
| | 889 | /* Stationary. */ |
| | 890 | if (xenoStatusPointer->left_arm_whirr != SOUND_NOACTIVEINDEX) |
| | 891 | { |
| | 892 | Sound_Stop(xenoStatusPointer->left_arm_whirr); |
| | 893 | Sound_Play(SID_ARMEND,"d",&sec->World_Offset); |
| | 894 | } |
| | 895 | } |
| | 896 | else |
| | 897 | { |
| | 898 | /* Moving! */ |
| | 899 | if (xenoStatusPointer->left_arm_whirr == SOUND_NOACTIVEINDEX) |
| | 900 | { |
| | 901 | Sound_Play(SID_ARMSTART, "d", &sec->World_Offset); |
| | 902 | Sound_Play(SID_ARMMID, "del", &sec->World_Offset, &xenoStatusPointer->left_arm_whirr); |
| | 903 | } |
| | 904 | else |
| | 905 | { |
| | 906 | Sound_Update3d(xenoStatusPointer->left_arm_whirr, &sec->World_Offset); |
| | 907 | } |
| | 908 | } |
| | 909 | } |
| | 910 | |
| | 911 | /* Right Arm. */ |
| | 912 | sec = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "right bicep"); |
| | 913 | |
| | 914 | if (sec == NULL) |
| | 915 | { |
| | 916 | /* No sound. */ |
| | 917 | if (xenoStatusPointer->right_arm_whirr != SOUND_NOACTIVEINDEX) |
| | 918 | Sound_Stop(xenoStatusPointer->right_arm_whirr); |
| | 919 | } |
| | 920 | else |
| | 921 | { |
| | 922 | if (!xenoStatusPointer->ra_moving) |
| | 923 | { |
| | 924 | /* Stationary. */ |
| | 925 | if (xenoStatusPointer->right_arm_whirr != SOUND_NOACTIVEINDEX) |
| | 926 | { |
| | 927 | Sound_Stop(xenoStatusPointer->right_arm_whirr); |
| | 928 | Sound_Play(SID_ARMEND, "d", &sec->World_Offset); |
| | 929 | } |
| | 930 | } |
| | 931 | else |
| | 932 | { |
| | 933 | /* Moving! */ |
| | 934 | if (xenoStatusPointer->right_arm_whirr == SOUND_NOACTIVEINDEX) |
| | 935 | { |
| | 936 | Sound_Play(SID_ARMSTART, "d", &sec->World_Offset); |
| | 937 | Sound_Play(SID_ARMMID, "del", &sec->World_Offset,&xenoStatusPointer->right_arm_whirr); |
| | 938 | } |
| | 939 | else |
| | 940 | { |
| | 941 | Sound_Update3d(xenoStatusPointer->right_arm_whirr,&sec->World_Offset); |
| | 942 | } |
| | 943 | } |
| | 944 | } |
| | 945 | |
| | 946 | /* Torso Twist. */ |
| | 947 | sec = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "chest"); |
| | 948 | |
| | 949 | if (sec == NULL) |
| | 950 | { |
| | 951 | /* No sound. */ |
| | 952 | if (xenoStatusPointer->torso_whirr!=SOUND_NOACTIVEINDEX) |
| | 953 | Sound_Stop(xenoStatusPointer->torso_whirr); |
| | 954 | } |
| | 955 | else |
| | 956 | { |
| | 957 | if (!xenoStatusPointer->torso_moving) |
| | 958 | { |
| | 959 | /* Stationary. */ |
| | 960 | if (xenoStatusPointer->torso_whirr != SOUND_NOACTIVEINDEX) |
| | 961 | { |
| | 962 | Sound_Stop(xenoStatusPointer->torso_whirr); |
| | 963 | Sound_Play(SID_ARMEND,"d",&sec->World_Offset); |
| | 964 | } |
| | 965 | } |
| | 966 | else |
| | 967 | { |
| | 968 | /* Moving! */ |
| | 969 | if (xenoStatusPointer->torso_whirr == SOUND_NOACTIVEINDEX) |
| | 970 | { |
| | 971 | Sound_Play(SID_ARMSTART,"d",&sec->World_Offset); |
| | 972 | Sound_Play(SID_ARMMID,"del",&sec->World_Offset,&xenoStatusPointer->torso_whirr); |
| | 973 | } |
| | 974 | else |
| | 975 | { |
| | 976 | Sound_Update3d(xenoStatusPointer->torso_whirr,&sec->World_Offset); |
| | 977 | } |
| | 978 | } |
| | 979 | } |
| | 980 | } |
| | 981 | |
| | 982 | void SetXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) |
| | 983 | { |
| | 984 | XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 985 | |
| | 986 | assert(length != 0); |
| | 987 | |
| | 988 | if (tweeningtime <= 0) |
| | 989 | { |
| | 990 | InitHModelSequence(&xenoStatus->HModelController,(int)type,subtype,length); |
| | 991 | } |
| | 992 | else |
| | 993 | { |
| | 994 | InitHModelTweening(&xenoStatus->HModelController, tweeningtime, (int)type,subtype,length, 1); |
| | 995 | //xenoStatus->HModelController.ElevationTweening = 1; |
| | 996 | } |
| | 997 | |
| | 998 | xenoStatus->HModelController.Playing=1; |
| | 999 | /* Might be unset... */ |
| | 1000 | } |
| | 1001 | |
| | 1002 | void EnforceXenoborgShapeAnimSequence_Core(STRATEGYBLOCK *sbPtr, HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime) |
| | 1003 | { |
| | 1004 | XENO_STATUS_BLOCK *xenoStatus = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1005 | |
| | 1006 | if ((xenoStatus->HModelController.Sequence_Type == type) && (xenoStatus->HModelController.Sub_Sequence == subtype)) |
| | 1007 | return; |
| | 1008 | else |
| | 1009 | SetXenoborgShapeAnimSequence_Core(sbPtr,type,subtype,length,tweeningtime); |
| | 1010 | } |
| | 1011 | |
| | 1012 | static void XenoborgHandleMovingAnimation(STRATEGYBLOCK *sbPtr) |
| | 1013 | { |
| | 1014 | VECTORCH offset; |
| | 1015 | int animfactor; |
| | 1016 | |
| | 1017 | assert(sbPtr); |
| | 1018 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1019 | assert(xenoStatusPointer); |
| | 1020 | |
| | 1021 | offset.vx = sbPtr->DynPtr->Position.vx - sbPtr->DynPtr->PrevPosition.vx; |
| | 1022 | offset.vy = sbPtr->DynPtr->Position.vy - sbPtr->DynPtr->PrevPosition.vy; |
| | 1023 | offset.vz = sbPtr->DynPtr->Position.vz - sbPtr->DynPtr->PrevPosition.vz; |
| | 1024 | |
| | 1025 | /* ...compute speed factor... */ |
| | 1026 | int speed = Magnitude(&offset); |
| | 1027 | |
| | 1028 | if (speed < (MUL_FIXED(NormalFrameTime, 50))) |
| | 1029 | { |
| | 1030 | /* Not moving much, are we? Be stationary! */ |
| | 1031 | #if ShowXenoStats |
| | 1032 | printf("Forced stationary animation!\n"); |
| | 1033 | #endif |
| | 1034 | |
| | 1035 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); |
| | 1036 | return; |
| | 1037 | } |
| | 1038 | |
| | 1039 | speed = DIV_FIXED(speed, NormalFrameTime); |
| | 1040 | |
| | 1041 | if (!speed) |
| | 1042 | animfactor = ONE_FIXED; |
| | 1043 | else |
| | 1044 | animfactor = DIV_FIXED(625,speed); // Was 512! Difference to correct for rounding down... |
| | 1045 | |
| | 1046 | assert(animfactor > 0); |
| | 1047 | |
| | 1048 | #if ShowXenoStats |
| | 1049 | printf("Anim Factor %d, Tweening %d\n",animfactor,xenoStatusPointer->HModelController.Tweening); |
| | 1050 | #endif |
| | 1051 | |
| | 1052 | /* Start animation. */ |
| | 1053 | EnforceXenoborgShapeAnimSequence_Core(sbPtr, HMSQT_Xenoborg, XBSS_Walking, XENO_WALKING_ANIM_SPEED, (ONE_FIXED>>2)); |
| | 1054 | |
| | 1055 | if (!xenoStatusPointer->HModelController.Tweening) |
| | 1056 | HModel_SetToolsRelativeSpeed(&xenoStatusPointer->HModelController, animfactor); |
| | 1057 | } |
| | 1058 | |
| | 1059 | static void Xeno_Enter_ActiveWait_State(STRATEGYBLOCK *sbPtr) |
| | 1060 | { |
| | 1061 | assert(sbPtr); |
| | 1062 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1063 | assert(xenoStatusPointer); |
| | 1064 | |
| | 1065 | xenoStatusPointer->stateTimer = 0; |
| | 1066 | xenoStatusPointer->behaviourState = XS_ActiveWait; |
| | 1067 | |
| | 1068 | SetXenoborgShapeAnimSequence_Core(sbPtr, HMSQT_Xenoborg, XBSS_Powered_Up_Standard, ONE_FIXED, (ONE_FIXED>>2)); |
| | 1069 | |
| | 1070 | assert(sbPtr->DynPtr); |
| | 1071 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 1072 | |
| | 1073 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 1074 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 1075 | } |
| | 1076 | |
| | 1077 | static void Xeno_Enter_Following_State(STRATEGYBLOCK *sbPtr) |
| | 1078 | { |
| | 1079 | assert(sbPtr); |
| | 1080 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1081 | assert(xenoStatusPointer); |
| | 1082 | |
| | 1083 | xenoStatusPointer->stateTimer = 0; |
| | 1084 | xenoStatusPointer->behaviourState = XS_Following; |
| | 1085 | InitWaypointManager(&xenoStatusPointer->waypointManager); |
| | 1086 | |
| | 1087 | /* Sequence handled in the behaviour. */ |
| | 1088 | |
| | 1089 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 1090 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 1091 | |
| | 1092 | Sound_Play(SID_LOADMOVE, "del", &sbPtr->DynPtr->Position, &xenoStatusPointer->soundHandle1); |
| | 1093 | } |
| | 1094 | |
| | 1095 | static void Xeno_Enter_Returning_State(STRATEGYBLOCK *sbPtr) |
| | 1096 | { |
| | 1097 | assert(sbPtr); |
| | 1098 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1099 | assert(xenoStatusPointer); |
| | 1100 | |
| | 1101 | xenoStatusPointer->stateTimer = 0; |
| | 1102 | xenoStatusPointer->behaviourState = XS_Returning; |
| | 1103 | InitWaypointManager(&xenoStatusPointer->waypointManager); |
| | 1104 | |
| | 1105 | /* Sequence handled in the behaviour. */ |
| | 1106 | |
| | 1107 | xenoStatusPointer->Target = NULL; |
| | 1108 | /* Forget your target, too. */ |
| | 1109 | |
| | 1110 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 1111 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 1112 | |
| | 1113 | Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); |
| | 1114 | } |
| | 1115 | |
| | 1116 | static void Xeno_TorsoMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) |
| | 1117 | { |
| | 1118 | assert(sbPtr); |
| | 1119 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1120 | assert(xenoStatusPointer); |
| | 1121 | |
| | 1122 | /* Turn the torso to face a certain way. No angley here. */ |
| | 1123 | |
| | 1124 | if (xenoStatusPointer->Torso_Twist < 0) |
| | 1125 | { |
| | 1126 | xenoStatusPointer->Torso_Twist += (NormalFrameTime>>rate); |
| | 1127 | |
| | 1128 | if (xenoStatusPointer->Torso_Twist > (XENO_TORSO_GIMBALL<<4)) |
| | 1129 | { |
| | 1130 | xenoStatusPointer->Torso_Twist = (XENO_TORSO_GIMBALL<<4); |
| | 1131 | } |
| | 1132 | else if (xenoStatusPointer->Torso_Twist > 0) |
| | 1133 | { |
| | 1134 | xenoStatusPointer->Torso_Twist = 0; |
| | 1135 | } |
| | 1136 | else |
| | 1137 | { |
| | 1138 | xenoStatusPointer->torso_moving = 1; |
| | 1139 | } |
| | 1140 | } |
| | 1141 | else if (xenoStatusPointer->Torso_Twist > 0) |
| | 1142 | { |
| | 1143 | xenoStatusPointer->Torso_Twist -= (NormalFrameTime>>rate); |
| | 1144 | |
| | 1145 | if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) |
| | 1146 | { |
| | 1147 | xenoStatusPointer->Torso_Twist = -(XENO_TORSO_GIMBALL<<4); |
| | 1148 | } |
| | 1149 | else if (xenoStatusPointer->Torso_Twist < 0) |
| | 1150 | { |
| | 1151 | xenoStatusPointer->Torso_Twist = 0; |
| | 1152 | } |
| | 1153 | else |
| | 1154 | { |
| | 1155 | xenoStatusPointer->torso_moving = 1; |
| | 1156 | } |
| | 1157 | } |
| | 1158 | |
| | 1159 | if (xenoStatusPointer->torso_twist) |
| | 1160 | xenoStatusPointer->torso_twist->Active = 1; |
| | 1161 | } |
| | 1162 | |
| | 1163 | static void Xeno_LeftArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) |
| | 1164 | { |
| | 1165 | assert(sbPtr); |
| | 1166 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1167 | assert(xenoStatusPointer); |
| | 1168 | |
| | 1169 | /* Centre the Left Arm. */ |
| | 1170 | |
| | 1171 | if (xenoStatusPointer->Left_Arm_Pan < 0) |
| | 1172 | { |
| | 1173 | xenoStatusPointer->Left_Arm_Pan += (NormalFrameTime>>rate); |
| | 1174 | |
| | 1175 | if (xenoStatusPointer->Left_Arm_Pan>(XENO_LEFTARM_ACW_GIMBALL<<4)) |
| | 1176 | { |
| | 1177 | xenoStatusPointer->Left_Arm_Pan = (XENO_LEFTARM_ACW_GIMBALL<<4); |
| | 1178 | } |
| | 1179 | else if (xenoStatusPointer->Left_Arm_Pan > 0) |
| | 1180 | { |
| | 1181 | xenoStatusPointer->Left_Arm_Pan = 0; |
| | 1182 | } |
| | 1183 | else |
| | 1184 | { |
| | 1185 | xenoStatusPointer->la_moving = 1; |
| | 1186 | } |
| | 1187 | } |
| | 1188 | else if (xenoStatusPointer->Left_Arm_Pan > 0) |
| | 1189 | { |
| | 1190 | xenoStatusPointer->Left_Arm_Pan -= (NormalFrameTime>>rate); |
| | 1191 | |
| | 1192 | if (xenoStatusPointer->Left_Arm_Pan < -(XENO_LEFTARM_CW_GIMBALL<<4)) |
| | 1193 | { |
| | 1194 | xenoStatusPointer->Left_Arm_Pan = -(XENO_LEFTARM_CW_GIMBALL<<4); |
| | 1195 | } |
| | 1196 | else if (xenoStatusPointer->Left_Arm_Pan < 0) |
| | 1197 | { |
| | 1198 | xenoStatusPointer->Left_Arm_Pan = 0; |
| | 1199 | } |
| | 1200 | else |
| | 1201 | { |
| | 1202 | xenoStatusPointer->la_moving = 1; |
| | 1203 | } |
| | 1204 | } |
| | 1205 | |
| | 1206 | if (xenoStatusPointer->left_arm_pan) |
| | 1207 | xenoStatusPointer->left_arm_pan->Active = 1; |
| | 1208 | |
| | 1209 | /* Now y. */ |
| | 1210 | |
| | 1211 | if (xenoStatusPointer->Left_Arm_Tilt < 0) |
| | 1212 | { |
| | 1213 | xenoStatusPointer->Left_Arm_Tilt += (NormalFrameTime>>rate); |
| | 1214 | |
| | 1215 | if (xenoStatusPointer->Left_Arm_Tilt > (XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1216 | { |
| | 1217 | xenoStatusPointer->Left_Arm_Tilt = (XENO_ARM_PITCH_GIMBALL<<4); |
| | 1218 | } |
| | 1219 | else if (xenoStatusPointer->Left_Arm_Tilt > 0) |
| | 1220 | { |
| | 1221 | xenoStatusPointer->Left_Arm_Tilt = 0; |
| | 1222 | } |
| | 1223 | else |
| | 1224 | { |
| | 1225 | xenoStatusPointer->la_moving = 1; |
| | 1226 | } |
| | 1227 | } |
| | 1228 | else if (xenoStatusPointer->Left_Arm_Tilt > 0) |
| | 1229 | { |
| | 1230 | xenoStatusPointer->Left_Arm_Tilt -= (NormalFrameTime>>rate); |
| | 1231 | |
| | 1232 | if (xenoStatusPointer->Left_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1233 | { |
| | 1234 | xenoStatusPointer->Left_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 1235 | } |
| | 1236 | else if (xenoStatusPointer->Left_Arm_Tilt < 0) |
| | 1237 | { |
| | 1238 | xenoStatusPointer->Left_Arm_Tilt = 0; |
| | 1239 | } |
| | 1240 | else |
| | 1241 | { |
| | 1242 | xenoStatusPointer->la_moving = 1; |
| | 1243 | } |
| | 1244 | } |
| | 1245 | |
| | 1246 | if (xenoStatusPointer->left_arm_tilt) |
| | 1247 | xenoStatusPointer->left_arm_tilt->Active = 1; |
| | 1248 | } |
| | 1249 | |
| | 1250 | static void Xeno_RightArmMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) |
| | 1251 | { |
| | 1252 | assert(sbPtr); |
| | 1253 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1254 | assert(xenoStatusPointer); |
| | 1255 | |
| | 1256 | /* Centre the Right Arm. */ |
| | 1257 | |
| | 1258 | if (xenoStatusPointer->Right_Arm_Pan < 0) |
| | 1259 | { |
| | 1260 | xenoStatusPointer->Right_Arm_Pan += (NormalFrameTime>>rate); |
| | 1261 | |
| | 1262 | if (xenoStatusPointer->Right_Arm_Pan > (XENO_RIGHTARM_ACW_GIMBALL<<4)) |
| | 1263 | { |
| | 1264 | xenoStatusPointer->Right_Arm_Pan = (XENO_RIGHTARM_ACW_GIMBALL<<4); |
| | 1265 | } |
| | 1266 | else if (xenoStatusPointer->Right_Arm_Pan > 0) |
| | 1267 | { |
| | 1268 | xenoStatusPointer->Right_Arm_Pan = 0; |
| | 1269 | } |
| | 1270 | else |
| | 1271 | { |
| | 1272 | xenoStatusPointer->ra_moving = 1; |
| | 1273 | } |
| | 1274 | } |
| | 1275 | else if (xenoStatusPointer->Right_Arm_Pan > 0) |
| | 1276 | { |
| | 1277 | xenoStatusPointer->Right_Arm_Pan -= (NormalFrameTime>>rate); |
| | 1278 | |
| | 1279 | if (xenoStatusPointer->Right_Arm_Pan < -(XENO_RIGHTARM_CW_GIMBALL<<4)) |
| | 1280 | { |
| | 1281 | xenoStatusPointer->Right_Arm_Pan = -(XENO_RIGHTARM_CW_GIMBALL<<4); |
| | 1282 | } |
| | 1283 | else if (xenoStatusPointer->Right_Arm_Pan < 0) |
| | 1284 | { |
| | 1285 | xenoStatusPointer->Right_Arm_Pan = 0; |
| | 1286 | } |
| | 1287 | else |
| | 1288 | { |
| | 1289 | xenoStatusPointer->ra_moving = 1; |
| | 1290 | } |
| | 1291 | } |
| | 1292 | |
| | 1293 | if (xenoStatusPointer->right_arm_pan) |
| | 1294 | xenoStatusPointer->right_arm_pan->Active = 1; |
| | 1295 | |
| | 1296 | /* Now y. */ |
| | 1297 | |
| | 1298 | if (xenoStatusPointer->Right_Arm_Tilt < 0) |
| | 1299 | { |
| | 1300 | xenoStatusPointer->Right_Arm_Tilt += (NormalFrameTime>>rate); |
| | 1301 | |
| | 1302 | if (xenoStatusPointer->Right_Arm_Tilt > (XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1303 | { |
| | 1304 | xenoStatusPointer->Right_Arm_Tilt = (XENO_ARM_PITCH_GIMBALL<<4); |
| | 1305 | } |
| | 1306 | else if (xenoStatusPointer->Right_Arm_Tilt > 0) |
| | 1307 | { |
| | 1308 | xenoStatusPointer->Right_Arm_Tilt = 0; |
| | 1309 | } |
| | 1310 | else |
| | 1311 | { |
| | 1312 | xenoStatusPointer->ra_moving = 1; |
| | 1313 | } |
| | 1314 | } |
| | 1315 | else if (xenoStatusPointer->Right_Arm_Tilt > 0) |
| | 1316 | { |
| | 1317 | xenoStatusPointer->Right_Arm_Tilt -= (NormalFrameTime>>rate); |
| | 1318 | |
| | 1319 | if (xenoStatusPointer->Right_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1320 | { |
| | 1321 | xenoStatusPointer->Right_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 1322 | } |
| | 1323 | else if (xenoStatusPointer->Right_Arm_Tilt < 0) |
| | 1324 | { |
| | 1325 | xenoStatusPointer->Right_Arm_Tilt = 0; |
| | 1326 | } |
| | 1327 | else |
| | 1328 | { |
| | 1329 | xenoStatusPointer->ra_moving = 1; |
| | 1330 | } |
| | 1331 | } |
| | 1332 | |
| | 1333 | if (xenoStatusPointer->right_arm_tilt) |
| | 1334 | xenoStatusPointer->right_arm_tilt->Active = 1; |
| | 1335 | |
| | 1336 | } |
| | 1337 | |
| | 1338 | static void Xeno_HeadMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate) |
| | 1339 | { |
| | 1340 | assert(sbPtr); |
| | 1341 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1342 | assert(xenoStatusPointer); |
| | 1343 | |
| | 1344 | /* Let's wave the head around. */ |
| | 1345 | if (xenoStatusPointer->headpandir) |
| | 1346 | { |
| | 1347 | xenoStatusPointer->Head_Pan += (NormalFrameTime>>rate); |
| | 1348 | |
| | 1349 | if (xenoStatusPointer->Head_Pan>(XENO_HEADPAN_GIMBALL<<4)) |
| | 1350 | { |
| | 1351 | xenoStatusPointer->Head_Pan = (XENO_HEADPAN_GIMBALL<<4); |
| | 1352 | xenoStatusPointer->headpandir = 0; |
| | 1353 | } |
| | 1354 | else |
| | 1355 | { |
| | 1356 | xenoStatusPointer->head_moving = 1; |
| | 1357 | } |
| | 1358 | } |
| | 1359 | else |
| | 1360 | { |
| | 1361 | xenoStatusPointer->Head_Pan -= (NormalFrameTime>>rate); |
| | 1362 | |
| | 1363 | if (xenoStatusPointer->Head_Pan < -(XENO_HEADPAN_GIMBALL<<4)) |
| | 1364 | { |
| | 1365 | xenoStatusPointer->Head_Pan = -(XENO_HEADPAN_GIMBALL<<4); |
| | 1366 | xenoStatusPointer->headpandir = 1; |
| | 1367 | } |
| | 1368 | else |
| | 1369 | { |
| | 1370 | xenoStatusPointer->head_moving = 1; |
| | 1371 | } |
| | 1372 | } |
| | 1373 | |
| | 1374 | if (xenoStatusPointer->head_pan) |
| | 1375 | xenoStatusPointer->head_pan->Active = 1; |
| | 1376 | } |
| | 1377 | |
| | 1378 | static void Xeno_HeadMovement_ScanUpDown(STRATEGYBLOCK *sbPtr,int rate) |
| | 1379 | { |
| | 1380 | assert(sbPtr); |
| | 1381 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1382 | assert(xenoStatusPointer); |
| | 1383 | |
| | 1384 | /* Let's wave the head around. */ |
| | 1385 | if (xenoStatusPointer->headtiltdir) |
| | 1386 | { |
| | 1387 | xenoStatusPointer->Head_Tilt += (NormalFrameTime>>rate); |
| | 1388 | |
| | 1389 | if (xenoStatusPointer->Head_Tilt > (XENO_HEADTILT_GIMBALL<<4)) |
| | 1390 | { |
| | 1391 | xenoStatusPointer->Head_Tilt = (XENO_HEADTILT_GIMBALL<<4); |
| | 1392 | xenoStatusPointer->headtiltdir = 0; |
| | 1393 | } |
| | 1394 | else |
| | 1395 | { |
| | 1396 | xenoStatusPointer->head_moving = 1; |
| | 1397 | } |
| | 1398 | } |
| | 1399 | else |
| | 1400 | { |
| | 1401 | xenoStatusPointer->Head_Tilt -= (NormalFrameTime>>rate); |
| | 1402 | |
| | 1403 | if (xenoStatusPointer->Head_Tilt<-(XENO_HEADTILT_GIMBALL<<4)) |
| | 1404 | { |
| | 1405 | xenoStatusPointer->Head_Tilt = -(XENO_HEADTILT_GIMBALL<<4); |
| | 1406 | xenoStatusPointer->headtiltdir = 1; |
| | 1407 | } |
| | 1408 | else |
| | 1409 | { |
| | 1410 | xenoStatusPointer->head_moving = 1; |
| | 1411 | } |
| | 1412 | } |
| | 1413 | |
| | 1414 | if (xenoStatusPointer->head_tilt) |
| | 1415 | xenoStatusPointer->head_tilt->Active = 1; |
| | 1416 | } |
| | 1417 | |
| | 1418 | static void Xenoborg_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint) |
| | 1419 | { |
| | 1420 | VECTORCH targetPos; |
| | 1421 | |
| | 1422 | assert(sbPtr); |
| | 1423 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1424 | assert(xenoStatusPointer); |
| | 1425 | |
| | 1426 | /* First, extract relative angle. */ |
| | 1427 | |
| | 1428 | MATRIXCH WtoL = sbPtr->DynPtr->OrientMat; |
| | 1429 | TransposeMatrixCH(&WtoL); |
| | 1430 | |
| | 1431 | targetPos = xenoStatusPointer->targetTrackPos; |
| | 1432 | targetPos.vx -= pivotPoint->vx; |
| | 1433 | targetPos.vy -= pivotPoint->vy; |
| | 1434 | targetPos.vz -= pivotPoint->vz; |
| | 1435 | |
| | 1436 | RotateVector(&targetPos,&WtoL); |
| | 1437 | |
| | 1438 | /* Now... */ |
| | 1439 | { |
| | 1440 | int offsetx = targetPos.vx; |
| | 1441 | int offsety = targetPos.vz; |
| | 1442 | int offseta = -targetPos.vy; |
| | 1443 | |
| | 1444 | while( (offsetx > (ONE_FIXED>>2)) |
| | 1445 | ||(offsety > (ONE_FIXED>>2)) |
| | 1446 | ||(offseta > (ONE_FIXED>>2)) |
| | 1447 | ||(offsetx < -(ONE_FIXED>>2)) |
| | 1448 | ||(offsety < -(ONE_FIXED>>2)) |
| | 1449 | ||(offseta < -(ONE_FIXED>>2))) |
| | 1450 | { |
| | 1451 | offsetx>>=1; |
| | 1452 | offsety>>=1; |
| | 1453 | offseta>>=1; |
| | 1454 | } |
| | 1455 | |
| | 1456 | int offsetz = SqRoot32((offsetx*offsetx)+(offsety*offsety)); |
| | 1457 | |
| | 1458 | if (angley) |
| | 1459 | { |
| | 1460 | *angley = ArcTan(offseta, offsetz); |
| | 1461 | |
| | 1462 | if (*angley >= 3072) |
| | 1463 | *angley -= 4096; |
| | 1464 | |
| | 1465 | if (*angley >= 2048) |
| | 1466 | *angley = *angley - 3072; |
| | 1467 | |
| | 1468 | if (*angley > 1024) |
| | 1469 | *angley = 2048 - *angley; |
| | 1470 | } |
| | 1471 | |
| | 1472 | if (anglex) |
| | 1473 | { |
| | 1474 | *anglex = ArcTan(offsetx, offsety); |
| | 1475 | |
| | 1476 | if (*anglex >= 3072) |
| | 1477 | *anglex -= 4096; |
| | 1478 | |
| | 1479 | if (*anglex >= 2048) |
| | 1480 | *anglex = *anglex - 4096; |
| | 1481 | } |
| | 1482 | } |
| | 1483 | } |
| | 1484 | |
| | 1485 | static void Xeno_TorsoMovement_TrackToAngle(STRATEGYBLOCK *sbPtr,int rate,int in_anglex) |
| | 1486 | { |
| | 1487 | assert(sbPtr); |
| | 1488 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1489 | assert(xenoStatusPointer); |
| | 1490 | |
| | 1491 | /* Turn the torso to face a certain way. No angley here. */ |
| | 1492 | |
| | 1493 | int anglex = in_anglex; |
| | 1494 | |
| | 1495 | if (anglex >= 3072) |
| | 1496 | anglex -= 4096; |
| | 1497 | |
| | 1498 | if (anglex >= 2048) |
| | 1499 | anglex = anglex - 3072; |
| | 1500 | |
| | 1501 | if (anglex > 1024) |
| | 1502 | anglex = 2048 - anglex; |
| | 1503 | |
| | 1504 | anglex <<= 4; |
| | 1505 | |
| | 1506 | if (xenoStatusPointer->Torso_Twist < anglex) |
| | 1507 | { |
| | 1508 | xenoStatusPointer->Torso_Twist += (NormalFrameTime>>rate); |
| | 1509 | |
| | 1510 | if (xenoStatusPointer->Torso_Twist > (XENO_TORSO_GIMBALL<<4)) |
| | 1511 | { |
| | 1512 | xenoStatusPointer->Torso_Twist = (XENO_TORSO_GIMBALL<<4); |
| | 1513 | } |
| | 1514 | else if (xenoStatusPointer->Torso_Twist > anglex) |
| | 1515 | { |
| | 1516 | xenoStatusPointer->Torso_Twist = anglex; |
| | 1517 | } |
| | 1518 | else |
| | 1519 | { |
| | 1520 | xenoStatusPointer->torso_moving = 1; |
| | 1521 | } |
| | 1522 | } |
| | 1523 | else if (xenoStatusPointer->Torso_Twist>anglex) |
| | 1524 | { |
| | 1525 | xenoStatusPointer->Torso_Twist -= (NormalFrameTime>>rate); |
| | 1526 | |
| | 1527 | if (xenoStatusPointer->Torso_Twist < -(XENO_TORSO_GIMBALL<<4)) |
| | 1528 | { |
| | 1529 | xenoStatusPointer->Torso_Twist = -(XENO_TORSO_GIMBALL<<4); |
| | 1530 | } |
| | 1531 | else if (xenoStatusPointer->Torso_Twist < anglex) |
| | 1532 | { |
| | 1533 | xenoStatusPointer->Torso_Twist = anglex; |
| | 1534 | } |
| | 1535 | else |
| | 1536 | { |
| | 1537 | xenoStatusPointer->torso_moving = 1; |
| | 1538 | } |
| | 1539 | } |
| | 1540 | |
| | 1541 | if (xenoStatusPointer->torso_twist) |
| | 1542 | xenoStatusPointer->torso_twist->Active = 1; |
| | 1543 | } |
| | 1544 | |
| | 1545 | static int Xeno_HeadMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) |
| | 1546 | { |
| | 1547 | assert(sbPtr); |
| | 1548 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1549 | assert(xenoStatusPointer); |
| | 1550 | |
| | 1551 | /* Turn the head to face a certain way. */ |
| | 1552 | |
| | 1553 | int real_anglex = in_anglex - (xenoStatusPointer->Torso_Twist>>4); |
| | 1554 | int angley = in_angley; |
| | 1555 | int online=0; |
| | 1556 | |
| | 1557 | /* Now fix multiples. */ |
| | 1558 | while ((real_anglex > 4095) || (real_anglex < 0)) |
| | 1559 | { |
| | 1560 | if (real_anglex < 0) |
| | 1561 | { |
| | 1562 | real_anglex += 4096; |
| | 1563 | } |
| | 1564 | else if (real_anglex > 4095) |
| | 1565 | { |
| | 1566 | real_anglex-=4096; |
| | 1567 | } |
| | 1568 | } |
| | 1569 | |
| | 1570 | if (real_anglex >= 3072) |
| | 1571 | real_anglex -= 4096; |
| | 1572 | |
| | 1573 | if (real_anglex >= 2048) |
| | 1574 | real_anglex = real_anglex-3072; |
| | 1575 | |
| | 1576 | if (real_anglex > 1024) |
| | 1577 | real_anglex = 2048-real_anglex; |
| | 1578 | |
| | 1579 | if (angley >= 3072) |
| | 1580 | angley -= 4096; |
| | 1581 | |
| | 1582 | if (angley >= 2048) |
| | 1583 | angley = angley-3072; |
| | 1584 | |
| | 1585 | if (angley > 1024) |
| | 1586 | angley = 2048-angley; |
| | 1587 | |
| | 1588 | assert((real_anglex<=1024)&&(real_anglex>=-1024)); |
| | 1589 | assert((angley<=1024)&&(angley>=-1024)); |
| | 1590 | |
| | 1591 | #if ShowXenoStats |
| | 1592 | printf("Target head angles: %d %d\n",real_anglex,angley); |
| | 1593 | #endif |
| | 1594 | |
| | 1595 | real_anglex <<= 4; |
| | 1596 | angley <<= 4; |
| | 1597 | |
| | 1598 | if (xenoStatusPointer->Head_Pan<real_anglex) |
| | 1599 | { |
| | 1600 | xenoStatusPointer->Head_Pan += (NormalFrameTime >> rate); |
| | 1601 | |
| | 1602 | if (xenoStatusPointer->Head_Pan > (XENO_HEADPAN_GIMBALL<<4)) |
| | 1603 | { |
| | 1604 | xenoStatusPointer->Head_Pan = (XENO_HEADPAN_GIMBALL<<4); |
| | 1605 | } |
| | 1606 | else if (xenoStatusPointer->Head_Pan > real_anglex) |
| | 1607 | { |
| | 1608 | xenoStatusPointer->Head_Pan = real_anglex; |
| | 1609 | online++; |
| | 1610 | } |
| | 1611 | } |
| | 1612 | else if (xenoStatusPointer->Head_Pan > real_anglex) |
| | 1613 | { |
| | 1614 | xenoStatusPointer->Head_Pan -= (NormalFrameTime>>rate); |
| | 1615 | |
| | 1616 | if (xenoStatusPointer->Head_Pan < -(XENO_HEADPAN_GIMBALL<<4)) |
| | 1617 | { |
| | 1618 | xenoStatusPointer->Head_Pan = -(XENO_HEADPAN_GIMBALL<<4); |
| | 1619 | } |
| | 1620 | else if (xenoStatusPointer->Head_Pan < real_anglex) |
| | 1621 | { |
| | 1622 | xenoStatusPointer->Head_Pan = real_anglex; |
| | 1623 | online++; |
| | 1624 | } |
| | 1625 | } |
| | 1626 | else |
| | 1627 | { |
| | 1628 | online++; |
| | 1629 | } |
| | 1630 | |
| | 1631 | if (xenoStatusPointer->head_pan) |
| | 1632 | xenoStatusPointer->head_pan->Active = 1; |
| | 1633 | |
| | 1634 | /* Now y. */ |
| | 1635 | angley = -angley; |
| | 1636 | /* Oops. */ |
| | 1637 | |
| | 1638 | if (xenoStatusPointer->Head_Tilt < angley) |
| | 1639 | { |
| | 1640 | xenoStatusPointer->Head_Tilt += (NormalFrameTime>>rate); |
| | 1641 | |
| | 1642 | if (xenoStatusPointer->Head_Tilt > (XENO_HEADTILT_GIMBALL<<4)) |
| | 1643 | { |
| | 1644 | xenoStatusPointer->Head_Tilt = (XENO_HEADTILT_GIMBALL<<4); |
| | 1645 | } |
| | 1646 | else if (xenoStatusPointer->Head_Tilt > angley) |
| | 1647 | { |
| | 1648 | xenoStatusPointer->Head_Tilt = angley; |
| | 1649 | online++; |
| | 1650 | } |
| | 1651 | } |
| | 1652 | else if (xenoStatusPointer->Head_Tilt > angley) |
| | 1653 | { |
| | 1654 | xenoStatusPointer->Head_Tilt -= (NormalFrameTime>>rate); |
| | 1655 | |
| | 1656 | if (xenoStatusPointer->Head_Tilt < -(XENO_HEADTILT_GIMBALL<<4)) |
| | 1657 | { |
| | 1658 | xenoStatusPointer->Head_Tilt = -(XENO_HEADTILT_GIMBALL<<4); |
| | 1659 | } |
| | 1660 | else if (xenoStatusPointer->Head_Tilt < angley) |
| | 1661 | { |
| | 1662 | xenoStatusPointer->Head_Tilt = angley; |
| | 1663 | online++; |
| | 1664 | } |
| | 1665 | } |
| | 1666 | else |
| | 1667 | { |
| | 1668 | online++; |
| | 1669 | } |
| | 1670 | |
| | 1671 | if (xenoStatusPointer->head_tilt) |
| | 1672 | xenoStatusPointer->head_tilt->Active = 1; |
| | 1673 | |
| | 1674 | if (online <= 1) |
| | 1675 | xenoStatusPointer->head_moving = 1; /* Still moving! */ |
| | 1676 | |
| | 1677 | if (xenoStatusPointer->HeadLaserOnTarget) |
| | 1678 | online = 2; |
| | 1679 | |
| | 1680 | return (online > 1); |
| | 1681 | } |
| | 1682 | |
| | 1683 | static int Xeno_LeftArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) |
| | 1684 | { |
| | 1685 | assert(sbPtr); |
| | 1686 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1687 | assert(xenoStatusPointer); |
| | 1688 | |
| | 1689 | /* Aim the Left Arm at a point. */ |
| | 1690 | |
| | 1691 | int real_anglex = in_anglex - (xenoStatusPointer->Torso_Twist>>4); |
| | 1692 | int angley = in_angley; |
| | 1693 | int online = 0; |
| | 1694 | |
| | 1695 | /* Now fix multiples. */ |
| | 1696 | while ((real_anglex > 4095) || (real_anglex < 0)) |
| | 1697 | { |
| | 1698 | if (real_anglex < 0) |
| | 1699 | { |
| | 1700 | real_anglex += 4096; |
| | 1701 | } |
| | 1702 | else if (real_anglex > 4095) |
| | 1703 | { |
| | 1704 | real_anglex -= 4096; |
| | 1705 | } |
| | 1706 | } |
| | 1707 | |
| | 1708 | if (real_anglex >= 3072) |
| | 1709 | real_anglex -= 4096; |
| | 1710 | |
| | 1711 | if (real_anglex >= 2048) |
| | 1712 | real_anglex = real_anglex - 3072; |
| | 1713 | |
| | 1714 | if (real_anglex > 1024) |
| | 1715 | real_anglex = 2048 - real_anglex; |
| | 1716 | |
| | 1717 | if (angley >= 3072) |
| | 1718 | angley -= 4096; |
| | 1719 | |
| | 1720 | if (angley >= 2048) |
| | 1721 | angley = angley - 3072; |
| | 1722 | |
| | 1723 | if (angley > 1024) |
| | 1724 | angley = 2048 - angley; |
| | 1725 | |
| | 1726 | real_anglex <<= 4; |
| | 1727 | angley <<= 4; |
| | 1728 | |
| | 1729 | if (xenoStatusPointer->Left_Arm_Pan < real_anglex) |
| | 1730 | { |
| | 1731 | xenoStatusPointer->Left_Arm_Pan += (NormalFrameTime>>rate); |
| | 1732 | |
| | 1733 | if (xenoStatusPointer->Left_Arm_Pan > (XENO_LEFTARM_ACW_GIMBALL<<4)) |
| | 1734 | { |
| | 1735 | xenoStatusPointer->Left_Arm_Pan = (XENO_LEFTARM_ACW_GIMBALL<<4); |
| | 1736 | } |
| | 1737 | else if (xenoStatusPointer->Left_Arm_Pan > real_anglex) |
| | 1738 | { |
| | 1739 | xenoStatusPointer->Left_Arm_Pan = real_anglex; |
| | 1740 | online++; |
| | 1741 | } |
| | 1742 | } |
| | 1743 | else if (xenoStatusPointer->Left_Arm_Pan>real_anglex) |
| | 1744 | { |
| | 1745 | xenoStatusPointer->Left_Arm_Pan -= (NormalFrameTime>>rate); |
| | 1746 | |
| | 1747 | if (xenoStatusPointer->Left_Arm_Pan < -(XENO_LEFTARM_CW_GIMBALL<<4)) |
| | 1748 | { |
| | 1749 | xenoStatusPointer->Left_Arm_Pan = -(XENO_LEFTARM_CW_GIMBALL<<4); |
| | 1750 | } |
| | 1751 | else if (xenoStatusPointer->Left_Arm_Pan < real_anglex) |
| | 1752 | { |
| | 1753 | xenoStatusPointer->Left_Arm_Pan=real_anglex; |
| | 1754 | online++; |
| | 1755 | } |
| | 1756 | } |
| | 1757 | else |
| | 1758 | { |
| | 1759 | online++; |
| | 1760 | } |
| | 1761 | |
| | 1762 | if (xenoStatusPointer->left_arm_pan) |
| | 1763 | xenoStatusPointer->left_arm_pan->Active = 1; |
| | 1764 | |
| | 1765 | /* Now y. */ |
| | 1766 | angley = -angley; |
| | 1767 | /* Oops. */ |
| | 1768 | |
| | 1769 | if (xenoStatusPointer->Left_Arm_Tilt < angley) |
| | 1770 | { |
| | 1771 | xenoStatusPointer->Left_Arm_Tilt += (NormalFrameTime>>rate); |
| | 1772 | |
| | 1773 | if (xenoStatusPointer->Left_Arm_Tilt > (XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1774 | { |
| | 1775 | xenoStatusPointer->Left_Arm_Tilt = (XENO_ARM_PITCH_GIMBALL<<4); |
| | 1776 | } |
| | 1777 | else if (xenoStatusPointer->Left_Arm_Tilt > angley) |
| | 1778 | { |
| | 1779 | xenoStatusPointer->Left_Arm_Tilt = angley; |
| | 1780 | online++; |
| | 1781 | } |
| | 1782 | } |
| | 1783 | else if (xenoStatusPointer->Left_Arm_Tilt > angley) |
| | 1784 | { |
| | 1785 | xenoStatusPointer->Left_Arm_Tilt -= (NormalFrameTime>>rate); |
| | 1786 | |
| | 1787 | if (xenoStatusPointer->Left_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1788 | { |
| | 1789 | xenoStatusPointer->Left_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 1790 | } |
| | 1791 | else if (xenoStatusPointer->Left_Arm_Tilt < angley) |
| | 1792 | { |
| | 1793 | xenoStatusPointer->Left_Arm_Tilt = angley; |
| | 1794 | online++; |
| | 1795 | } |
| | 1796 | } |
| | 1797 | else |
| | 1798 | { |
| | 1799 | online++; |
| | 1800 | } |
| | 1801 | |
| | 1802 | if (xenoStatusPointer->left_arm_tilt) |
| | 1803 | xenoStatusPointer->left_arm_tilt->Active = 1; |
| | 1804 | |
| | 1805 | if (online <= 1) |
| | 1806 | xenoStatusPointer->la_moving = 1; /* Still going! */ |
| | 1807 | |
| | 1808 | if (xenoStatusPointer->HeadLaserOnTarget) |
| | 1809 | xenoStatusPointer->UseLALaser = 1; |
| | 1810 | |
| | 1811 | if (xenoStatusPointer->LALaserOnTarget) |
| | 1812 | online = 2; |
| | 1813 | |
| | 1814 | if (online > 1) |
| | 1815 | { |
| | 1816 | if (xenoStatusPointer->Target) |
| | 1817 | xenoStatusPointer->FiringLeft = 1; /* What the heck! */ |
| | 1818 | return 1; |
| | 1819 | } |
| | 1820 | else |
| | 1821 | { |
| | 1822 | return 0; |
| | 1823 | } |
| | 1824 | } |
| | 1825 | |
| | 1826 | static int Xeno_RightArmMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) |
| | 1827 | { |
| | 1828 | assert(sbPtr); |
| | 1829 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1830 | assert(xenoStatusPointer); |
| | 1831 | |
| | 1832 | /* Aim the Right Arm at a point. */ |
| | 1833 | |
| | 1834 | int real_anglex = in_anglex - (xenoStatusPointer->Torso_Twist >> 4) + RATweak; |
| | 1835 | int angley = in_angley; |
| | 1836 | int online = 0; |
| | 1837 | |
| | 1838 | /* Now fix multiples. */ |
| | 1839 | while ((real_anglex > 4095) || (real_anglex < 0)) |
| | 1840 | { |
| | 1841 | if (real_anglex < 0) |
| | 1842 | { |
| | 1843 | real_anglex += 4096; |
| | 1844 | } |
| | 1845 | else if (real_anglex > 4095) |
| | 1846 | { |
| | 1847 | real_anglex -= 4096; |
| | 1848 | } |
| | 1849 | } |
| | 1850 | |
| | 1851 | if (real_anglex >= 3072) |
| | 1852 | real_anglex -= 4096; |
| | 1853 | |
| | 1854 | if (real_anglex >= 2048) |
| | 1855 | real_anglex = real_anglex - 3072; |
| | 1856 | |
| | 1857 | if (real_anglex > 1024) |
| | 1858 | real_anglex = 2048 - real_anglex; |
| | 1859 | |
| | 1860 | if (angley >= 3072) |
| | 1861 | angley -= 4096; |
| | 1862 | |
| | 1863 | if (angley >= 2048) |
| | 1864 | angley = angley-3072; |
| | 1865 | |
| | 1866 | if (angley > 1024) |
| | 1867 | angley = 2048-angley; |
| | 1868 | |
| | 1869 | real_anglex <<= 4; |
| | 1870 | angley <<= 4; |
| | 1871 | |
| | 1872 | if (xenoStatusPointer->Right_Arm_Pan < real_anglex) |
| | 1873 | { |
| | 1874 | xenoStatusPointer->Right_Arm_Pan += (NormalFrameTime >> rate); |
| | 1875 | |
| | 1876 | if (xenoStatusPointer->Right_Arm_Pan > (XENO_RIGHTARM_ACW_GIMBALL << 4)) |
| | 1877 | { |
| | 1878 | xenoStatusPointer->Right_Arm_Pan = (XENO_RIGHTARM_ACW_GIMBALL << 4); |
| | 1879 | } |
| | 1880 | else if (xenoStatusPointer->Right_Arm_Pan > real_anglex) |
| | 1881 | { |
| | 1882 | xenoStatusPointer->Right_Arm_Pan = real_anglex; |
| | 1883 | online++; |
| | 1884 | } |
| | 1885 | } |
| | 1886 | else if (xenoStatusPointer->Right_Arm_Pan>real_anglex) |
| | 1887 | { |
| | 1888 | xenoStatusPointer->Right_Arm_Pan -= (NormalFrameTime>>rate); |
| | 1889 | |
| | 1890 | if (xenoStatusPointer->Right_Arm_Pan < -(XENO_RIGHTARM_CW_GIMBALL<<4)) |
| | 1891 | { |
| | 1892 | xenoStatusPointer->Right_Arm_Pan = -(XENO_RIGHTARM_CW_GIMBALL<<4); |
| | 1893 | } |
| | 1894 | else if (xenoStatusPointer->Right_Arm_Pan < real_anglex) |
| | 1895 | { |
| | 1896 | xenoStatusPointer->Right_Arm_Pan = real_anglex; |
| | 1897 | online++; |
| | 1898 | } |
| | 1899 | } |
| | 1900 | else |
| | 1901 | { |
| | 1902 | online++; |
| | 1903 | } |
| | 1904 | |
| | 1905 | if (xenoStatusPointer->right_arm_pan) |
| | 1906 | xenoStatusPointer->right_arm_pan->Active = 1; |
| | 1907 | |
| | 1908 | /* Now y. */ |
| | 1909 | angley = -angley; |
| | 1910 | /* Oops. */ |
| | 1911 | |
| | 1912 | if (xenoStatusPointer->Right_Arm_Tilt < angley) |
| | 1913 | { |
| | 1914 | xenoStatusPointer->Right_Arm_Tilt += (NormalFrameTime >> rate); |
| | 1915 | |
| | 1916 | if (xenoStatusPointer->Right_Arm_Tilt > (XENO_ARM_PITCH_GIMBALL << 4)) |
| | 1917 | { |
| | 1918 | xenoStatusPointer->Right_Arm_Tilt = (XENO_ARM_PITCH_GIMBALL << 4); |
| | 1919 | } |
| | 1920 | else if (xenoStatusPointer->Right_Arm_Tilt > angley) |
| | 1921 | { |
| | 1922 | xenoStatusPointer->Right_Arm_Tilt = angley; |
| | 1923 | online++; |
| | 1924 | } |
| | 1925 | } |
| | 1926 | else if (xenoStatusPointer->Right_Arm_Tilt > angley) |
| | 1927 | { |
| | 1928 | xenoStatusPointer->Right_Arm_Tilt -= (NormalFrameTime >> rate); |
| | 1929 | |
| | 1930 | if (xenoStatusPointer->Right_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 1931 | { |
| | 1932 | xenoStatusPointer->Right_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 1933 | } |
| | 1934 | else if (xenoStatusPointer->Right_Arm_Tilt < angley) |
| | 1935 | { |
| | 1936 | xenoStatusPointer->Right_Arm_Tilt = angley; |
| | 1937 | online++; |
| | 1938 | } |
| | 1939 | } |
| | 1940 | else |
| | 1941 | { |
| | 1942 | online++; |
| | 1943 | } |
| | 1944 | |
| | 1945 | if (xenoStatusPointer->right_arm_tilt) |
| | 1946 | xenoStatusPointer->right_arm_tilt->Active = 1; |
| | 1947 | |
| | 1948 | if (online <= 1) |
| | 1949 | xenoStatusPointer->ra_moving = 1; /* Still moving! */ |
| | 1950 | |
| | 1951 | if (xenoStatusPointer->HeadLaserOnTarget) |
| | 1952 | xenoStatusPointer->UseRALaser = 1; |
| | 1953 | |
| | 1954 | if (xenoStatusPointer->RALaserOnTarget) |
| | 1955 | online = 2; |
| | 1956 | |
| | 1957 | if (online > 1) |
| | 1958 | { |
| | 1959 | if (xenoStatusPointer->Target) |
| | 1960 | xenoStatusPointer->FiringRight = 1; /* What the heck! */ |
| | 1961 | |
| | 1962 | return 1; |
| | 1963 | } |
| | 1964 | else |
| | 1965 | { |
| | 1966 | return 0; |
| | 1967 | } |
| | 1968 | } |
| | 1969 | |
| | 1970 | static void Xeno_TurnAndTarget(STRATEGYBLOCK *sbPtr, int *ref_anglex,int *ref_angley) |
| | 1971 | { |
| | 1972 | int anglex,angley; |
| | 1973 | |
| | 1974 | assert(sbPtr); |
| | 1975 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1976 | assert(xenoStatusPointer); |
| | 1977 | |
| | 1978 | { |
| | 1979 | SECTION_DATA *head_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "neck"); |
| | 1980 | assert(head_section); |
| | 1981 | |
| | 1982 | Xenoborg_GetRelativeAngles(sbPtr, &anglex, &angley, &head_section->World_Offset); |
| | 1983 | } |
| | 1984 | |
| | 1985 | *ref_anglex = anglex; |
| | 1986 | *ref_angley = angley; |
| | 1987 | |
| | 1988 | /* Start turning / targeting procedure. */ |
| | 1989 | |
| | 1990 | /* Always torso twist. */ |
| | 1991 | Xeno_TorsoMovement_TrackToAngle(sbPtr,XENO_TORSO_TWIST_RATE,anglex); |
| | 1992 | |
| | 1993 | xenoStatusPointer->headLock = Xeno_HeadMovement_TrackToAngles(sbPtr,XENO_HEAD_LOCK_RATE,anglex,angley); |
| | 1994 | |
| | 1995 | /* Now the arm. */ |
| | 1996 | |
| | 1997 | if (xenoStatusPointer->headLock && ((anglex < XENO_LEFTARM_ACW_GIMBALL) || (anglex > -XENO_LEFTARM_CW_GIMBALL))) |
| | 1998 | { |
| | 1999 | int arm_anglex = 0; |
| | 2000 | int arm_angley = 0; |
| | 2001 | |
| | 2002 | SECTION_DATA *this_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left bicep"); |
| | 2003 | |
| | 2004 | if (this_section) |
| | 2005 | Xenoborg_GetRelativeAngles(sbPtr,&arm_anglex,NULL,&this_section->World_Offset); |
| | 2006 | |
| | 2007 | this_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left forearm"); |
| | 2008 | |
| | 2009 | if (this_section) |
| | 2010 | Xenoborg_GetRelativeAngles(sbPtr,NULL,&arm_angley,&this_section->World_Offset); |
| | 2011 | |
| | 2012 | xenoStatusPointer->leftArmLock = Xeno_LeftArmMovement_TrackToAngles(sbPtr,XENO_ARM_LOCK_RATE,arm_anglex,arm_angley); |
| | 2013 | } |
| | 2014 | |
| | 2015 | if (xenoStatusPointer->headLock && ((anglex < XENO_RIGHTARM_ACW_GIMBALL) || (anglex > -XENO_RIGHTARM_CW_GIMBALL))) |
| | 2016 | { |
| | 2017 | int arm_anglex = 0; |
| | 2018 | int arm_angley = 0; |
| | 2019 | |
| | 2020 | SECTION_DATA *this_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "right bicep"); |
| | 2021 | |
| | 2022 | if (this_section) |
| | 2023 | Xenoborg_GetRelativeAngles(sbPtr,&arm_anglex,NULL,&this_section->World_Offset); |
| | 2024 | |
| | 2025 | this_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right forearm"); |
| | 2026 | |
| | 2027 | if (this_section) |
| | 2028 | Xenoborg_GetRelativeAngles(sbPtr,NULL,&arm_angley,&this_section->World_Offset); |
| | 2029 | |
| | 2030 | xenoStatusPointer->rightArmLock = Xeno_RightArmMovement_TrackToAngles(sbPtr,XENO_ARM_LOCK_RATE,arm_anglex,arm_angley); |
| | 2031 | } |
| | 2032 | |
| | 2033 | xenoStatusPointer->UseHeadLaser = 1; |
| | 2034 | } |
| | 2035 | |
| | 2036 | void Execute_Xeno_Avoidance_Far(STRATEGYBLOCK *sbPtr) |
| | 2037 | { |
| | 2038 | #if FAR_XENO_ACTIVITY |
| | 2039 | int anglex,angley; |
| | 2040 | #endif |
| | 2041 | assert(sbPtr); |
| | 2042 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2043 | assert(xenoStatusPointer); |
| | 2044 | |
| | 2045 | #if ShowXenoStats |
| | 2046 | printf("In Avoidance Far.\n"); |
| | 2047 | #endif |
| | 2048 | |
| | 2049 | XenoborgHandleMovingAnimation(sbPtr); |
| | 2050 | |
| | 2051 | #if FAR_XENO_ACTIVITY |
| | 2052 | if (!xenoStatusPointer->targetSightTest) |
| | 2053 | { |
| | 2054 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 2055 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 2056 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 2057 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 2058 | } |
| | 2059 | else |
| | 2060 | { |
| | 2061 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 2062 | } |
| | 2063 | #endif |
| | 2064 | |
| | 2065 | /* go to an appropriate state */ |
| | 2066 | switch (xenoStatusPointer->lastState) |
| | 2067 | { |
| | 2068 | case XS_Returning: |
| | 2069 | Xeno_Enter_Returning_State(sbPtr); |
| | 2070 | return; |
| | 2071 | case XS_Following: |
| | 2072 | Xeno_Enter_Following_State(sbPtr); |
| | 2073 | return; |
| | 2074 | default: |
| | 2075 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 2076 | } |
| | 2077 | } |
| | 2078 | |
| | 2079 | static void Xenoborg_MaintainLeftGun(STRATEGYBLOCK *sbPtr) |
| | 2080 | { |
| | 2081 | VECTORCH alpha; |
| | 2082 | VECTORCH beta; |
| | 2083 | |
| | 2084 | assert(sbPtr); |
| | 2085 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2086 | assert(xenoStatusPointer); |
| | 2087 | |
| | 2088 | SECTION_DATA *left_dum = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "flash dummy A"); |
| | 2089 | |
| | 2090 | if (xenoStatusPointer->Wounds & section_flag_left_hand) |
| | 2091 | xenoStatusPointer->FiringLeft = 0; |
| | 2092 | |
| | 2093 | if (!xenoStatusPointer->FiringLeft || (left_dum == NULL) || xenoStatusPointer->IAmFar) |
| | 2094 | { |
| | 2095 | /* Not firing, go away. */ |
| | 2096 | xenoStatusPointer->LeftMainBeam.BeamIsOn = 0; |
| | 2097 | return; |
| | 2098 | } |
| | 2099 | |
| | 2100 | /* Okay, must be firing. Did we get anyone? */ |
| | 2101 | |
| | 2102 | int multiple = FIRING_RATE_LEFT * NormalFrameTime; |
| | 2103 | |
| | 2104 | alpha = left_dum->World_Offset; |
| | 2105 | |
| | 2106 | beta.vx = left_dum->SecMat.mat31; |
| | 2107 | beta.vy = left_dum->SecMat.mat32; |
| | 2108 | beta.vz = left_dum->SecMat.mat33; |
| | 2109 | |
| | 2110 | if(FindPolygonInLineOfSight(&beta, &alpha, sbPtr->DisplayBlock)) |
| | 2111 | { |
| | 2112 | #if DEBUG |
| | 2113 | if (LOS_HModel_Section && LOS_ObjectHitPtr->ObStrategyBlock && LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock) |
| | 2114 | { |
| | 2115 | assert(LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock->HModelControlBlock == LOS_HModel_Section->my_controller); |
| | 2116 | } |
| | 2117 | #endif |
| | 2118 | |
| | 2119 | /* this fn needs updating to take amount of damage into account etc. */ |
| | 2120 | HandleWeaponImpact1(&LOS_Point, LOS_ObjectHitPtr->ObStrategyBlock, &beta, multiple, LOS_HModel_Section); |
| | 2121 | xenoStatusPointer->LeftMainBeam.TargetPosition = LOS_Point; |
| | 2122 | xenoStatusPointer->LeftMainBeam.BeamHasHitPlayer = (LOS_ObjectHitPtr == PlayerStatus.DisplayBlock); |
| | 2123 | } |
| | 2124 | else if(0) |
| | 2125 | { |
| | 2126 | /* Cheat for killing far targets? */ |
| | 2127 | if (xenoStatusPointer->Target && (xenoStatusPointer->Target->DisplayBlock == NULL)) |
| | 2128 | HandleWeaponImpact1(&xenoStatusPointer->Target->DynPtr->Position, xenoStatusPointer->Target, &beta, multiple, NULL); |
| | 2129 | |
| | 2130 | /* Must be hitting nothing... */ |
| | 2131 | xenoStatusPointer->LeftMainBeam.TargetPosition = alpha; |
| | 2132 | xenoStatusPointer->LeftMainBeam.TargetPosition.vx += (beta.vx>>3); |
| | 2133 | xenoStatusPointer->LeftMainBeam.TargetPosition.vy += (beta.vy>>3); |
| | 2134 | xenoStatusPointer->LeftMainBeam.TargetPosition.vz += (beta.vz>>3); |
| | 2135 | xenoStatusPointer->LeftMainBeam.BeamHasHitPlayer = 0; |
| | 2136 | } |
| | 2137 | |
| | 2138 | xenoStatusPointer->LeftMainBeam.BeamIsOn = 1; |
| | 2139 | xenoStatusPointer->LeftMainBeam.SourcePosition = left_dum->World_Offset; |
| | 2140 | } |
| | 2141 | |
| | 2142 | static void Xenoborg_MaintainRightGun(STRATEGYBLOCK *sbPtr) |
| | 2143 | { |
| | 2144 | VECTORCH alpha; |
| | 2145 | VECTORCH beta; |
| | 2146 | |
| | 2147 | assert(sbPtr); |
| | 2148 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2149 | assert(xenoStatusPointer); |
| | 2150 | |
| | 2151 | SECTION_DATA *right_dum = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy B"); |
| | 2152 | |
| | 2153 | if (xenoStatusPointer->Wounds & section_flag_right_hand) |
| | 2154 | xenoStatusPointer->FiringRight = 0; |
| | 2155 | |
| | 2156 | if (!xenoStatusPointer->FiringRight || (right_dum == NULL) || xenoStatusPointer->IAmFar) |
| | 2157 | { |
| | 2158 | /* Not firing, go away. */ |
| | 2159 | xenoStatusPointer->RightMainBeam.BeamIsOn = 0; |
| | 2160 | return; |
| | 2161 | } |
| | 2162 | |
| | 2163 | /* Okay, must be firing. Did we get anyone? */ |
| | 2164 | |
| | 2165 | int multiple = FIRING_RATE_RIGHT * NormalFrameTime; |
| | 2166 | |
| | 2167 | alpha = right_dum->World_Offset; |
| | 2168 | |
| | 2169 | beta.vx = right_dum->SecMat.mat31; |
| | 2170 | beta.vy = right_dum->SecMat.mat32; |
| | 2171 | beta.vz = right_dum->SecMat.mat33; |
| | 2172 | |
| | 2173 | if(FindPolygonInLineOfSight(&beta, &alpha, sbPtr->DisplayBlock)) |
| | 2174 | { |
| | 2175 | #if DEBUG |
| | 2176 | if (LOS_HModel_Section && LOS_ObjectHitPtr->ObStrategyBlock && LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock) |
| | 2177 | { |
| | 2178 | assert(LOS_ObjectHitPtr->ObStrategyBlock->DisplayBlock->HModelControlBlock == LOS_HModel_Section->my_controller); |
| | 2179 | } |
| | 2180 | #endif |
| | 2181 | |
| | 2182 | /* this fn needs updating to take amount of damage into account etc. */ |
| | 2183 | HandleWeaponImpact1(&LOS_Point, LOS_ObjectHitPtr->ObStrategyBlock, &beta, multiple, LOS_HModel_Section); |
| | 2184 | xenoStatusPointer->RightMainBeam.TargetPosition = LOS_Point; |
| | 2185 | xenoStatusPointer->RightMainBeam.BeamHasHitPlayer = (LOS_ObjectHitPtr == PlayerStatus.DisplayBlock); |
| | 2186 | } |
| | 2187 | else if(0) |
| | 2188 | { |
| | 2189 | /* Cheat for killing far targets? */ |
| | 2190 | if (xenoStatusPointer->Target && (xenoStatusPointer->Target->DisplayBlock == NULL)) |
| | 2191 | HandleWeaponImpact1(&xenoStatusPointer->Target->DynPtr->Position, xenoStatusPointer->Target, &beta, multiple, NULL); |
| | 2192 | |
| | 2193 | xenoStatusPointer->RightMainBeam.TargetPosition = alpha; |
| | 2194 | xenoStatusPointer->RightMainBeam.TargetPosition.vx += (beta.vx >> 3); |
| | 2195 | xenoStatusPointer->RightMainBeam.TargetPosition.vy += (beta.vy >> 3); |
| | 2196 | xenoStatusPointer->RightMainBeam.TargetPosition.vz += (beta.vz >> 3); |
| | 2197 | xenoStatusPointer->RightMainBeam.BeamHasHitPlayer = 0; |
| | 2198 | } |
| | 2199 | |
| | 2200 | xenoStatusPointer->RightMainBeam.BeamIsOn = 1; |
| | 2201 | xenoStatusPointer->RightMainBeam.SourcePosition = right_dum->World_Offset; |
| | 2202 | } |
| | 2203 | |
| | 2204 | static void Xeno_MaintainLasers(STRATEGYBLOCK *sbPtr) |
| | 2205 | { |
| | 2206 | SECTION_DATA *dum = NULL; |
| | 2207 | VECTORCH alpha; |
| | 2208 | VECTORCH beta; |
| | 2209 | int a,uselaser = 0; |
| | 2210 | |
| | 2211 | assert(sbPtr); |
| | 2212 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2213 | assert(xenoStatusPointer); |
| | 2214 | |
| | 2215 | xenoStatusPointer->HeadLaserOnTarget = 0; |
| | 2216 | xenoStatusPointer->LALaserOnTarget = 0; |
| | 2217 | xenoStatusPointer->RALaserOnTarget = 0; |
| | 2218 | |
| | 2219 | #if (FAR_XENO_ACTIVITY == 0) |
| | 2220 | if (xenoStatusPointer->IAmFar) |
| | 2221 | { |
| | 2222 | xenoStatusPointer->TargetingLaser[0].BeamIsOn = 0; |
| | 2223 | xenoStatusPointer->TargetingLaser[1].BeamIsOn = 0; |
| | 2224 | xenoStatusPointer->TargetingLaser[2].BeamIsOn = 0; |
| | 2225 | return; |
| | 2226 | } |
| | 2227 | #endif |
| | 2228 | |
| | 2229 | for (a=0; a < 3; a++) |
| | 2230 | { |
| | 2231 | xenoStatusPointer->TargetingLaser[a].BeamIsOn = 0; |
| | 2232 | |
| | 2233 | switch (a) |
| | 2234 | { |
| | 2235 | case 0: |
| | 2236 | dum = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummyZ"); |
| | 2237 | |
| | 2238 | uselaser = (NULL == dum) ? 0 : xenoStatusPointer->UseHeadLaser; |
| | 2239 | break; |
| | 2240 | case 1: |
| | 2241 | dum = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy C"); |
| | 2242 | |
| | 2243 | uselaser = (NULL == dum) ? 0 : xenoStatusPointer->UseLALaser; |
| | 2244 | break; |
| | 2245 | case 2: |
| | 2246 | dum = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"flash dummy D"); |
| | 2247 | |
| | 2248 | uselaser = (NULL == dum) ? 0 : xenoStatusPointer->UseRALaser; |
| | 2249 | break; |
| | 2250 | default: |
| | 2251 | assert(0); |
| | 2252 | break; |
| | 2253 | } |
| | 2254 | |
| | 2255 | if (uselaser) |
| | 2256 | { |
| | 2257 | alpha = dum->World_Offset; |
| | 2258 | |
| | 2259 | beta.vx = dum->SecMat.mat31; |
| | 2260 | beta.vy = dum->SecMat.mat32; |
| | 2261 | beta.vz = dum->SecMat.mat33; |
| | 2262 | |
| | 2263 | |
| | 2264 | /* Now deal with LOS_ObjectHitPtr. */ |
| | 2265 | xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer = (LOS_ObjectHitPtr == PlayerStatus.DisplayBlock); |
| | 2266 | xenoStatusPointer->TargetingLaser[a].SourcePosition = alpha; |
| | 2267 | |
| | 2268 | if(FindPolygonInLineOfSight(&beta, &alpha, sbPtr->DisplayBlock)) |
| | 2269 | { |
| | 2270 | xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer = (LOS_ObjectHitPtr == PlayerStatus.DisplayBlock); |
| | 2271 | xenoStatusPointer->TargetingLaser[a].TargetPosition = LOS_Point; |
| | 2272 | |
| | 2273 | if ((NULL != LOS_ObjectHitPtr->ObStrategyBlock) && (LOS_ObjectHitPtr->ObStrategyBlock == xenoStatusPointer->Target)) |
| | 2274 | { |
| | 2275 | switch(a) |
| | 2276 | { |
| | 2277 | case 0: |
| | 2278 | xenoStatusPointer->HeadLaserOnTarget = 1; |
| | 2279 | break; |
| | 2280 | case 1: |
| | 2281 | xenoStatusPointer->LALaserOnTarget = 1; |
| | 2282 | break; |
| | 2283 | case 2: |
| | 2284 | xenoStatusPointer->RALaserOnTarget = 1; |
| | 2285 | break; |
| | 2286 | default: |
| | 2287 | assert(0); |
| | 2288 | } |
| | 2289 | } |
| | 2290 | } |
| | 2291 | else |
| | 2292 | { |
| | 2293 | /* Must be hitting nothing... */ |
| | 2294 | xenoStatusPointer->TargetingLaser[a].BeamHasHitPlayer = 0; |
| | 2295 | xenoStatusPointer->TargetingLaser[a].TargetPosition = alpha; |
| | 2296 | xenoStatusPointer->TargetingLaser[a].TargetPosition.vx += (beta.vx >> 3); |
| | 2297 | xenoStatusPointer->TargetingLaser[a].TargetPosition.vy += (beta.vy >> 3); |
| | 2298 | xenoStatusPointer->TargetingLaser[a].TargetPosition.vz += (beta.vz >> 3); |
| | 2299 | |
| | 2300 | } |
| | 2301 | |
| | 2302 | xenoStatusPointer->TargetingLaser[a].BeamIsOn = 1; |
| | 2303 | } |
| | 2304 | } |
| | 2305 | } |
| | 2306 | |
| | 2307 | static void Xeno_Stomp(STRATEGYBLOCK *sbPtr) |
| | 2308 | { |
| | 2309 | SECTION_DATA *foot = NULL; |
| | 2310 | |
| | 2311 | assert(sbPtr); |
| | 2312 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2313 | assert(xenoStatusPointer); |
| | 2314 | |
| | 2315 | if (xenoStatusPointer->HModelController.keyframe_flags & 4) |
| | 2316 | { |
| | 2317 | foot = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"right foot"); |
| | 2318 | } |
| | 2319 | else if (xenoStatusPointer->HModelController.keyframe_flags & 8) |
| | 2320 | { |
| | 2321 | foot = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"left foot"); |
| | 2322 | } |
| | 2323 | |
| | 2324 | if (foot) |
| | 2325 | Sound_Play(SID_STOMP,"d",&foot->World_Offset); |
| | 2326 | } |
| | 2327 | |
| | 2328 | static void Xenoborg_DeactivateAllDeltas(STRATEGYBLOCK *sbPtr) |
| | 2329 | { |
| | 2330 | assert(sbPtr); |
| | 2331 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2332 | assert(xenoStatusPointer); |
| | 2333 | |
| | 2334 | if (xenoStatusPointer->head_pan) |
| | 2335 | xenoStatusPointer->head_pan->Active = 0; |
| | 2336 | |
| | 2337 | xenoStatusPointer->Head_Pan = 0; |
| | 2338 | |
| | 2339 | if (xenoStatusPointer->head_tilt) |
| | 2340 | xenoStatusPointer->head_tilt->Active = 0; |
| | 2341 | |
| | 2342 | xenoStatusPointer->Head_Tilt = 0; |
| | 2343 | |
| | 2344 | if (xenoStatusPointer->left_arm_pan) |
| | 2345 | xenoStatusPointer->left_arm_pan->Active = 0; |
| | 2346 | |
| | 2347 | xenoStatusPointer->Left_Arm_Pan = 0; |
| | 2348 | |
| | 2349 | if (xenoStatusPointer->left_arm_tilt) |
| | 2350 | xenoStatusPointer->left_arm_tilt->Active = 0; |
| | 2351 | |
| | 2352 | xenoStatusPointer->Left_Arm_Tilt = 0; |
| | 2353 | |
| | 2354 | if (xenoStatusPointer->right_arm_pan) |
| | 2355 | xenoStatusPointer->right_arm_pan->Active = 0; |
| | 2356 | |
| | 2357 | xenoStatusPointer->Right_Arm_Pan = 0; |
| | 2358 | |
| | 2359 | if (xenoStatusPointer->right_arm_tilt) |
| | 2360 | xenoStatusPointer->right_arm_tilt->Active = 0; |
| | 2361 | |
| | 2362 | xenoStatusPointer->Right_Arm_Tilt = 0; |
| | 2363 | |
| | 2364 | if (xenoStatusPointer->torso_twist) |
| | 2365 | xenoStatusPointer->torso_twist->Active = 0; |
| | 2366 | |
| | 2367 | xenoStatusPointer->Torso_Twist = 0; |
| | 2368 | } |
| | 2369 | |
| | 2370 | void Xeno_Enter_PowerDown_State(STRATEGYBLOCK *sbPtr) |
| | 2371 | { |
| | 2372 | assert(sbPtr); |
| | 2373 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2374 | assert(xenoStatusPointer); |
| | 2375 | |
| | 2376 | if (xenoStatusPointer->behaviourState == XS_Inactive) |
| | 2377 | return; /* Ha! */ |
| | 2378 | |
| | 2379 | xenoStatusPointer->Target = NULL; |
| | 2380 | xenoStatusPointer->stateTimer = 0; |
| | 2381 | xenoStatusPointer->behaviourState = XS_Deactivating; |
| | 2382 | |
| | 2383 | SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Down,ONE_FIXED,(ONE_FIXED>>2)); |
| | 2384 | xenoStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 2385 | |
| | 2386 | assert(sbPtr->DynPtr); |
| | 2387 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 2388 | |
| | 2389 | Xenoborg_DeactivateAllDeltas(sbPtr); |
| | 2390 | Xeno_SwitchLED(sbPtr,0); |
| | 2391 | |
| | 2392 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 2393 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 2394 | |
| | 2395 | if (xenoStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) |
| | 2396 | Sound_Stop(xenoStatusPointer->soundHandle2); /* Stop BorgOn. */ |
| | 2397 | |
| | 2398 | Sound_Play(SID_POWERDN,"de",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); |
| | 2399 | } |
| | 2400 | |
| | 2401 | static void Execute_Xeno_Dying(STRATEGYBLOCK *sbPtr) |
| | 2402 | { |
| | 2403 | assert(sbPtr); |
| | 2404 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2405 | assert(xenoStatusPointer); |
| | 2406 | |
| | 2407 | DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock; |
| | 2408 | |
| | 2409 | if (dispPtr) |
| | 2410 | { |
| | 2411 | dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; |
| | 2412 | dispPtr->ObFlags2 = xenoStatusPointer->stateTimer/2; |
| | 2413 | |
| | 2414 | if (dispPtr->ObFlags2 < ONE_FIXED) |
| | 2415 | xenoStatusPointer->HModelController.DisableBleeding=1; |
| | 2416 | } |
| | 2417 | |
| | 2418 | xenoStatusPointer->stateTimer -= NormalFrameTime; |
| | 2419 | } |
| | 2420 | |
| | 2421 | static int XenoActivation_FrustrumReject(VECTORCH *localOffset) |
| | 2422 | { |
| | 2423 | if ( (localOffset->vz < 0) |
| | 2424 | && (localOffset->vz < localOffset->vx) |
| | 2425 | && (localOffset->vz < -localOffset->vx) |
| | 2426 | && (localOffset->vz < localOffset->vy) |
| | 2427 | && (localOffset->vz < -localOffset->vy) ) |
| | 2428 | { |
| | 2429 | /* 90 horizontal, 90 vertical. */ |
| | 2430 | return 1; |
| | 2431 | } |
| | 2432 | else |
| | 2433 | { |
| | 2434 | return 0; |
| | 2435 | } |
| | 2436 | } |
| | 2437 | |
| | 2438 | static int Xeno_Activation_Test(STRATEGYBLOCK *sbPtr) |
| | 2439 | { |
| | 2440 | assert(sbPtr); |
| | 2441 | MATRIXCH WtoL = sbPtr->DynPtr->OrientMat; |
| | 2442 | int a = 0; |
| | 2443 | MODULE *dmod = ModuleFromPosition(&sbPtr->DynPtr->Position, PlayerStatus.sbptr->containingModule); |
| | 2444 | |
| | 2445 | assert(dmod); |
| | 2446 | |
| | 2447 | TransposeMatrixCH(&WtoL); |
| | 2448 | |
| | 2449 | for (; a < NumActiveStBlocks; a++) |
| | 2450 | { |
| | 2451 | STRATEGYBLOCK *candidate = ActiveStBlockList[a]; |
| | 2452 | |
| | 2453 | if (candidate != sbPtr) |
| | 2454 | { |
| | 2455 | if (candidate->DynPtr) |
| | 2456 | { |
| | 2457 | if (Xenoborg_TargetFilter(candidate)) |
| | 2458 | { |
| | 2459 | VECTORCH offset; |
| | 2460 | |
| | 2461 | offset.vx = sbPtr->DynPtr->Position.vx - candidate->DynPtr->Position.vx; |
| | 2462 | offset.vy = sbPtr->DynPtr->Position.vy - candidate->DynPtr->Position.vy; |
| | 2463 | offset.vz = sbPtr->DynPtr->Position.vz - candidate->DynPtr->Position.vz; |
| | 2464 | |
| | 2465 | RotateVector(&offset,&WtoL); |
| | 2466 | |
| | 2467 | if (XenoActivation_FrustrumReject(&offset)) |
| | 2468 | { |
| | 2469 | /* Check visibility? */ |
| | 2470 | if (NPCCanSeeTarget(sbPtr, candidate) && !NPC_IsDead(candidate) &&
IsModuleVisibleFromModule(dmod,candidate->containingModule)) |
| | 2471 | return 1; |
| | 2472 | } |
| | 2473 | } |
| | 2474 | } |
| | 2475 | } |
| | 2476 | } |
| | 2477 | |
| | 2478 | return 0; |
| | 2479 | } |
| | 2480 | |
| | 2481 | static void Xenoborg_ActivateAllDeltas(STRATEGYBLOCK *sbPtr) |
| | 2482 | { |
| | 2483 | assert(sbPtr); |
| | 2484 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2485 | assert(xenoStatusPointer); |
| | 2486 | |
| | 2487 | if (xenoStatusPointer->head_pan) |
| | 2488 | xenoStatusPointer->head_pan->Active = 1; |
| | 2489 | |
| | 2490 | if (xenoStatusPointer->head_tilt) |
| | 2491 | xenoStatusPointer->head_tilt->Active = 1; |
| | 2492 | |
| | 2493 | if (xenoStatusPointer->left_arm_pan) |
| | 2494 | xenoStatusPointer->left_arm_pan->Active = 1; |
| | 2495 | |
| | 2496 | if (xenoStatusPointer->left_arm_tilt) |
| | 2497 | xenoStatusPointer->left_arm_tilt->Active = 1; |
| | 2498 | |
| | 2499 | if (xenoStatusPointer->right_arm_pan) |
| | 2500 | xenoStatusPointer->right_arm_pan->Active = 1; |
| | 2501 | |
| | 2502 | if (xenoStatusPointer->right_arm_tilt) |
| | 2503 | xenoStatusPointer->right_arm_tilt->Active = 1; |
| | 2504 | |
| | 2505 | if (xenoStatusPointer->torso_twist) |
| | 2506 | xenoStatusPointer->torso_twist->Active = 1; |
| | 2507 | } |
| | 2508 | |
| | 2509 | void Xeno_Enter_PowerUp_State(STRATEGYBLOCK *sbPtr) |
| | 2510 | { |
| | 2511 | assert(sbPtr); |
| | 2512 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2513 | assert(xenoStatusPointer); |
| | 2514 | |
| | 2515 | if (xenoStatusPointer->behaviourState != XS_Inactive) |
| | 2516 | return; /* Ha! */ |
| | 2517 | |
| | 2518 | xenoStatusPointer->Target = NULL; |
| | 2519 | xenoStatusPointer->stateTimer = 0; |
| | 2520 | xenoStatusPointer->behaviourState = XS_Activating; |
| | 2521 | |
| | 2522 | assert(xenoStatusPointer->HModelController.Sequence_Type == HMSQT_Xenoborg); |
| | 2523 | assert(xenoStatusPointer->HModelController.Sub_Sequence == XBSS_Powered_Down_Standard); |
| | 2524 | |
| | 2525 | SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Up,(ONE_FIXED*4),(ONE_FIXED>>2)); |
| | 2526 | |
| | 2527 | xenoStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 2528 | |
| | 2529 | Xenoborg_ActivateAllDeltas(sbPtr); |
| | 2530 | Xeno_SwitchLED(sbPtr,1); |
| | 2531 | |
| | 2532 | /* Now play with a sound. */ |
| | 2533 | |
| | 2534 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 2535 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 2536 | |
| | 2537 | if (xenoStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) |
| | 2538 | Sound_Stop(xenoStatusPointer->soundHandle2); /* Well, it shouldn't be! */ |
| | 2539 | |
| | 2540 | Sound_Play(SID_POWERUP,"de",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); |
| | 2541 | } |
| | 2542 | |
| | 2543 | static void Execute_Xeno_Inactive(STRATEGYBLOCK *sbPtr) |
| | 2544 | { |
| | 2545 | assert(sbPtr); |
| | 2546 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2547 | assert(xenoStatusPointer); |
| | 2548 | |
| | 2549 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Xenoborg]; |
| | 2550 | |
| | 2551 | #if ShowXenoStats |
| | 2552 | printf("In Inactive.\n"); |
| | 2553 | #endif |
| | 2554 | |
| | 2555 | if (!sbPtr->DisplayBlock) |
| | 2556 | { |
| | 2557 | /* We're far... do the timer! */ |
| | 2558 | ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); |
| | 2559 | } |
| | 2560 | |
| | 2561 | /* Regenerate a bit? */ |
| | 2562 | |
| | 2563 | if (sbPtr->DamageBlock.Health > 0) |
| | 2564 | { |
| | 2565 | int health_increment = DIV_FIXED((NpcData->StartingStats.Health*NormalFrameTime),XENO_REGEN_TIME); |
| | 2566 | sbPtr->DamageBlock.Health += health_increment; |
| | 2567 | |
| | 2568 | if (sbPtr->DamageBlock.Health > (NpcData->StartingStats.Health << ONE_FIXED_SHIFT)) |
| | 2569 | sbPtr->DamageBlock.Health = (NpcData->StartingStats.Health << ONE_FIXED_SHIFT); |
| | 2570 | |
| | 2571 | HModel_Regen(&xenoStatusPointer->HModelController,XENO_REGEN_TIME); |
| | 2572 | } |
| | 2573 | |
| | 2574 | if (xenoStatusPointer->stateTimer<XENO_POWERDOWN_TIME) |
| | 2575 | { |
| | 2576 | xenoStatusPointer->stateTimer+=NormalFrameTime; |
| | 2577 | } |
| | 2578 | else |
| | 2579 | { |
| | 2580 | /* Tum te tum te tum. */ |
| | 2581 | |
| | 2582 | if (Xeno_Activation_Test(sbPtr)) |
| | 2583 | Xeno_Enter_PowerUp_State(sbPtr); /* Oh well, orange alert. */ |
| | 2584 | } |
| | 2585 | } |
| | 2586 | |
| | 2587 | static void Execute_Xeno_PowerUp(STRATEGYBLOCK *sbPtr) |
| | 2588 | { |
| | 2589 | assert(sbPtr); |
| | 2590 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2591 | assert(xenoStatusPointer); |
| | 2592 | |
| | 2593 | /* Wait to finish, I guess... */ |
| | 2594 | |
| | 2595 | #if ShowXenoStats |
| | 2596 | printf("In PowerUp.\n"); |
| | 2597 | #endif |
| | 2598 | |
| | 2599 | if (!sbPtr->DisplayBlock) |
| | 2600 | { |
| | 2601 | /* We're far... do the timer! */ |
| | 2602 | ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); |
| | 2603 | } |
| | 2604 | |
| | 2605 | xenoStatusPointer->Target = NULL; |
| | 2606 | xenoStatusPointer->stateTimer += NormalFrameTime; |
| | 2607 | |
| | 2608 | if (xenoStatusPointer->soundHandle2 == SOUND_NOACTIVEINDEX) |
| | 2609 | { |
| | 2610 | if (xenoStatusPointer->stateTimer > ((ONE_FIXED*5)/2)) |
| | 2611 | { |
| | 2612 | /* Time to start the BorgOn sound. */ |
| | 2613 | Sound_Play(SID_BORGON,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle2); |
| | 2614 | } |
| | 2615 | } |
| | 2616 | |
| | 2617 | if (!xenoStatusPointer->HModelController.Tweening |
| | 2618 | && (xenoStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1))) |
| | 2619 | { |
| | 2620 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 2621 | } |
| | 2622 | } |
| | 2623 | |
| | 2624 | static void Xeno_Enter_Dormant_State(STRATEGYBLOCK *sbPtr) |
| | 2625 | { |
| | 2626 | assert(sbPtr); |
| | 2627 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2628 | assert(xenoStatusPointer); |
| | 2629 | |
| | 2630 | xenoStatusPointer->stateTimer = 0; |
| | 2631 | xenoStatusPointer->behaviourState = XS_Inactive; |
| | 2632 | |
| | 2633 | SetXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Down_Standard,ONE_FIXED,(ONE_FIXED>>2)); |
| | 2634 | |
| | 2635 | if (xenoStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) |
| | 2636 | Sound_Stop(xenoStatusPointer->soundHandle2); /* Well, it shouldn't be! */ |
| | 2637 | |
| | 2638 | /* soundHandle1 might be still powering down. */ |
| | 2639 | |
| | 2640 | assert(sbPtr->DynPtr); |
| | 2641 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 2642 | } |
| | 2643 | |
| | 2644 | static void Execute_Xeno_PowerDown(STRATEGYBLOCK *sbPtr) |
| | 2645 | { |
| | 2646 | assert(sbPtr); |
| | 2647 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2648 | assert(xenoStatusPointer); |
| | 2649 | |
| | 2650 | #if ShowXenoStats |
| | 2651 | printf("In PowerDown.\n"); |
| | 2652 | #endif |
| | 2653 | |
| | 2654 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Power_Down,ONE_FIXED,(ONE_FIXED>>2)); |
| | 2655 | xenoStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 2656 | xenoStatusPointer->HModelController.Looped = 0; |
| | 2657 | |
| | 2658 | if (!sbPtr->DisplayBlock) |
| | 2659 | { |
| | 2660 | /* We're far... do the timer! */ |
| | 2661 | ProveHModel_Far(&xenoStatusPointer->HModelController,sbPtr); |
| | 2662 | } |
| | 2663 | |
| | 2664 | /* Wait to finish, I guess... */ |
| | 2665 | |
| | 2666 | xenoStatusPointer->Target = NULL; |
| | 2667 | |
| | 2668 | if (!xenoStatusPointer->HModelController.Tweening |
| | 2669 | && (xenoStatusPointer->HModelController.sequence_timer == (ONE_FIXED-1))) |
| | 2670 | { |
| | 2671 | Xeno_Enter_Dormant_State(sbPtr); |
| | 2672 | } |
| | 2673 | } |
| | 2674 | |
| | 2675 | static void Xeno_Enter_TurnToFace_State(STRATEGYBLOCK *sbPtr) |
| | 2676 | { |
| | 2677 | assert(sbPtr); |
| | 2678 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2679 | assert(xenoStatusPointer); |
| | 2680 | |
| | 2681 | xenoStatusPointer->stateTimer = 0; |
| | 2682 | xenoStatusPointer->behaviourState = XS_TurnToFace; |
| | 2683 | |
| | 2684 | /* Sequence handled in the behaviour. */ |
| | 2685 | |
| | 2686 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 2687 | { |
| | 2688 | /* Well, it shouldn't be! */ |
| | 2689 | Sound_Stop(xenoStatusPointer->soundHandle1); |
| | 2690 | } |
| | 2691 | |
| | 2692 | Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); |
| | 2693 | |
| | 2694 | /* zero velocity */ |
| | 2695 | assert(sbPtr->DynPtr); |
| | 2696 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 2697 | } |
| | 2698 | |
| | 2699 | static void Execute_Xeno_ActiveWait(STRATEGYBLOCK *sbPtr) |
| | 2700 | { |
| | 2701 | XENO_STATUS_BLOCK *xenoStatusPointer; |
| | 2702 | int anglex,angley,correctlyOrientated; |
| | 2703 | |
| | 2704 | assert(sbPtr); |
| | 2705 | xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2706 | assert(xenoStatusPointer); |
| | 2707 | |
| | 2708 | /* What to do? Do we have a target? */ |
| | 2709 | |
| | 2710 | #if ShowXenoStats |
| | 2711 | printf("In ActiveWait.\n"); |
| | 2712 | #endif |
| | 2713 | |
| | 2714 | if (xenoStatusPointer->Target == NULL) |
| | 2715 | { |
| | 2716 | /* Let's wave the head around. */ |
| | 2717 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 2718 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 2719 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 2720 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 2721 | Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); |
| | 2722 | |
| | 2723 | xenoStatusPointer->UseHeadLaser = 1; |
| | 2724 | /* Are we at home? */ |
| | 2725 | if (sbPtr->containingModule->m_aimodule != xenoStatusPointer->my_module) |
| | 2726 | { |
| | 2727 | Xeno_Enter_Returning_State(sbPtr); |
| | 2728 | return; |
| | 2729 | } |
| | 2730 | |
| | 2731 | /* Are we facing the right way? */ |
| | 2732 | |
| | 2733 | correctlyOrientated = NPCOrientateToVector(sbPtr, &xenoStatusPointer->my_orientdir_therin, (NPC_TURNRATE >> XENO_FOOT_TURN_RATE)); |
| | 2734 | |
| | 2735 | if (!correctlyOrientated) |
| | 2736 | { |
| | 2737 | SECTION_DATA *master_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); |
| | 2738 | assert(master_section); |
| | 2739 | |
| | 2740 | Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); |
| | 2741 | |
| | 2742 | if (anglex > 0) |
| | 2743 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); |
| | 2744 | else |
| | 2745 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); |
| | 2746 | |
| | 2747 | if (xenoStatusPointer->soundHandle1 == SOUND_NOACTIVEINDEX) |
| | 2748 | Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); |
| | 2749 | } |
| | 2750 | else |
| | 2751 | { |
| | 2752 | /* Otherwise just wait? */ |
| | 2753 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 2754 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 2755 | |
| | 2756 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); |
| | 2757 | |
| | 2758 | xenoStatusPointer->stateTimer += NormalFrameTime; |
| | 2759 | |
| | 2760 | if (xenoStatusPointer->stateTimer>xenoStatusPointer->UpTime) |
| | 2761 | { |
| | 2762 | Xeno_Enter_PowerDown_State(sbPtr); |
| | 2763 | /* Voluntary powerdown! */ |
| | 2764 | xenoStatusPointer->stateTimer = XENO_POWERDOWN_TIME; |
| | 2765 | } |
| | 2766 | } |
| | 2767 | return; |
| | 2768 | } |
| | 2769 | |
| | 2770 | assert(xenoStatusPointer->Target); |
| | 2771 | |
| | 2772 | xenoStatusPointer->stateTimer = 0; |
| | 2773 | |
| | 2774 | /* Now we have a target. Can we see it? */ |
| | 2775 | if (!xenoStatusPointer->targetSightTest) |
| | 2776 | { |
| | 2777 | /* Can't see them. Are we out of range? */ |
| | 2778 | if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0) == NULL) |
| | 2779 | Xeno_Enter_Returning_State(sbPtr); |
| | 2780 | else |
| | 2781 | Xeno_Enter_Following_State(sbPtr); |
| | 2782 | return; |
| | 2783 | } |
| | 2784 | |
| | 2785 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 2786 | |
| | 2787 | /* Always turn to face too? */ |
| | 2788 | Xeno_Enter_TurnToFace_State(sbPtr); |
| | 2789 | } |
| | 2790 | |
| | 2791 | static void Execute_Xeno_ActiveWait_Far(STRATEGYBLOCK *sbPtr) |
| | 2792 | { |
| | 2793 | int anglex,angley; |
| | 2794 | |
| | 2795 | assert(sbPtr); |
| | 2796 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2797 | assert(xenoStatusPointer); |
| | 2798 | |
| | 2799 | /* What to do? Do we have a target? */ |
| | 2800 | |
| | 2801 | #if ShowXenoStats |
| | 2802 | printf("In ActiveWait Far.\n"); |
| | 2803 | #endif |
| | 2804 | |
| | 2805 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); |
| | 2806 | |
| | 2807 | if (xenoStatusPointer->Target == NULL) |
| | 2808 | { |
| | 2809 | #if FAR_XENO_ACTIVITY |
| | 2810 | /* Let's wave the head around. */ |
| | 2811 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 2812 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 2813 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 2814 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 2815 | Xeno_HeadMovement_ScanUpDown(sbPtr,XENO_HEAD_SCAN_RATE+2); |
| | 2816 | #endif |
| | 2817 | |
| | 2818 | if (sbPtr->containingModule->m_aimodule != xenoStatusPointer->my_module) |
| | 2819 | { |
| | 2820 | Xeno_Enter_Returning_State(sbPtr); |
| | 2821 | return; |
| | 2822 | } |
| | 2823 | |
| | 2824 | xenoStatusPointer->stateTimer += NormalFrameTime; |
| | 2825 | |
| | 2826 | if (xenoStatusPointer->stateTimer > xenoStatusPointer->UpTime) |
| | 2827 | Xeno_Enter_PowerDown_State(sbPtr); |
| | 2828 | |
| | 2829 | /* Are we at home? */ |
| | 2830 | if (sbPtr->containingModule->m_aimodule != xenoStatusPointer->my_module) |
| | 2831 | { |
| | 2832 | Xeno_Enter_Returning_State(sbPtr); |
| | 2833 | return; |
| | 2834 | } |
| | 2835 | |
| | 2836 | /* Are we facing the right way? */ |
| | 2837 | |
| | 2838 | if (!NPCOrientateToVector(sbPtr, &xenoStatusPointer->my_orientdir_therin, ONE_FIXED)) |
| | 2839 | { |
| | 2840 | SECTION_DATA *master_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); |
| | 2841 | assert(master_section); |
| | 2842 | |
| | 2843 | Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); |
| | 2844 | |
| | 2845 | if (anglex > 0) |
| | 2846 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); |
| | 2847 | else |
| | 2848 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); |
| | 2849 | |
| | 2850 | #if FAR_XENO_ACTIVITY |
| | 2851 | if (xenoStatusPointer->soundHandle1 == SOUND_NOACTIVEINDEX) |
| | 2852 | Sound_Play(SID_LOADMOVE,"del",&sbPtr->DynPtr->Position,&xenoStatusPointer->soundHandle1); |
| | 2853 | #endif |
| | 2854 | } |
| | 2855 | else |
| | 2856 | { |
| | 2857 | /* Otherwise just wait? */ |
| | 2858 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 2859 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 2860 | |
| | 2861 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED,(ONE_FIXED>>2)); |
| | 2862 | |
| | 2863 | xenoStatusPointer->stateTimer += NormalFrameTime; |
| | 2864 | |
| | 2865 | if (xenoStatusPointer->stateTimer > xenoStatusPointer->UpTime) |
| | 2866 | Xeno_Enter_PowerDown_State(sbPtr); |
| | 2867 | } |
| | 2868 | return; |
| | 2869 | } |
| | 2870 | |
| | 2871 | assert(xenoStatusPointer->Target); |
| | 2872 | |
| | 2873 | /* Now we have a target. Can we see it? */ |
| | 2874 | if (!xenoStatusPointer->targetSightTest) |
| | 2875 | { |
| | 2876 | /* Can't see them. Are we out of range? */ |
| | 2877 | if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0)==NULL) |
| | 2878 | Xeno_Enter_Returning_State(sbPtr); |
| | 2879 | else |
| | 2880 | Xeno_Enter_Following_State(sbPtr); |
| | 2881 | return; |
| | 2882 | } |
| | 2883 | |
| | 2884 | #if FAR_XENO_ACTIVITY |
| | 2885 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 2886 | |
| | 2887 | if ((anglex > (((XENO_HEADPAN_GIMBALL)*7)/8)) || (anglex < -(((XENO_HEADPAN_GIMBALL)*7)/8))) |
| | 2888 | Xeno_Enter_TurnToFace_State(sbPtr); |
| | 2889 | #endif |
| | 2890 | |
| | 2891 | #if ShowXenoStats |
| | 2892 | printf("Targets in module....\n"); |
| | 2893 | #endif |
| | 2894 | } |
| | 2895 | |
| | 2896 | static void Xeno_Enter_ShootingTheRoof_State(STRATEGYBLOCK *sbPtr) |
| | 2897 | { |
| | 2898 | assert(sbPtr); |
| | 2899 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2900 | assert(xenoStatusPointer); |
| | 2901 | |
| | 2902 | xenoStatusPointer->stateTimer = 0; |
| | 2903 | xenoStatusPointer->behaviourState = XS_ShootingTheRoof; |
| | 2904 | |
| | 2905 | /* Sequence handled in the behaviour. */ |
| | 2906 | |
| | 2907 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 2908 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 2909 | |
| | 2910 | Sound_Play(SID_LOADMOVE, "del", &sbPtr->DynPtr->Position, &xenoStatusPointer->soundHandle1); |
| | 2911 | |
| | 2912 | assert(sbPtr->DynPtr); |
| | 2913 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 2914 | } |
| | 2915 | |
| | 2916 | static void Execute_Xeno_TurnToFace(STRATEGYBLOCK *sbPtr) |
| | 2917 | { |
| | 2918 | int correctlyOrientated; |
| | 2919 | VECTORCH orientationDirn; |
| | 2920 | int anglex,angley; |
| | 2921 | |
| | 2922 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2923 | |
| | 2924 | #if ShowXenoStats |
| | 2925 | printf("In Turn To Face.\n"); |
| | 2926 | #endif |
| | 2927 | |
| | 2928 | if (xenoStatusPointer->Target == NULL) |
| | 2929 | { |
| | 2930 | Xeno_Enter_ActiveWait_State(sbPtr); /* Otherwise just wait? */ |
| | 2931 | return; |
| | 2932 | } |
| | 2933 | |
| | 2934 | orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx; |
| | 2935 | orientationDirn.vy = 0; |
| | 2936 | orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz; |
| | 2937 | |
| | 2938 | //correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, (NPC_TURNRATE >> XENO_FOOT_TURN_RATE)); |
| | 2939 | correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, NPC_TURNRATE); |
| | 2940 | |
| | 2941 | { |
| | 2942 | SECTION_DATA *master_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "pelvis presley"); |
| | 2943 | assert(master_section); |
| | 2944 | |
| | 2945 | Xenoborg_GetRelativeAngles(sbPtr, &anglex, &angley, &master_section->World_Offset); |
| | 2946 | |
| | 2947 | if (anglex > 0) |
| | 2948 | EnforceXenoborgShapeAnimSequence_Core(sbPtr, HMSQT_Xenoborg, XBSS_Turn_Right, XENO_TURNING_ANIM_SPEED, (ONE_FIXED>>2)); |
| | 2949 | else |
| | 2950 | EnforceXenoborgShapeAnimSequence_Core(sbPtr, HMSQT_Xenoborg, XBSS_Turn_Left, XENO_TURNING_ANIM_SPEED, (ONE_FIXED>>2)); |
| | 2951 | } |
| | 2952 | |
| | 2953 | Xeno_TurnAndTarget(sbPtr, &anglex,&angley); |
| | 2954 | |
| | 2955 | if (angley >= XENO_HEADTILT_GIMBALL) |
| | 2956 | { |
| | 2957 | Xeno_Enter_ShootingTheRoof_State(sbPtr); |
| | 2958 | return; |
| | 2959 | } |
| | 2960 | |
| | 2961 | if (correctlyOrientated) |
| | 2962 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 2963 | } |
| | 2964 | |
| | 2965 | static void Execute_Xeno_TurnToFace_Far(STRATEGYBLOCK *sbPtr) |
| | 2966 | { |
| | 2967 | int correctlyOrientated; |
| | 2968 | int anglex,angley; |
| | 2969 | |
| | 2970 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 2971 | |
| | 2972 | #if ShowXenoStats |
| | 2973 | printf("In Turn To Face Far.\n"); |
| | 2974 | #endif |
| | 2975 | |
| | 2976 | if (xenoStatusPointer->Target == NULL) |
| | 2977 | { |
| | 2978 | Xeno_Enter_ActiveWait_State(sbPtr); /* Otherwise just wait? */ |
| | 2979 | return; |
| | 2980 | } |
| | 2981 | |
| | 2982 | /* Set up animation... Which Way? */ |
| | 2983 | { |
| | 2984 | VECTORCH orientationDirn; |
| | 2985 | SECTION_DATA *master_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "pelvis presley"); |
| | 2986 | assert(master_section); |
| | 2987 | |
| | 2988 | Xenoborg_GetRelativeAngles(sbPtr, &anglex, &angley, &master_section->World_Offset); |
| | 2989 | |
| | 2990 | if (anglex < 2048) |
| | 2991 | EnforceXenoborgShapeAnimSequence_Core(sbPtr, HMSQT_Xenoborg, XBSS_Turn_Right, XENO_TURNING_ANIM_SPEED, (ONE_FIXED>>2)); |
| | 2992 | else |
| | 2993 | EnforceXenoborgShapeAnimSequence_Core(sbPtr, HMSQT_Xenoborg, XBSS_Turn_Left, XENO_TURNING_ANIM_SPEED, (ONE_FIXED>>2)); |
| | 2994 | |
| | 2995 | /* Then turn to face it, of course. */ |
| | 2996 | |
| | 2997 | orientationDirn.vx = xenoStatusPointer->targetTrackPos.vx - sbPtr->DynPtr->Position.vx; |
| | 2998 | orientationDirn.vy = 0; |
| | 2999 | orientationDirn.vz = xenoStatusPointer->targetTrackPos.vz - sbPtr->DynPtr->Position.vz; |
| | 3000 | correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, ONE_FIXED); |
| | 3001 | /* Spin FAST. */ |
| | 3002 | } |
| | 3003 | |
| | 3004 | #if FAR_XENO_ACTIVITY |
| | 3005 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 3006 | #endif |
| | 3007 | if (correctlyOrientated) |
| | 3008 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3009 | } |
| | 3010 | |
| | 3011 | static void ProcessFarXenoborgTargetModule(STRATEGYBLOCK *sbPtr, AIMODULE* targetModule) |
| | 3012 | { |
| | 3013 | assert(sbPtr); |
| | 3014 | assert(targetModule); |
| | 3015 | |
| | 3016 | NPC_TARGETMODULESTATUS targetStatus = GetTargetAIModuleStatus(sbPtr, targetModule,0); |
| | 3017 | |
| | 3018 | switch(targetStatus) |
| | 3019 | { |
| | 3020 | case NPCTM_NormalRoom: |
| | 3021 | case NPCTM_LiftDoorOpen: |
| | 3022 | case NPCTM_ProxDoorOpen: |
| | 3023 | case NPCTM_SecurityDoorOpen: |
| | 3024 | case NPCTM_AirDuct: |
| | 3025 | LocateFarNPCInAIModule(sbPtr, targetModule); |
| | 3026 | break; |
| | 3027 | case NPCTM_LiftDoorNotOpen: |
| | 3028 | case NPCTM_LiftTeleport: |
| | 3029 | case NPCTM_NoEntryPoint: |
| | 3030 | FarNpc_FlipAround(sbPtr); |
| | 3031 | break; |
| | 3032 | case NPCTM_ProxDoorNotOpen: |
| | 3033 | { |
| | 3034 | MODULE *renderModule = *(targetModule->m_module_ptrs); |
| | 3035 | /* trigger the door, and set timer to quick so we can catch the door when it's open */ |
| | 3036 | ((PROXDOOR_BEHAV_BLOCK *)renderModule->m_sbptr->dataptr)->alienTrigger = 1; |
| | 3037 | } |
| | 3038 | break; |
| | 3039 | case NPCTM_SecurityDoorNotOpen: |
| | 3040 | { |
| | 3041 | MODULE *renderModule = *(targetModule->m_module_ptrs); |
| | 3042 | /* do some door opening stuff here. Door should stay open for long enough |
| | 3043 | for us to catch it open next time */ |
| | 3044 | RequestState((renderModule->m_sbptr),1,0); |
| | 3045 | } |
| | 3046 | break; |
| | 3047 | default: |
| | 3048 | { |
| | 3049 | assert(1==0); |
| | 3050 | } |
| | 3051 | } |
| | 3052 | } |
| | 3053 | |
| | 3054 | static void Execute_Xeno_Follow_Far(STRATEGYBLOCK *sbPtr) |
| | 3055 | { |
| | 3056 | #if FAR_XENO_ACTIVITY |
| | 3057 | int anglex,angley; |
| | 3058 | #endif |
| | 3059 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3060 | |
| | 3061 | /* In theory, we're following the target, and can't see it. */ |
| | 3062 | |
| | 3063 | #if ShowXenoStats |
| | 3064 | printf("In Follow Far.\n"); |
| | 3065 | #endif |
| | 3066 | |
| | 3067 | if (xenoStatusPointer->Target == NULL) |
| | 3068 | { |
| | 3069 | /* Let's wave the head around. */ |
| | 3070 | #if FAR_XENO_ACTIVITY |
| | 3071 | Xeno_HeadMovement_ScanLeftRight(sbPtr, XENO_HEAD_SCAN_RATE); |
| | 3072 | Xeno_HeadMovement_ScanUpDown(sbPtr, XENO_HEAD_SCAN_RATE+2); |
| | 3073 | #endif |
| | 3074 | /* And return to my module. */ |
| | 3075 | Xeno_Enter_Returning_State(sbPtr); |
| | 3076 | return; |
| | 3077 | } |
| | 3078 | |
| | 3079 | /* Increment the Far state timer */ |
| | 3080 | xenoStatusPointer->stateTimer += NormalFrameTime; |
| | 3081 | |
| | 3082 | /* check if far state timer has timed-out. If so, it is time |
| | 3083 | to do something. Otherwise just return. */ |
| | 3084 | |
| | 3085 | if(xenoStatusPointer->stateTimer < XENO_FAR_MOVE_TIME) |
| | 3086 | { |
| | 3087 | #if FAR_XENO_ACTIVITY |
| | 3088 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 3089 | #endif |
| | 3090 | return; |
| | 3091 | } |
| | 3092 | |
| | 3093 | assert(xenoStatusPointer->Target); |
| | 3094 | /* Now we know have a target. Can we see it yet? */ |
| | 3095 | |
| | 3096 | if (!xenoStatusPointer->targetSightTest) |
| | 3097 | { |
| | 3098 | AIMODULE *targetModule; |
| | 3099 | |
| | 3100 | /* Can't see them. Never mind. Go to the next module? */ |
| | 3101 | if (xenoStatusPointer->Target->containingModule == NULL) |
| | 3102 | { |
| | 3103 | /* Fall through for now. */ |
| | 3104 | targetModule = NULL; |
| | 3105 | } |
| | 3106 | else if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0) ==
NULL) |
| | 3107 | { |
| | 3108 | /* Too Far! */ |
| | 3109 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3110 | return; |
| | 3111 | } |
| | 3112 | else |
| | 3113 | { |
| | 3114 | /* Still in range: keep going. */ |
| | 3115 | targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
xenoStatusPointer->Target->containingModule->m_aimodule,xenoStatusPointer->module_range,0); |
| | 3116 | } |
| | 3117 | |
| | 3118 | if (targetModule == NULL) |
| | 3119 | { |
| | 3120 | /* They're way away. */ |
| | 3121 | Xeno_Enter_Returning_State(sbPtr); |
| | 3122 | return; |
| | 3123 | } |
| | 3124 | |
| | 3125 | if (targetModule != xenoStatusPointer->Target->containingModule->m_aimodule) |
| | 3126 | { |
| | 3127 | assert(targetModule); |
| | 3128 | ProcessFarXenoborgTargetModule(sbPtr,targetModule); |
| | 3129 | |
| | 3130 | } |
| | 3131 | else |
| | 3132 | { |
| | 3133 | /* In our target's module! */ |
| | 3134 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3135 | } |
| | 3136 | } |
| | 3137 | else |
| | 3138 | { |
| | 3139 | /* Re-aquired! */ |
| | 3140 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3141 | return; |
| | 3142 | } |
| | 3143 | |
| | 3144 | xenoStatusPointer->stateTimer = 0; |
| | 3145 | |
| | 3146 | XenoborgHandleMovingAnimation(sbPtr); |
| | 3147 | |
| | 3148 | #if FAR_XENO_ACTIVITY |
| | 3149 | if (!xenoStatusPointer->targetSightTest) |
| | 3150 | { |
| | 3151 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3152 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3153 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3154 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 3155 | } |
| | 3156 | else |
| | 3157 | { |
| | 3158 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 3159 | } |
| | 3160 | #endif |
| | 3161 | } |
| | 3162 | |
| | 3163 | static void Xeno_CopeWithLossOfHome(STRATEGYBLOCK *sbPtr) |
| | 3164 | { |
| | 3165 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3166 | /* Ooh, yuck. */ |
| | 3167 | xenoStatusPointer->my_module = sbPtr->containingModule->m_aimodule; |
| | 3168 | xenoStatusPointer->my_spot_therin = sbPtr->DynPtr->Position; |
| | 3169 | } |
| | 3170 | |
| | 3171 | static void Execute_Xeno_Return_Far(STRATEGYBLOCK *sbPtr) |
| | 3172 | { |
| | 3173 | assert(sbPtr); |
| | 3174 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3175 | assert(xenoStatusPointer); |
| | 3176 | |
| | 3177 | /* In theory, we're following the target, and can't see it. */ |
| | 3178 | |
| | 3179 | #if ShowXenoStats |
| | 3180 | printf("In Return Far.\n"); |
| | 3181 | #endif |
| | 3182 | |
| | 3183 | if (xenoStatusPointer->Target != NULL) |
| | 3184 | { |
| | 3185 | /* Saw something! */ |
| | 3186 | /* Go to active wait. */ |
| | 3187 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3188 | return; |
| | 3189 | } |
| | 3190 | |
| | 3191 | /* Increment the Far state timer */ |
| | 3192 | xenoStatusPointer->stateTimer += NormalFrameTime; |
| | 3193 | |
| | 3194 | /* check if far state timer has timed-out. If so, it is time |
| | 3195 | to do something. Otherwise just return. */ |
| | 3196 | |
| | 3197 | if(xenoStatusPointer->stateTimer < XENO_FAR_MOVE_TIME) |
| | 3198 | { |
| | 3199 | #if FAR_XENO_ACTIVITY |
| | 3200 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 3201 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3202 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3203 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3204 | #endif |
| | 3205 | return; |
| | 3206 | } |
| | 3207 | |
| | 3208 | assert(xenoStatusPointer->Target == NULL); |
| | 3209 | /* Find our way home. */ |
| | 3210 | |
| | 3211 | { |
| | 3212 | /* Go to the next module. */ |
| | 3213 | AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
xenoStatusPointer->my_module,xenoStatusPointer->module_range+2,0); |
| | 3214 | /* Just to be on the safe side. */ |
| | 3215 | |
| | 3216 | if (targetModule == NULL) |
| | 3217 | { |
| | 3218 | /* Emergency! */ |
| | 3219 | targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
xenoStatusPointer->my_module,xenoStatusPointer->module_range+5,0); |
| | 3220 | |
| | 3221 | if (targetModule == NULL) |
| | 3222 | { |
| | 3223 | /* Totally broken. Stay here. */ |
| | 3224 | Xeno_CopeWithLossOfHome(sbPtr); |
| | 3225 | return; |
| | 3226 | } |
| | 3227 | } |
| | 3228 | |
| | 3229 | if (targetModule != sbPtr->containingModule->m_aimodule) |
| | 3230 | { |
| | 3231 | assert(targetModule); |
| | 3232 | ProcessFarXenoborgTargetModule(sbPtr,targetModule); |
| | 3233 | } |
| | 3234 | else |
| | 3235 | { |
| | 3236 | /* In our own home module! */ |
| | 3237 | |
| | 3238 | sbPtr->DynPtr->Position=xenoStatusPointer->my_spot_therin; |
| | 3239 | |
| | 3240 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3241 | } |
| | 3242 | } |
| | 3243 | |
| | 3244 | xenoStatusPointer->stateTimer = 0; |
| | 3245 | |
| | 3246 | XenoborgHandleMovingAnimation(sbPtr); |
| | 3247 | |
| | 3248 | #if FAR_XENO_ACTIVITY |
| | 3249 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3250 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3251 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3252 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 3253 | #endif |
| | 3254 | } |
| | 3255 | |
| | 3256 | static void Xeno_Enter_Avoidance_State(STRATEGYBLOCK *sbPtr) |
| | 3257 | { |
| | 3258 | assert(sbPtr); |
| | 3259 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3260 | assert(xenoStatusPointer); |
| | 3261 | |
| | 3262 | xenoStatusPointer->Target = NULL; |
| | 3263 | /* Make sure obstruction is set! */ |
| | 3264 | NPC_InitMovementData(&(xenoStatusPointer->moveData)); |
| | 3265 | NPCGetAvoidanceDirection(sbPtr, &(xenoStatusPointer->moveData.avoidanceDirn),&xenoStatusPointer->obstruction); |
| | 3266 | xenoStatusPointer->lastState = xenoStatusPointer->behaviourState; |
| | 3267 | xenoStatusPointer->behaviourState = XS_Avoidance; |
| | 3268 | xenoStatusPointer->stateTimer = NPC_AVOIDTIME; |
| | 3269 | InitWaypointManager(&xenoStatusPointer->waypointManager); |
| | 3270 | |
| | 3271 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 3272 | Sound_Stop(xenoStatusPointer->soundHandle1); /* Well, it shouldn't be! */ |
| | 3273 | |
| | 3274 | Sound_Play(SID_LOADMOVE, "del", &sbPtr->DynPtr->Position, &xenoStatusPointer->soundHandle1); |
| | 3275 | } |
| | 3276 | |
| | 3277 | static void Execute_Xeno_Follow(STRATEGYBLOCK *sbPtr) |
| | 3278 | { |
| | 3279 | VECTORCH velocityDirection = {0,0,0}; |
| | 3280 | VECTORCH targetPosition; |
| | 3281 | int targetIsAirduct = 0; |
| | 3282 | int anglex,angley; |
| | 3283 | |
| | 3284 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3285 | |
| | 3286 | /* In theory, we're following the target, and can't see it. */ |
| | 3287 | |
| | 3288 | #if ShowXenoStats |
| | 3289 | printf("In Follow.\n"); |
| | 3290 | #endif |
| | 3291 | |
| | 3292 | if (xenoStatusPointer->Target == NULL) |
| | 3293 | { |
| | 3294 | /* Let's wave the head around. */ |
| | 3295 | Xeno_HeadMovement_ScanLeftRight(sbPtr, XENO_HEAD_SCAN_RATE); |
| | 3296 | |
| | 3297 | /* Do we want to do this? */ |
| | 3298 | Xeno_HeadMovement_ScanUpDown(sbPtr, XENO_HEAD_SCAN_RATE+2); |
| | 3299 | xenoStatusPointer->UseHeadLaser = 1; |
| | 3300 | |
| | 3301 | /* And return to my module. */ |
| | 3302 | Xeno_Enter_Returning_State(sbPtr); |
| | 3303 | return; |
| | 3304 | } |
| | 3305 | |
| | 3306 | /* Now we know have a target. Can we see it yet? */ |
| | 3307 | |
| | 3308 | if (!xenoStatusPointer->targetSightTest) |
| | 3309 | { |
| | 3310 | AIMODULE *targetModule; |
| | 3311 | |
| | 3312 | /* Can't see them. Never mind. Go to the next module? */ |
| | 3313 | if (xenoStatusPointer->Target->containingModule == NULL) |
| | 3314 | { |
| | 3315 | /* Fall through for now. */ |
| | 3316 | targetModule = NULL; |
| | 3317 | } |
| | 3318 | else if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0) ==
NULL) |
| | 3319 | { |
| | 3320 | /* Too Far! */ |
| | 3321 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3322 | return; |
| | 3323 | } |
| | 3324 | else |
| | 3325 | { |
| | 3326 | /* Still in range: keep going. */ |
| | 3327 | targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
xenoStatusPointer->Target->containingModule->m_aimodule,xenoStatusPointer->module_range,0); |
| | 3328 | } |
| | 3329 | |
| | 3330 | if (targetModule == NULL) |
| | 3331 | { |
| | 3332 | /* They're way away. */ |
| | 3333 | Xeno_Enter_Returning_State(sbPtr); |
| | 3334 | return; |
| | 3335 | } |
| | 3336 | |
| | 3337 | if (targetModule == sbPtr->containingModule->m_aimodule) |
| | 3338 | { |
| | 3339 | /* Good Grief, Penfold! He's right there, but I can't see him! */ |
| | 3340 | NPCGetMovementDirection(sbPtr, &velocityDirection, &xenoStatusPointer->targetTrackPos,&xenoStatusPointer->waypointManager); |
| | 3341 | NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); |
| | 3342 | |
| | 3343 | targetPosition = xenoStatusPointer->targetTrackPos; |
| | 3344 | |
| | 3345 | #if ShowXenoStats |
| | 3346 | printf("Direct movement - no LOS.\n"); |
| | 3347 | #endif |
| | 3348 | |
| | 3349 | /* Oh, well. Go to last known position? */ |
| | 3350 | } |
| | 3351 | else |
| | 3352 | { |
| | 3353 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); |
| | 3354 | |
| | 3355 | if (!thisEp) |
| | 3356 | { |
| | 3357 | printf("This assert is a busted adjacency!\nNo EP between %s and %s.", |
| | 3358 | (*(targetModule->m_module_ptrs))->name, sbPtr->containingModule->name); |
| | 3359 | assert(thisEp); |
| | 3360 | } |
| | 3361 | /* If that fired, there's a farped adjacency. */ |
| | 3362 | |
| | 3363 | xenoStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 3364 | xenoStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx; |
| | 3365 | xenoStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy; |
| | 3366 | xenoStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz; |
| | 3367 | |
| | 3368 | NPCGetMovementDirection(sbPtr, &velocityDirection,
&(xenoStatusPointer->wanderData.worldPosition),&xenoStatusPointer->waypointManager); |
| | 3369 | NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); |
| | 3370 | targetPosition = xenoStatusPointer->wanderData.worldPosition; |
| | 3371 | } |
| | 3372 | } |
| | 3373 | else |
| | 3374 | { |
| | 3375 | /* Re-aquired! Get a bit closer? */ |
| | 3376 | |
| | 3377 | if (GetNextModuleForLink(sbPtr->containingModule->m_aimodule, xenoStatusPointer->my_module,(xenoStatusPointer->module_range)-1,0) == NULL) |
| | 3378 | { |
| | 3379 | /* Too Far! */ |
| | 3380 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3381 | return; |
| | 3382 | } |
| | 3383 | |
| | 3384 | int range = VectorDistance(&xenoStatusPointer->Target->DynPtr->Position, &sbPtr->DynPtr->Position); |
| | 3385 | |
| | 3386 | if (range > XENO_CLOSE_APPROACH_DISTANCE) |
| | 3387 | { |
| | 3388 | NPCGetMovementTarget(sbPtr, xenoStatusPointer->Target, &targetPosition, &targetIsAirduct,0); |
| | 3389 | NPCGetMovementDirection(sbPtr, &velocityDirection, &targetPosition,&xenoStatusPointer->waypointManager); |
| | 3390 | NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); |
| | 3391 | |
| | 3392 | #if ShowXenoStats |
| | 3393 | printf("Direct movement - LOS Okay.\n"); |
| | 3394 | #endif |
| | 3395 | } |
| | 3396 | else |
| | 3397 | { |
| | 3398 | /* Return to ActiveWait. */ |
| | 3399 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3400 | return; |
| | 3401 | } |
| | 3402 | } |
| | 3403 | |
| | 3404 | XenoborgHandleMovingAnimation(sbPtr); |
| | 3405 | |
| | 3406 | if (!xenoStatusPointer->targetSightTest) |
| | 3407 | { |
| | 3408 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3409 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3410 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3411 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 3412 | xenoStatusPointer->UseHeadLaser = 1; |
| | 3413 | } |
| | 3414 | else |
| | 3415 | { |
| | 3416 | Xeno_TurnAndTarget(sbPtr, &anglex,&angley); |
| | 3417 | } |
| | 3418 | |
| | 3419 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 3420 | { |
| | 3421 | STRATEGYBLOCK *destructableObject = NULL; |
| | 3422 | |
| | 3423 | NPC_IsObstructed(sbPtr, &xenoStatusPointer->moveData, &xenoStatusPointer->obstruction, &destructableObject); |
| | 3424 | |
| | 3425 | if(xenoStatusPointer->obstruction.environment) |
| | 3426 | { |
| | 3427 | Xeno_Enter_Avoidance_State(sbPtr); |
| | 3428 | return; |
| | 3429 | } |
| | 3430 | |
| | 3431 | if(xenoStatusPointer->obstruction.destructableObject) |
| | 3432 | { |
| | 3433 | assert(destructableObject); |
| | 3434 | CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL); |
| | 3435 | } |
| | 3436 | } |
| | 3437 | |
| | 3438 | if(NPC_CannotReachTarget(&xenoStatusPointer->moveData, &targetPosition, &velocityDirection)) |
| | 3439 | { |
| | 3440 | xenoStatusPointer->obstruction.environment = 1; |
| | 3441 | xenoStatusPointer->obstruction.destructableObject = 0; |
| | 3442 | xenoStatusPointer->obstruction.otherCharacter = 0; |
| | 3443 | xenoStatusPointer->obstruction.anySingleObstruction = 0; |
| | 3444 | Xeno_Enter_Avoidance_State(sbPtr); |
| | 3445 | } |
| | 3446 | } |
| | 3447 | |
| | 3448 | static void Execute_Xeno_Return(STRATEGYBLOCK *sbPtr) |
| | 3449 | { |
| | 3450 | VECTORCH velocityDirection = {0,0,0}; |
| | 3451 | VECTORCH *targetPosition = NULL; |
| | 3452 | |
| | 3453 | assert(sbPtr); |
| | 3454 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3455 | assert(xenoStatusPointer); |
| | 3456 | |
| | 3457 | /* In theory, we're following the target, and can't see it. */ |
| | 3458 | |
| | 3459 | #if ShowXenoStats |
| | 3460 | printf("In Return.\n"); |
| | 3461 | #endif |
| | 3462 | |
| | 3463 | if (xenoStatusPointer->Target != NULL) |
| | 3464 | { |
| | 3465 | /* Saw something! */ |
| | 3466 | /* Go to active wait. */ |
| | 3467 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3468 | return; |
| | 3469 | } |
| | 3470 | |
| | 3471 | /* Find our way home. */ |
| | 3472 | |
| | 3473 | { |
| | 3474 | /* Go to the next module. */ |
| | 3475 | AIMODULE *targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
xenoStatusPointer->my_module,xenoStatusPointer->module_range+2,0); |
| | 3476 | /* Just to be on the safe side. */ |
| | 3477 | |
| | 3478 | if (targetModule == NULL) |
| | 3479 | { |
| | 3480 | |
| | 3481 | /* Emergency! */ |
| | 3482 | targetModule = GetNextModuleForLink(sbPtr->containingModule->m_aimodule,
xenoStatusPointer->my_module,xenoStatusPointer->module_range+5,0); |
| | 3483 | |
| | 3484 | if (targetModule == NULL) |
| | 3485 | { |
| | 3486 | /* Totally broken. Stay here. */ |
| | 3487 | Xeno_CopeWithLossOfHome(sbPtr); |
| | 3488 | return; |
| | 3489 | } |
| | 3490 | } |
| | 3491 | |
| | 3492 | if (targetModule != sbPtr->containingModule->m_aimodule) |
| | 3493 | { |
| | 3494 | FARENTRYPOINT *thisEp = GetAIModuleEP(targetModule,sbPtr->containingModule->m_aimodule); |
| | 3495 | |
| | 3496 | if (!thisEp) |
| | 3497 | { |
| | 3498 | printf("This assert is a busted adjacency!\nNo EP between %s and %s.", (*(targetModule->m_module_ptrs))->name,
sbPtr->containingModule->name); |
| | 3499 | assert(thisEp); |
| | 3500 | } |
| | 3501 | |
| | 3502 | /* If that fired, there's a farped adjacency. */ |
| | 3503 | |
| | 3504 | xenoStatusPointer->wanderData.worldPosition = thisEp->position; |
| | 3505 | xenoStatusPointer->wanderData.worldPosition.vx += targetModule->m_world.vx; |
| | 3506 | xenoStatusPointer->wanderData.worldPosition.vy += targetModule->m_world.vy; |
| | 3507 | xenoStatusPointer->wanderData.worldPosition.vz += targetModule->m_world.vz; |
| | 3508 | |
| | 3509 | NPCGetMovementDirection(sbPtr, &velocityDirection,
&(xenoStatusPointer->wanderData.worldPosition),&xenoStatusPointer->waypointManager); |
| | 3510 | NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); |
| | 3511 | targetPosition=&(xenoStatusPointer->wanderData.worldPosition); |
| | 3512 | } |
| | 3513 | else |
| | 3514 | { |
| | 3515 | VECTORCH offset; |
| | 3516 | /* In our own home module! */ |
| | 3517 | |
| | 3518 | offset.vx = sbPtr->DynPtr->Position.vx - xenoStatusPointer->my_spot_therin.vx; |
| | 3519 | offset.vy = sbPtr->DynPtr->Position.vy - xenoStatusPointer->my_spot_therin.vy; |
| | 3520 | offset.vz = sbPtr->DynPtr->Position.vz - xenoStatusPointer->my_spot_therin.vz; |
| | 3521 | /* Fix for midair start points, grrrr. */ |
| | 3522 | offset.vy >>= 2; |
| | 3523 | |
| | 3524 | /* Find distance off spot. */ |
| | 3525 | int dist = Approximate3dMagnitude(&offset); |
| | 3526 | |
| | 3527 | if (dist < XENO_SENTRY_SENSITIVITY) |
| | 3528 | { |
| | 3529 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3530 | return; |
| | 3531 | } |
| | 3532 | else |
| | 3533 | { |
| | 3534 | NPCGetMovementDirection(sbPtr, &velocityDirection, &(xenoStatusPointer->my_spot_therin),&xenoStatusPointer->waypointManager); |
| | 3535 | NPCSetVelocity(sbPtr, &velocityDirection, XENO_NEAR_SPEED); |
| | 3536 | targetPosition = &(xenoStatusPointer->my_spot_therin); |
| | 3537 | } |
| | 3538 | } |
| | 3539 | } |
| | 3540 | |
| | 3541 | XenoborgHandleMovingAnimation(sbPtr); |
| | 3542 | |
| | 3543 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3544 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3545 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3546 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 3547 | xenoStatusPointer->UseHeadLaser = 1; |
| | 3548 | |
| | 3549 | /* test here for impeding collisions, and not being able to reach target... */ |
| | 3550 | { |
| | 3551 | STRATEGYBLOCK *destructableObject = NULL; |
| | 3552 | |
| | 3553 | NPC_IsObstructed(sbPtr, &xenoStatusPointer->moveData, &xenoStatusPointer->obstruction, &destructableObject); |
| | 3554 | |
| | 3555 | if(xenoStatusPointer->obstruction.environment) |
| | 3556 | { |
| | 3557 | /* go to avoidance */ |
| | 3558 | Xeno_Enter_Avoidance_State(sbPtr); |
| | 3559 | return; |
| | 3560 | } |
| | 3561 | |
| | 3562 | if(xenoStatusPointer->obstruction.destructableObject) |
| | 3563 | { |
| | 3564 | assert(destructableObject); |
| | 3565 | CauseDamageToObject(destructableObject,&TemplateAmmo[AMMO_NPC_OBSTACLE_CLEAR].MaxDamage, ONE_FIXED,NULL); |
| | 3566 | } |
| | 3567 | } |
| | 3568 | |
| | 3569 | if(NPC_CannotReachTarget(&xenoStatusPointer->moveData, targetPosition, &velocityDirection)) |
| | 3570 | { |
| | 3571 | xenoStatusPointer->obstruction.environment = 1; |
| | 3572 | xenoStatusPointer->obstruction.destructableObject = 0; |
| | 3573 | xenoStatusPointer->obstruction.otherCharacter = 0; |
| | 3574 | xenoStatusPointer->obstruction.anySingleObstruction = 0; |
| | 3575 | |
| | 3576 | Xeno_Enter_Avoidance_State(sbPtr); |
| | 3577 | } |
| | 3578 | } |
| | 3579 | |
| | 3580 | static void Execute_Xeno_Avoidance(STRATEGYBLOCK *sbPtr) |
| | 3581 | { |
| | 3582 | assert(sbPtr); |
| | 3583 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3584 | assert(xenoStatusPointer); |
| | 3585 | |
| | 3586 | #if ShowXenoStats |
| | 3587 | printf("In Avoidance.\n"); |
| | 3588 | #endif |
| | 3589 | |
| | 3590 | XenoborgHandleMovingAnimation(sbPtr); |
| | 3591 | |
| | 3592 | if (!xenoStatusPointer->targetSightTest) |
| | 3593 | { |
| | 3594 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3595 | Xeno_LeftArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3596 | Xeno_RightArmMovement_Centre(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3597 | Xeno_HeadMovement_ScanLeftRight(sbPtr,XENO_HEAD_SCAN_RATE); |
| | 3598 | xenoStatusPointer->UseHeadLaser = 1; |
| | 3599 | } |
| | 3600 | else |
| | 3601 | { |
| | 3602 | int anglex,angley; |
| | 3603 | Xeno_TurnAndTarget(sbPtr,&anglex,&angley); |
| | 3604 | } |
| | 3605 | |
| | 3606 | /* set velocity */ |
| | 3607 | assert((xenoStatusPointer->moveData.avoidanceDirn.vx !=0)|| |
| | 3608 | (xenoStatusPointer->moveData.avoidanceDirn.vy !=0)|| |
| | 3609 | (xenoStatusPointer->moveData.avoidanceDirn.vz !=0)); |
| | 3610 | |
| | 3611 | NPCSetVelocity(sbPtr, &(xenoStatusPointer->moveData.avoidanceDirn), (XENO_NEAR_SPEED)); |
| | 3612 | |
| | 3613 | /* decrement state timer */ |
| | 3614 | xenoStatusPointer->stateTimer -= NormalFrameTime; |
| | 3615 | |
| | 3616 | { |
| | 3617 | STRATEGYBLOCK *destructableObject = NULL; |
| | 3618 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 3619 | |
| | 3620 | NPC_IsObstructed(sbPtr,&(xenoStatusPointer->moveData),&obstruction,&destructableObject); |
| | 3621 | |
| | 3622 | if((xenoStatusPointer->stateTimer <= 0) || obstruction.anySingleObstruction) |
| | 3623 | { |
| | 3624 | /* go to an appropriate state */ |
| | 3625 | switch (xenoStatusPointer->lastState) |
| | 3626 | { |
| | 3627 | case XS_Returning: |
| | 3628 | Xeno_Enter_Returning_State(sbPtr); |
| | 3629 | return; |
| | 3630 | case XS_Following: |
| | 3631 | Xeno_Enter_Following_State(sbPtr); |
| | 3632 | return; |
| | 3633 | default: |
| | 3634 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3635 | return; |
| | 3636 | } |
| | 3637 | } |
| | 3638 | } |
| | 3639 | } |
| | 3640 | |
| | 3641 | static void Xeno_LeftArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate) |
| | 3642 | { |
| | 3643 | assert(sbPtr); |
| | 3644 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3645 | assert(xenoStatusPointer); |
| | 3646 | |
| | 3647 | /* Let's wave the left arm around. */ |
| | 3648 | if (xenoStatusPointer->leftarmtiltdir) |
| | 3649 | { |
| | 3650 | xenoStatusPointer->Left_Arm_Tilt += (NormalFrameTime>>rate); |
| | 3651 | |
| | 3652 | if (xenoStatusPointer->Left_Arm_Tilt > -(XENO_HEADTILT_GIMBALL<<4)) |
| | 3653 | { |
| | 3654 | xenoStatusPointer->Left_Arm_Tilt = -(XENO_HEADTILT_GIMBALL<<4); |
| | 3655 | xenoStatusPointer->leftarmtiltdir = 0; |
| | 3656 | } |
| | 3657 | else |
| | 3658 | { |
| | 3659 | xenoStatusPointer->la_moving = 1; |
| | 3660 | } |
| | 3661 | } |
| | 3662 | else |
| | 3663 | { |
| | 3664 | xenoStatusPointer->Left_Arm_Tilt -= (NormalFrameTime>>rate); |
| | 3665 | |
| | 3666 | if (xenoStatusPointer->Left_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 3667 | { |
| | 3668 | xenoStatusPointer->Left_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 3669 | xenoStatusPointer->leftarmtiltdir = 1; |
| | 3670 | } |
| | 3671 | else |
| | 3672 | { |
| | 3673 | xenoStatusPointer->la_moving = 1; |
| | 3674 | } |
| | 3675 | } |
| | 3676 | |
| | 3677 | if (xenoStatusPointer->left_arm_tilt) |
| | 3678 | xenoStatusPointer->left_arm_tilt->Active = 1; |
| | 3679 | } |
| | 3680 | |
| | 3681 | static void Xeno_LeftArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate) |
| | 3682 | { |
| | 3683 | assert(sbPtr); |
| | 3684 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3685 | assert(xenoStatusPointer); |
| | 3686 | |
| | 3687 | /* Let's wave the left arm around. */ |
| | 3688 | if (xenoStatusPointer->leftarmpandir) |
| | 3689 | { |
| | 3690 | xenoStatusPointer->Left_Arm_Pan += (NormalFrameTime>>rate); |
| | 3691 | |
| | 3692 | if (xenoStatusPointer->Left_Arm_Pan > (XENO_LEFTARM_ACW_GIMBALL<<4)) |
| | 3693 | { |
| | 3694 | xenoStatusPointer->Left_Arm_Pan = (XENO_LEFTARM_ACW_GIMBALL<<4); |
| | 3695 | xenoStatusPointer->leftarmpandir = 0; |
| | 3696 | } |
| | 3697 | else |
| | 3698 | { |
| | 3699 | xenoStatusPointer->la_moving = 1; |
| | 3700 | } |
| | 3701 | } |
| | 3702 | else |
| | 3703 | { |
| | 3704 | xenoStatusPointer->Left_Arm_Pan -= (NormalFrameTime>>rate); |
| | 3705 | |
| | 3706 | if (xenoStatusPointer->Left_Arm_Pan < -(XENO_LEFTARM_CW_GIMBALL<<4)) |
| | 3707 | { |
| | 3708 | xenoStatusPointer->Left_Arm_Pan = -(XENO_LEFTARM_CW_GIMBALL<<4); |
| | 3709 | xenoStatusPointer->leftarmpandir = 1; |
| | 3710 | } |
| | 3711 | else |
| | 3712 | { |
| | 3713 | xenoStatusPointer->la_moving = 1; |
| | 3714 | } |
| | 3715 | } |
| | 3716 | |
| | 3717 | if (xenoStatusPointer->left_arm_pan) |
| | 3718 | xenoStatusPointer->left_arm_pan->Active = 1; |
| | 3719 | } |
| | 3720 | |
| | 3721 | static void Xeno_RightArmMovement_WaveUp(STRATEGYBLOCK *sbPtr,int rate) |
| | 3722 | { |
| | 3723 | assert(sbPtr); |
| | 3724 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3725 | assert(xenoStatusPointer); |
| | 3726 | |
| | 3727 | /* Let's wave the Right arm around. */ |
| | 3728 | if (xenoStatusPointer->rightarmtiltdir) |
| | 3729 | { |
| | 3730 | xenoStatusPointer->Right_Arm_Tilt += (NormalFrameTime>>rate); |
| | 3731 | |
| | 3732 | if (xenoStatusPointer->Right_Arm_Tilt > -(XENO_HEADTILT_GIMBALL<<4)) |
| | 3733 | { |
| | 3734 | xenoStatusPointer->Right_Arm_Tilt = -(XENO_HEADTILT_GIMBALL<<4); |
| | 3735 | xenoStatusPointer->rightarmtiltdir = 0; |
| | 3736 | } |
| | 3737 | else |
| | 3738 | { |
| | 3739 | xenoStatusPointer->ra_moving = 1; |
| | 3740 | } |
| | 3741 | } |
| | 3742 | else |
| | 3743 | { |
| | 3744 | xenoStatusPointer->Right_Arm_Tilt -= (NormalFrameTime>>rate); |
| | 3745 | |
| | 3746 | if (xenoStatusPointer->Right_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 3747 | { |
| | 3748 | xenoStatusPointer->Right_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 3749 | xenoStatusPointer->rightarmtiltdir = 1; |
| | 3750 | } |
| | 3751 | else |
| | 3752 | { |
| | 3753 | xenoStatusPointer->ra_moving = 1; |
| | 3754 | } |
| | 3755 | } |
| | 3756 | |
| | 3757 | if (xenoStatusPointer->right_arm_tilt) |
| | 3758 | xenoStatusPointer->right_arm_tilt->Active = 1; |
| | 3759 | } |
| | 3760 | |
| | 3761 | static void Xeno_RightArmMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate) |
| | 3762 | { |
| | 3763 | assert(sbPtr); |
| | 3764 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3765 | assert(xenoStatusPointer); |
| | 3766 | |
| | 3767 | /* Let's wave the Right arm around. */ |
| | 3768 | if (xenoStatusPointer->rightarmpandir) |
| | 3769 | { |
| | 3770 | xenoStatusPointer->Right_Arm_Pan += (NormalFrameTime>>rate); |
| | 3771 | |
| | 3772 | if (xenoStatusPointer->Right_Arm_Pan > (XENO_RIGHTARM_ACW_GIMBALL<<4)) |
| | 3773 | { |
| | 3774 | xenoStatusPointer->Right_Arm_Pan = (XENO_RIGHTARM_ACW_GIMBALL<<4); |
| | 3775 | xenoStatusPointer->rightarmpandir = 0; |
| | 3776 | } |
| | 3777 | else |
| | 3778 | { |
| | 3779 | xenoStatusPointer->ra_moving = 1; |
| | 3780 | } |
| | 3781 | } |
| | 3782 | else |
| | 3783 | { |
| | 3784 | xenoStatusPointer->Right_Arm_Pan -= (NormalFrameTime>>rate); |
| | 3785 | |
| | 3786 | if (xenoStatusPointer->Right_Arm_Pan < -(XENO_RIGHTARM_CW_GIMBALL<<4)) |
| | 3787 | { |
| | 3788 | xenoStatusPointer->Right_Arm_Pan = -(XENO_RIGHTARM_CW_GIMBALL<<4); |
| | 3789 | xenoStatusPointer->rightarmpandir = 1; |
| | 3790 | } |
| | 3791 | else |
| | 3792 | { |
| | 3793 | xenoStatusPointer->ra_moving = 1; |
| | 3794 | } |
| | 3795 | } |
| | 3796 | |
| | 3797 | if (xenoStatusPointer->right_arm_pan) |
| | 3798 | xenoStatusPointer->right_arm_pan->Active = 1; |
| | 3799 | } |
| | 3800 | |
| | 3801 | static void Xeno_Limbs_ShootTheRoof(STRATEGYBLOCK *sbPtr) |
| | 3802 | { |
| | 3803 | assert(sbPtr); |
| | 3804 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3805 | assert(xenoStatusPointer); |
| | 3806 | |
| | 3807 | Xeno_TorsoMovement_Centre(sbPtr,XENO_TORSO_TWIST_RATE); |
| | 3808 | Xeno_LeftArmMovement_WaveUp(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3809 | Xeno_LeftArmMovement_TrackLeftRight(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3810 | Xeno_RightArmMovement_WaveUp(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3811 | Xeno_RightArmMovement_TrackLeftRight(sbPtr,XENO_ARM_LOCK_RATE); |
| | 3812 | Xeno_HeadMovement_TrackToAngles(sbPtr,XENO_HEAD_SCAN_RATE,0,XENO_HEADTILT_GIMBALL); |
| | 3813 | xenoStatusPointer->UseHeadLaser = 0; |
| | 3814 | xenoStatusPointer->UseRALaser = 1; |
| | 3815 | xenoStatusPointer->UseLALaser = 1; |
| | 3816 | xenoStatusPointer->FiringLeft = 1; |
| | 3817 | xenoStatusPointer->FiringRight = 1; |
| | 3818 | } |
| | 3819 | |
| | 3820 | static void Execute_Xeno_ShootTheRoof(STRATEGYBLOCK *sbPtr) |
| | 3821 | { |
| | 3822 | int anglex,angley; |
| | 3823 | |
| | 3824 | assert(sbPtr); |
| | 3825 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3826 | assert(xenoStatusPointer); |
| | 3827 | |
| | 3828 | /* Do we have a target? */ |
| | 3829 | |
| | 3830 | #if ShowXenoStats |
| | 3831 | printf("In Shoot The Roof.\n"); |
| | 3832 | #endif |
| | 3833 | |
| | 3834 | if ((xenoStatusPointer->Target == NULL) || xenoStatusPointer->IAmFar) |
| | 3835 | { |
| | 3836 | Xeno_Enter_ActiveWait_State(sbPtr); |
| | 3837 | /* Otherwise just wait? */ |
| | 3838 | return; |
| | 3839 | } |
| | 3840 | |
| | 3841 | /* Now we have a target. */ |
| | 3842 | assert(xenoStatusPointer->Target); |
| | 3843 | |
| | 3844 | /* Set up animation... Which Way? Keep TurnToFace functionality? */ |
| | 3845 | { |
| | 3846 | VECTORCH orientationDirn; |
| | 3847 | SECTION_DATA *master_section = GetThisSectionData(xenoStatusPointer->HModelController.section_data,"pelvis presley"); |
| | 3848 | assert(master_section); |
| | 3849 | |
| | 3850 | Xenoborg_GetRelativeAngles(sbPtr,&anglex,&angley,&master_section->World_Offset); |
| | 3851 | |
| | 3852 | anglex = 512; |
| | 3853 | |
| | 3854 | if (anglex > 0) |
| | 3855 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Right,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); |
| | 3856 | else |
| | 3857 | EnforceXenoborgShapeAnimSequence_Core(sbPtr,HMSQT_Xenoborg,XBSS_Turn_Left,XENO_TURNING_ANIM_SPEED,(ONE_FIXED>>2)); |
| | 3858 | |
| | 3859 | /* Synthesize a new orientationDirn. */ |
| | 3860 | orientationDirn.vx = sbPtr->DynPtr->OrientMat.mat11; |
| | 3861 | orientationDirn.vy = sbPtr->DynPtr->OrientMat.mat12; |
| | 3862 | orientationDirn.vz = sbPtr->DynPtr->OrientMat.mat13; |
| | 3863 | int correctlyOrientated = NPCOrientateToVector(sbPtr, &orientationDirn, (NPC_TURNRATE >> XENO_FOOT_TURN_RATE)); |
| | 3864 | } |
| | 3865 | |
| | 3866 | Xeno_Limbs_ShootTheRoof(sbPtr); |
| | 3867 | |
| | 3868 | if (angley < XENO_HEADTILT_GIMBALL) |
| | 3869 | Xeno_Enter_TurnToFace_State(sbPtr); |
| | 3870 | } |
| | 3871 | |
| | 3872 | void XenoborgBehaviour(STRATEGYBLOCK *sbPtr) |
| | 3873 | { |
| | 3874 | int xenoborgIsNear = 0; |
| | 3875 | |
| | 3876 | assert(sbPtr); |
| | 3877 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 3878 | assert(xenoStatusPointer); |
| | 3879 | |
| | 3880 | const NPC_DATA *NpcData = &NpcDataList[I_NPC_Xenoborg]; |
| | 3881 | |
| | 3882 | /* test if we've got a containing module: if we haven't, do nothing. |
| | 3883 | This is important as the object could have been marked for deletion by the visibility |
| | 3884 | management system...*/ |
| | 3885 | |
| | 3886 | if(!sbPtr->containingModule) |
| | 3887 | { |
| | 3888 | sbPtr->please_destroy_me = 1; |
| | 3889 | return; |
| | 3890 | } |
| | 3891 | |
| | 3892 | if(sbPtr->DisplayBlock) |
| | 3893 | { |
| | 3894 | xenoborgIsNear = 1; |
| | 3895 | assert(ModuleCurrVisArray[sbPtr->containingModule->m_index]); |
| | 3896 | } |
| | 3897 | |
| | 3898 | VerifyDeltaControllers(sbPtr); |
| | 3899 | |
| | 3900 | InitWaypointSystem(0); |
| | 3901 | |
| | 3902 | xenoStatusPointer->IAmFar = !xenoborgIsNear; |
| | 3903 | |
| | 3904 | /* Store angles. */ |
| | 3905 | xenoStatusPointer->Old_Head_Pan = xenoStatusPointer->Head_Pan; |
| | 3906 | xenoStatusPointer->Old_Head_Tilt = xenoStatusPointer->Head_Tilt; |
| | 3907 | xenoStatusPointer->Old_Left_Arm_Pan = xenoStatusPointer->Left_Arm_Pan; |
| | 3908 | xenoStatusPointer->Old_Left_Arm_Tilt = xenoStatusPointer->Left_Arm_Tilt; |
| | 3909 | xenoStatusPointer->Old_Right_Arm_Pan = xenoStatusPointer->Right_Arm_Pan; |
| | 3910 | xenoStatusPointer->Old_Right_Arm_Tilt = xenoStatusPointer->Right_Arm_Tilt; |
| | 3911 | xenoStatusPointer->Old_Torso_Twist = xenoStatusPointer->Torso_Twist; |
| | 3912 | |
| | 3913 | xenoStatusPointer->head_moving = 0; |
| | 3914 | xenoStatusPointer->la_moving = 0; |
| | 3915 | xenoStatusPointer->ra_moving = 0; |
| | 3916 | xenoStatusPointer->torso_moving = 0; |
| | 3917 | |
| | 3918 | xenoStatusPointer->FiringLeft = 0; |
| | 3919 | xenoStatusPointer->FiringRight = 0; |
| | 3920 | xenoStatusPointer->UseHeadLaser = 0; |
| | 3921 | xenoStatusPointer->UseLALaser= 0; |
| | 3922 | xenoStatusPointer->UseRALaser = 0; |
| | 3923 | xenoStatusPointer->LeftMainBeam.BeamIsOn = 0; |
| | 3924 | xenoStatusPointer->RightMainBeam.BeamIsOn = 0; |
| | 3925 | xenoStatusPointer->TargetingLaser[0].BeamIsOn = 0; |
| | 3926 | xenoStatusPointer->TargetingLaser[1].BeamIsOn = 0; |
| | 3927 | xenoStatusPointer->TargetingLaser[2].BeamIsOn = 0; |
| | 3928 | |
| | 3929 | if (xenoStatusPointer->Target == NULL) |
| | 3930 | { |
| | 3931 | if (xenoborgIsNear || xenoStatusPointer->incidentFlag) |
| | 3932 | { |
| | 3933 | /* Get new target. */ |
| | 3934 | xenoStatusPointer->Target = Xenoborg_GetNewTarget(&sbPtr->DynPtr->Position, sbPtr); |
| | 3935 | xenoStatusPointer->targetSightTest = 0; |
| | 3936 | |
| | 3937 | if (xenoStatusPointer->Target) |
| | 3938 | { |
| | 3939 | COPY_NAME(xenoStatusPointer->Target_SBname, xenoStatusPointer->Target->SBname); |
| | 3940 | xenoStatusPointer->targetSightTest = 1; |
| | 3941 | GetTargetingPointOfObject_Far(xenoStatusPointer->Target, &xenoStatusPointer->targetTrackPos); |
| | 3942 | } |
| | 3943 | else |
| | 3944 | { |
| | 3945 | xenoStatusPointer->targetTrackPos.vx = xenoStatusPointer->targetTrackPos.vy = xenoStatusPointer->targetTrackPos.vz = 0; |
| | 3946 | } |
| | 3947 | |
| | 3948 | xenoStatusPointer->headLock = 0; |
| | 3949 | xenoStatusPointer->leftArmLock = 0; |
| | 3950 | xenoStatusPointer->rightArmLock = 0; |
| | 3951 | } |
| | 3952 | } |
| | 3953 | else |
| | 3954 | { |
| | 3955 | if (NPC_IsDead(xenoStatusPointer->Target) || !NAME_ISEQUAL(xenoStatusPointer->Target->SBname, xenoStatusPointer->Target_SBname)) |
| | 3956 | { |
| | 3957 | xenoStatusPointer->Target = NULL; |
| | 3958 | } |
| | 3959 | else |
| | 3960 | { |
| | 3961 | if(NPCCanSeeTarget(sbPtr, xenoStatusPointer->Target)) |
| | 3962 | { |
| | 3963 | GetTargetingPointOfObject_Far(xenoStatusPointer->Target, &xenoStatusPointer->targetTrackPos); |
| | 3964 | xenoStatusPointer->targetSightTest = 1; |
| | 3965 | } |
| | 3966 | else |
| | 3967 | { |
| | 3968 | /* We have a target that we can't see. */ |
| | 3969 | xenoStatusPointer->headLock = 0; |
| | 3970 | xenoStatusPointer->leftArmLock = 0; |
| | 3971 | xenoStatusPointer->rightArmLock = 0; |
| | 3972 | xenoStatusPointer->targetSightTest = 0; |
| | 3973 | } |
| | 3974 | } |
| | 3975 | } |
| | 3976 | |
| | 3977 | xenoStatusPointer->incidentFlag = 0; |
| | 3978 | xenoStatusPointer->incidentTimer -= NormalFrameTime; |
| | 3979 | |
| | 3980 | if (xenoStatusPointer->incidentTimer < 0) |
| | 3981 | { |
| | 3982 | xenoStatusPointer->incidentFlag = 1; |
| | 3983 | xenoStatusPointer->incidentTimer = 32767 + (FastRandom() & 65535); |
| | 3984 | } |
| | 3985 | |
| | 3986 | if (sbPtr->DamageBlock.IsOnFire) |
| | 3987 | { |
| | 3988 | /* Why not? */ |
| | 3989 | CauseDamageToObject(sbPtr, &damage_profiles[FIREDAMAGE], NormalFrameTime, NULL); |
| | 3990 | |
| | 3991 | if (sbPtr->type == I_BehaviourCorpse) |
| | 3992 | return; /* Gettin' out of here... */ |
| | 3993 | |
| | 3994 | if (xenoStatusPointer->incidentFlag) |
| | 3995 | { |
| | 3996 | if ((FastRandom() & 65535) < 32767) |
| | 3997 | sbPtr->DamageBlock.IsOnFire = 0; |
| | 3998 | } |
| | 3999 | } |
| | 4000 | |
| | 4001 | switch (xenoStatusPointer->behaviourState) |
| | 4002 | { |
| | 4003 | case XS_ActiveWait: |
| | 4004 | if (xenoStatusPointer->IAmFar) |
| | 4005 | Execute_Xeno_ActiveWait_Far(sbPtr); |
| | 4006 | else |
| | 4007 | Execute_Xeno_ActiveWait(sbPtr); |
| | 4008 | break; |
| | 4009 | case XS_TurnToFace: |
| | 4010 | if (xenoStatusPointer->IAmFar) |
| | 4011 | Execute_Xeno_TurnToFace_Far(sbPtr); |
| | 4012 | else |
| | 4013 | Execute_Xeno_TurnToFace(sbPtr); |
| | 4014 | break; |
| | 4015 | case XS_Following: |
| | 4016 | if (xenoStatusPointer->IAmFar) |
| | 4017 | Execute_Xeno_Follow_Far(sbPtr); |
| | 4018 | else |
| | 4019 | Execute_Xeno_Follow(sbPtr); |
| | 4020 | break; |
| | 4021 | case XS_Returning: |
| | 4022 | if (xenoStatusPointer->IAmFar) |
| | 4023 | Execute_Xeno_Return_Far(sbPtr); |
| | 4024 | else |
| | 4025 | Execute_Xeno_Return(sbPtr); |
| | 4026 | break; |
| | 4027 | case XS_Avoidance: |
| | 4028 | if (xenoStatusPointer->IAmFar) |
| | 4029 | Execute_Xeno_Avoidance_Far(sbPtr); |
| | 4030 | else |
| | 4031 | Execute_Xeno_Avoidance(sbPtr); |
| | 4032 | break; |
| | 4033 | case XS_Inactive: |
| | 4034 | Execute_Xeno_Inactive(sbPtr); |
| | 4035 | break; |
| | 4036 | case XS_Activating: |
| | 4037 | Execute_Xeno_PowerUp(sbPtr); |
| | 4038 | break; |
| | 4039 | case XS_Deactivating: |
| | 4040 | Execute_Xeno_PowerDown(sbPtr); |
| | 4041 | break; |
| | 4042 | case XS_Dying: |
| | 4043 | Execute_Xeno_Dying(sbPtr); |
| | 4044 | break; |
| | 4045 | case XS_ShootingTheRoof: |
| | 4046 | Execute_Xeno_ShootTheRoof(sbPtr); |
| | 4047 | break; |
| | 4048 | case XS_Regenerating: |
| | 4049 | default: |
| | 4050 | /* No action? */ |
| | 4051 | break; |
| | 4052 | } |
| | 4053 | |
| | 4054 | switch(xenoStatusPointer->behaviourState) |
| | 4055 | { |
| | 4056 | case XS_Dying: |
| | 4057 | /* if we have actually died, we need to remove the strategyblock... so do this here */ |
| | 4058 | if (xenoStatusPointer->stateTimer <= 0) |
| | 4059 | sbPtr->please_destroy_me = 1; |
| | 4060 | break; |
| | 4061 | case XS_Inactive: |
| | 4062 | case XS_Activating: |
| | 4063 | case XS_Deactivating: |
| | 4064 | break; |
| | 4065 | default: |
| | 4066 | { |
| | 4067 | /* Time to regenerate? */ |
| | 4068 | if ((sbPtr->DamageBlock.Health < (NpcData->StartingStats.Health << (ONE_FIXED_SHIFT-2))) && (sbPtr->DamageBlock.Health
> 0)) |
| | 4069 | { |
| | 4070 | /* 25% health or less. */ |
| | 4071 | Xeno_Enter_PowerDown_State(sbPtr); |
| | 4072 | } |
| | 4073 | } |
| | 4074 | } |
| | 4075 | |
| | 4076 | ComputeDeltaValues(sbPtr); |
| | 4077 | |
| | 4078 | ProveHModel_Far(&xenoStatusPointer->HModelController, sbPtr); |
| | 4079 | |
| | 4080 | Xeno_MaintainSounds(sbPtr); |
| | 4081 | |
| | 4082 | if (xenoStatusPointer->IAmFar) |
| | 4083 | { |
| | 4084 | /* No lasers if far. */ |
| | 4085 | xenoStatusPointer->UseHeadLaser = 0; |
| | 4086 | xenoStatusPointer->UseLALaser = 0; |
| | 4087 | xenoStatusPointer->UseRALaser = 0; |
| | 4088 | |
| | 4089 | #if FAR_XENO_FIRING |
| | 4090 | xenoStatusPointer->FiringLeft = 0; |
| | 4091 | xenoStatusPointer->FiringRight = 0; |
| | 4092 | #endif |
| | 4093 | } |
| | 4094 | |
| | 4095 | /* Now consider the lasers. */ |
| | 4096 | Xeno_MaintainLasers(sbPtr); |
| | 4097 | Xeno_Stomp(sbPtr); |
| | 4098 | |
| | 4099 | /* Now, are we firing? */ |
| | 4100 | Xenoborg_MaintainLeftGun(sbPtr); |
| | 4101 | Xenoborg_MaintainRightGun(sbPtr); |
| | 4102 | |
| | 4103 | /* Unset shot flag. */ |
| | 4104 | xenoStatusPointer->ShotThisFrame = 0; |
| | 4105 | } |
| | 4106 | |
| | 4107 | void MakeXenoborgFar(STRATEGYBLOCK *sbPtr) |
| | 4108 | { |
| | 4109 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4110 | assert(xenoStatusPointer); |
| | 4111 | |
| | 4112 | DestroyActiveObject(&sbPtr->DisplayBlock); |
| | 4113 | |
| | 4114 | /* xenoborg data block init */ |
| | 4115 | if(xenoStatusPointer->behaviourState != XS_Dying) |
| | 4116 | xenoStatusPointer->stateTimer = 0; |
| | 4117 | |
| | 4118 | /* zero linear velocity in dynamics block */ |
| | 4119 | sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0; |
| | 4120 | |
| | 4121 | xenoStatusPointer->IAmFar = 1; |
| | 4122 | } |
| | 4123 | |
| | 4124 | static void KillXeno(STRATEGYBLOCK *sbPtr, int wounds, const DAMAGE_PROFILE *damage, int multiple, VECTORCH *incoming) |
| | 4125 | { |
| | 4126 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4127 | int GibbFactor = 0; |
| | 4128 | |
| | 4129 | Sound_Play(SID_SENTRYGUNDEST, "d", &sbPtr->DynPtr->Position); |
| | 4130 | |
| | 4131 | xenoStatusPointer->stateTimer = XENO_DYINGTIME; |
| | 4132 | xenoStatusPointer->HModelController.Looped = 0; |
| | 4133 | xenoStatusPointer->HModelController.LoopAfterTweening = 0; |
| | 4134 | xenoStatusPointer->behaviourState = XS_Dying; |
| | 4135 | |
| | 4136 | Xenoborg_DeactivateAllDeltas(sbPtr); |
| | 4137 | Xeno_SwitchLED(sbPtr, 0); |
| | 4138 | |
| | 4139 | if(xenoStatusPointer->death_target_sbptr) |
| | 4140 | RequestState(xenoStatusPointer->death_target_sbptr, xenoStatusPointer->death_target_request, 0); |
| | 4141 | |
| | 4142 | if (xenoStatusPointer->soundHandle1 != SOUND_NOACTIVEINDEX) |
| | 4143 | Sound_Stop(xenoStatusPointer->soundHandle1); |
| | 4144 | |
| | 4145 | if (xenoStatusPointer->soundHandle2 != SOUND_NOACTIVEINDEX) |
| | 4146 | Sound_Stop(xenoStatusPointer->soundHandle2); |
| | 4147 | |
| | 4148 | if (xenoStatusPointer->head_whirr != SOUND_NOACTIVEINDEX) |
| | 4149 | Sound_Stop(xenoStatusPointer->head_whirr); |
| | 4150 | |
| | 4151 | if (xenoStatusPointer->left_arm_whirr != SOUND_NOACTIVEINDEX) |
| | 4152 | Sound_Stop(xenoStatusPointer->left_arm_whirr); |
| | 4153 | |
| | 4154 | if (xenoStatusPointer->right_arm_whirr != SOUND_NOACTIVEINDEX) |
| | 4155 | Sound_Stop(xenoStatusPointer->right_arm_whirr); |
| | 4156 | |
| | 4157 | if (xenoStatusPointer->torso_whirr != SOUND_NOACTIVEINDEX) |
| | 4158 | Sound_Stop(xenoStatusPointer->torso_whirr); |
| | 4159 | |
| | 4160 | int tkd = TotalKineticDamage(damage); |
| | 4161 | int deathtype = 0; |
| | 4162 | |
| | 4163 | if (tkd > 40) |
| | 4164 | { |
| | 4165 | /* Explosion case. */ |
| | 4166 | if (MUL_FIXED(tkd, (multiple & ((ONE_FIXED << 1) -1))) > 20) |
| | 4167 | { |
| | 4168 | /* Okay, you can gibb now. */ |
| | 4169 | GibbFactor = -(ONE_FIXED >> 3); |
| | 4170 | deathtype = 2; |
| | 4171 | } |
| | 4172 | } |
| | 4173 | else if ( (multiple>>16)>1 ) |
| | 4174 | { |
| | 4175 | int temp = MUL_FIXED(tkd, DIV_FIXED(multiple, NormalFrameTime)); |
| | 4176 | |
| | 4177 | if (temp > 700) |
| | 4178 | { |
| | 4179 | /* Excessive bullets case 1. */ |
| | 4180 | GibbFactor = -(ONE_FIXED >> 5); |
| | 4181 | deathtype = 2; |
| | 4182 | } |
| | 4183 | else if (temp > 250) |
| | 4184 | { |
| | 4185 | /* Excessive bullets case 2. */ |
| | 4186 | //GibbFactor = ONE_FIXED >> 6; |
| | 4187 | deathtype = 1; |
| | 4188 | } |
| | 4189 | } |
| | 4190 | |
| | 4191 | if (tkd > 200) |
| | 4192 | { |
| | 4193 | /* Basically SADARS only. */ |
| | 4194 | GibbFactor = ONE_FIXED >> 2; |
| | 4195 | deathtype = 3; |
| | 4196 | } |
| | 4197 | |
| | 4198 | { |
| | 4199 | SECTION_DATA *chest = GetThisSectionData(xenoStatusPointer->HModelController.section_data, "chest"); |
| | 4200 | |
| | 4201 | if (chest == NULL) |
| | 4202 | { |
| | 4203 | /* I'm impressed. */ |
| | 4204 | deathtype += 2; |
| | 4205 | } |
| | 4206 | else if ((chest->flags & section_data_notreal) && (chest->flags & section_data_terminate_here)) |
| | 4207 | { |
| | 4208 | /* That's gotta hurt. */ |
| | 4209 | deathtype++; |
| | 4210 | } |
| | 4211 | } |
| | 4212 | |
| | 4213 | if (GibbFactor > 0) // put this into use? |
| | 4214 | Extreme_Gibbing(sbPtr, xenoStatusPointer->HModelController.section_data, GibbFactor, incoming); |
| | 4215 | |
| | 4216 | { |
| | 4217 | HIT_FACING facing = { 0,0,0,0 }; |
| | 4218 | |
| | 4219 | if (incoming) |
| | 4220 | { |
| | 4221 | if (incoming->vz > 0) |
| | 4222 | facing.Back = 1; |
| | 4223 | else |
| | 4224 | facing.Front = 1; |
| | 4225 | |
| | 4226 | if (incoming->vx > 0) |
| | 4227 | facing.Right = 1; |
| | 4228 | else |
| | 4229 | facing.Left = 1; |
| | 4230 | } |
| | 4231 | |
| | 4232 | DEATH_DATA *this_death = GetDeathSequence(&xenoStatusPointer->HModelController,NULL, xenoStatusPointer->Wounds, |
| | 4233 | (xenoStatusPointer->Wounds&( section_flag_left_leg|section_flag_right_leg|section_flag_left_foot|section_flag_right_foot)), deathtype,
&facing,0,0,0, 4); |
| | 4234 | |
| | 4235 | assert(this_death); |
| | 4236 | |
| | 4237 | Convert_Xenoborg_To_Corpse(sbPtr,this_death); |
| | 4238 | } |
| | 4239 | } |
| | 4240 | |
| | 4241 | void XenoborgIsDamaged(STRATEGYBLOCK *sbPtr, const DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming) |
| | 4242 | { |
| | 4243 | assert(sbPtr); |
| | 4244 | assert(sbPtr->DynPtr); |
| | 4245 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4246 | assert(xenoStatusPointer); |
| | 4247 | |
| | 4248 | xenoStatusPointer->Wounds |= wounds; |
| | 4249 | xenoStatusPointer->ShotThisFrame = 1; |
| | 4250 | |
| | 4251 | if (sbPtr->DamageBlock.Health <= 0) |
| | 4252 | { |
| | 4253 | /* Oh yes, kill them, too. */ |
| | 4254 | if (xenoStatusPointer->behaviourState != XS_Dying) |
| | 4255 | { |
| | 4256 | CurrentGameStats_CreatureKilled(sbPtr, NULL); |
| | 4257 | KillXeno(sbPtr, wounds, damage, multiple, incoming); |
| | 4258 | } |
| | 4259 | } |
| | 4260 | |
| | 4261 | if (xenoStatusPointer->behaviourState == XS_Inactive) |
| | 4262 | { |
| | 4263 | if (xenoStatusPointer->stateTimer >= XENO_POWERDOWN_TIME) |
| | 4264 | Xeno_Enter_PowerUp_State(sbPtr); /* Ow, that hurt. */ |
| | 4265 | } |
| | 4266 | |
| | 4267 | xenoStatusPointer->Target = NULL; |
| | 4268 | } |
| | 4269 | |
| | 4270 | static void Xeno_LeftArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate) |
| | 4271 | { |
| | 4272 | assert(sbPtr); |
| | 4273 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4274 | assert(xenoStatusPointer); |
| | 4275 | |
| | 4276 | /* Let's wave the left arm around. */ |
| | 4277 | if (xenoStatusPointer->leftarmtiltdir) |
| | 4278 | { |
| | 4279 | xenoStatusPointer->Left_Arm_Tilt += (NormalFrameTime>>rate); |
| | 4280 | |
| | 4281 | if (xenoStatusPointer->Left_Arm_Tilt > (XENO_ARM_PITCH_GIMBALL<<4)) |
| | 4282 | { |
| | 4283 | xenoStatusPointer->Left_Arm_Tilt = (XENO_ARM_PITCH_GIMBALL<<4); |
| | 4284 | xenoStatusPointer->leftarmtiltdir = 0; |
| | 4285 | } |
| | 4286 | else |
| | 4287 | { |
| | 4288 | xenoStatusPointer->la_moving = 1; |
| | 4289 | } |
| | 4290 | } |
| | 4291 | else |
| | 4292 | { |
| | 4293 | xenoStatusPointer->Left_Arm_Tilt -= (NormalFrameTime>>rate); |
| | 4294 | |
| | 4295 | if (xenoStatusPointer->Left_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL<<4)) |
| | 4296 | { |
| | 4297 | xenoStatusPointer->Left_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL<<4); |
| | 4298 | xenoStatusPointer->leftarmtiltdir = 1; |
| | 4299 | } |
| | 4300 | else |
| | 4301 | { |
| | 4302 | xenoStatusPointer->la_moving = 1; |
| | 4303 | } |
| | 4304 | } |
| | 4305 | |
| | 4306 | if (xenoStatusPointer->left_arm_tilt) |
| | 4307 | xenoStatusPointer->left_arm_tilt->Active = 1; |
| | 4308 | } |
| | 4309 | |
| | 4310 | static void Xeno_RightArmMovement_TrackUpDown(STRATEGYBLOCK *sbPtr,int rate) |
| | 4311 | { |
| | 4312 | assert(sbPtr); |
| | 4313 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4314 | assert(xenoStatusPointer); |
| | 4315 | |
| | 4316 | /* Let's wave the Right arm around. */ |
| | 4317 | if (xenoStatusPointer->rightarmtiltdir) |
| | 4318 | { |
| | 4319 | xenoStatusPointer->Right_Arm_Tilt += (NormalFrameTime >> rate); |
| | 4320 | |
| | 4321 | if (xenoStatusPointer->Right_Arm_Tilt > (XENO_ARM_PITCH_GIMBALL<<4)) |
| | 4322 | { |
| | 4323 | xenoStatusPointer->Right_Arm_Tilt = (XENO_ARM_PITCH_GIMBALL<<4); |
| | 4324 | xenoStatusPointer->rightarmtiltdir = 0; |
| | 4325 | } |
| | 4326 | else |
| | 4327 | { |
| | 4328 | xenoStatusPointer->ra_moving = 1; |
| | 4329 | } |
| | 4330 | } |
| | 4331 | else |
| | 4332 | { |
| | 4333 | xenoStatusPointer->Right_Arm_Tilt -= (NormalFrameTime >> rate); |
| | 4334 | |
| | 4335 | if (xenoStatusPointer->Right_Arm_Tilt < -(XENO_ARM_PITCH_GIMBALL << 4)) |
| | 4336 | { |
| | 4337 | xenoStatusPointer->Right_Arm_Tilt = -(XENO_ARM_PITCH_GIMBALL << 4); |
| | 4338 | xenoStatusPointer->rightarmtiltdir = 1; |
| | 4339 | } |
| | 4340 | else |
| | 4341 | { |
| | 4342 | xenoStatusPointer->ra_moving = 1; |
| | 4343 | } |
| | 4344 | } |
| | 4345 | |
| | 4346 | if (xenoStatusPointer->right_arm_tilt) |
| | 4347 | xenoStatusPointer->right_arm_tilt->Active = 1; |
| | 4348 | } |
| | 4349 | |
| | 4350 | static void Xeno_TorsoMovement_TrackLeftRight(STRATEGYBLOCK *sbPtr,int rate) |
| | 4351 | { |
| | 4352 | assert(sbPtr); |
| | 4353 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4354 | assert(xenoStatusPointer); |
| | 4355 | |
| | 4356 | /* Let's twist the torso. */ |
| | 4357 | if (xenoStatusPointer->torsotwistdir) |
| | 4358 | { |
| | 4359 | xenoStatusPointer->Torso_Twist += (NormalFrameTime >> rate); |
| | 4360 | |
| | 4361 | if (xenoStatusPointer->Torso_Twist > (XENO_TORSO_GIMBALL<<4)) |
| | 4362 | { |
| | 4363 | xenoStatusPointer->Torso_Twist = (XENO_TORSO_GIMBALL<<4); |
| | 4364 | xenoStatusPointer->torsotwistdir = 0; |
| | 4365 | } |
| | 4366 | else |
| | 4367 | { |
| | 4368 | xenoStatusPointer->torso_moving = 1; |
| | 4369 | } |
| | 4370 | } |
| | 4371 | else |
| | 4372 | { |
| | 4373 | xenoStatusPointer->Torso_Twist -= (NormalFrameTime >> rate); |
| | 4374 | |
| | 4375 | if (xenoStatusPointer->Torso_Twist<-(XENO_TORSO_GIMBALL<<4)) |
| | 4376 | { |
| | 4377 | xenoStatusPointer->Torso_Twist = -(XENO_TORSO_GIMBALL<<4); |
| | 4378 | xenoStatusPointer->torsotwistdir = 1; |
| | 4379 | } |
| | 4380 | else |
| | 4381 | { |
| | 4382 | xenoStatusPointer->torso_moving = 1; |
| | 4383 | } |
| | 4384 | } |
| | 4385 | |
| | 4386 | if (xenoStatusPointer->right_arm_tilt) |
| | 4387 | xenoStatusPointer->right_arm_tilt->Active = 1; |
| | 4388 | } |
| | 4389 | |
| | 4390 | int XenoSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset) |
| | 4391 | { |
| | 4392 | assert(sbPtr); |
| | 4393 | XENO_STATUS_BLOCK *xenoStatusPointer = (XENO_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 4394 | assert(xenoStatusPointer); |
| | 4395 | |
| | 4396 | if (localOffset->vx > 0) |
| | 4397 | { |
| | 4398 | /* 180 horizontal, 180 vertical. */ |
| | 4399 | return 1; |
| | 4400 | } |
| | 4401 | else |
| | 4402 | { |
| | 4403 | return (xenoStatusPointer->Target || xenoStatusPointer->ShotThisFrame); |
| | 4404 | } |
| | 4405 | } |
| | 4406 | |
| | 4407 | /*--------------------** |
| | 4408 | ** Loading and Saving ** |
| | 4409 | **--------------------*/ |
| | 4410 | #include "savegame.h" |
| | 4411 | |
| | 4412 | typedef struct xenoborg_save_block |
| | 4413 | { |
| | 4414 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 4415 | |
| | 4416 | //behaviour block stuff |
| | 4417 | XENO_BHSTATE behaviourState; |
| | 4418 | XENO_BHSTATE lastState; |
| | 4419 | int stateTimer; |
| | 4420 | NPC_WANDERDATA wanderData; |
| | 4421 | NPC_OBSTRUCTIONREPORT obstruction; |
| | 4422 | VECTORCH my_spot_therin; |
| | 4423 | VECTORCH my_orientdir_therin; |
| | 4424 | int module_range; |
| | 4425 | int UpTime; |
| | 4426 | int Wounds; |
| | 4427 | |
| | 4428 | VECTORCH targetTrackPos; |
| | 4429 | |
| | 4430 | int Head_Pan; |
| | 4431 | int Head_Tilt; |
| | 4432 | int Left_Arm_Pan; |
| | 4433 | int Left_Arm_Tilt; |
| | 4434 | int Right_Arm_Pan; |
| | 4435 | int Right_Arm_Tilt; |
| | 4436 | int Torso_Twist; |
| | 4437 | |
| | 4438 | int Old_Head_Pan; |
| | 4439 | int Old_Head_Tilt; |
| | 4440 | int Old_Left_Arm_Pan; |
| | 4441 | int Old_Left_Arm_Tilt; |
| | 4442 | int Old_Right_Arm_Pan; |
| | 4443 | int Old_Right_Arm_Tilt; |
| | 4444 | int Old_Torso_Twist; |
| | 4445 | |
| | 4446 | LASER_BEAM_DESC LeftMainBeam; |
| | 4447 | LASER_BEAM_DESC RightMainBeam; |
| | 4448 | LASER_BEAM_DESC TargetingLaser[3]; |
| | 4449 | |
| | 4450 | unsigned int headpandir :1; |
| | 4451 | unsigned int headtiltdir :1; |
| | 4452 | unsigned int leftarmpandir :1; |
| | 4453 | unsigned int leftarmtiltdir :1; |
| | 4454 | unsigned int rightarmpandir :1; |
| | 4455 | unsigned int rightarmtiltdir :1; |
| | 4456 | unsigned int torsotwistdir :1; |
| | 4457 | |
| | 4458 | unsigned int headLock :1; |
| | 4459 | unsigned int leftArmLock :1; |
| | 4460 | unsigned int rightArmLock :1; |
| | 4461 | unsigned int targetSightTest :1; |
| | 4462 | unsigned int IAmFar :1; |
| | 4463 | unsigned int ShotThisFrame :1; |
| | 4464 | |
| | 4465 | unsigned int FiringLeft :1; |
| | 4466 | unsigned int FiringRight :1; |
| | 4467 | |
| | 4468 | unsigned int UseHeadLaser :1; |
| | 4469 | unsigned int UseLALaser :1; |
| | 4470 | unsigned int UseRALaser :1; |
| | 4471 | |
| | 4472 | unsigned int HeadLaserOnTarget :1; |
| | 4473 | unsigned int LALaserOnTarget :1; |
| | 4474 | unsigned int RALaserOnTarget :1; |
| | 4475 | |
| | 4476 | unsigned int head_moving :1; |
| | 4477 | unsigned int la_moving :1; |
| | 4478 | unsigned int ra_moving :1; |
| | 4479 | unsigned int torso_moving :1; |
| | 4480 | |
| | 4481 | int incidentFlag; |
| | 4482 | int incidentTimer; |
| | 4483 | |
| | 4484 | int head_whirr; |
| | 4485 | int left_arm_whirr; |
| | 4486 | int right_arm_whirr; |
| | 4487 | int torso_whirr; |
| | 4488 | |
| | 4489 | //annoying pointer related things |
| | 4490 | int my_module_index; |
| | 4491 | |
| | 4492 | char Target_SBname[SB_NAME_LENGTH]; |
| | 4493 | |
| | 4494 | //strategyblock stuff |
| | 4495 | DAMAGEBLOCK DamageBlock; |
| | 4496 | DYNAMICSBLOCK dynamics; |
| | 4497 | |
| | 4498 | } XENOBORG_SAVE_BLOCK; |
| | 4499 | |
| | 4500 | //defines for load/save macros |
| | 4501 | #define SAVELOAD_BLOCK block |
| | 4502 | #define SAVELOAD_BEHAV xenoStatusPointer |
| | 4503 | |
| | 4504 | void LoadStrategy_Xenoborg(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 4505 | { |
| | 4506 | XENOBORG_SAVE_BLOCK* block = (XENOBORG_SAVE_BLOCK*) header; |
| | 4507 | |
| | 4508 | //check the size of the save block |
| | 4509 | if(header->size != sizeof(*block)) |
| | 4510 | return; |
| | 4511 | |
| | 4512 | //find the existing strategy block |
| | 4513 | STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname); |
| | 4514 | |
| | 4515 | if(!sbPtr) |
| | 4516 | return; |
| | 4517 | |
| | 4518 | //make sure the strategy found is of the right type |
| | 4519 | if(sbPtr->type != I_BehaviourXenoborg) |
| | 4520 | return; |
| | 4521 | |
| | 4522 | XENO_STATUS_BLOCK* xenoStatusPointer =(XENO_STATUS_BLOCK*) sbPtr->dataptr; |
| | 4523 | |
| | 4524 | //start copying stuff |
| | 4525 | COPYELEMENT_LOAD(behaviourState) |
| | 4526 | COPYELEMENT_LOAD(lastState) |
| | 4527 | COPYELEMENT_LOAD(stateTimer) |
| | 4528 | COPYELEMENT_LOAD(wanderData) |
| | 4529 | COPYELEMENT_LOAD(obstruction) |
| | 4530 | COPYELEMENT_LOAD(my_spot_therin) |
| | 4531 | COPYELEMENT_LOAD(my_orientdir_therin) |
| | 4532 | COPYELEMENT_LOAD(module_range) |
| | 4533 | COPYELEMENT_LOAD(UpTime) |
| | 4534 | COPYELEMENT_LOAD(Wounds) |
| | 4535 | COPYELEMENT_LOAD(targetTrackPos) |
| | 4536 | COPYELEMENT_LOAD(Head_Pan) |
| | 4537 | COPYELEMENT_LOAD(Head_Tilt) |
| | 4538 | COPYELEMENT_LOAD(Left_Arm_Pan) |
| | 4539 | COPYELEMENT_LOAD(Left_Arm_Tilt) |
| | 4540 | COPYELEMENT_LOAD(Right_Arm_Pan) |
| | 4541 | COPYELEMENT_LOAD(Right_Arm_Tilt) |
| | 4542 | COPYELEMENT_LOAD(Torso_Twist) |
| | 4543 | COPYELEMENT_LOAD(Old_Head_Pan) |
| | 4544 | COPYELEMENT_LOAD(Old_Head_Tilt) |
| | 4545 | COPYELEMENT_LOAD(Old_Left_Arm_Pan) |
| | 4546 | COPYELEMENT_LOAD(Old_Left_Arm_Tilt) |
| | 4547 | COPYELEMENT_LOAD(Old_Right_Arm_Pan) |
| | 4548 | COPYELEMENT_LOAD(Old_Right_Arm_Tilt) |
| | 4549 | COPYELEMENT_LOAD(Old_Torso_Twist) |
| | 4550 | COPYELEMENT_LOAD(LeftMainBeam) |
| | 4551 | COPYELEMENT_LOAD(RightMainBeam) |
| | 4552 | |
| | 4553 | COPYELEMENT_LOAD(headpandir) |
| | 4554 | COPYELEMENT_LOAD(headtiltdir) |
| | 4555 | COPYELEMENT_LOAD(leftarmpandir) |
| | 4556 | COPYELEMENT_LOAD(leftarmtiltdir) |
| | 4557 | COPYELEMENT_LOAD(rightarmpandir) |
| | 4558 | COPYELEMENT_LOAD(rightarmtiltdir) |
| | 4559 | COPYELEMENT_LOAD(torsotwistdir) |
| | 4560 | |
| | 4561 | COPYELEMENT_LOAD(headLock) |
| | 4562 | COPYELEMENT_LOAD(leftArmLock) |
| | 4563 | COPYELEMENT_LOAD(rightArmLock) |
| | 4564 | COPYELEMENT_LOAD(targetSightTest) |
| | 4565 | COPYELEMENT_LOAD(IAmFar) |
| | 4566 | COPYELEMENT_LOAD(ShotThisFrame) |
| | 4567 | |
| | 4568 | COPYELEMENT_LOAD(FiringLeft) |
| | 4569 | COPYELEMENT_LOAD(FiringRight) |
| | 4570 | |
| | 4571 | COPYELEMENT_LOAD(UseHeadLaser) |
| | 4572 | COPYELEMENT_LOAD(UseLALaser) |
| | 4573 | COPYELEMENT_LOAD(UseRALaser) |
| | 4574 | |
| | 4575 | COPYELEMENT_LOAD(HeadLaserOnTarget) |
| | 4576 | COPYELEMENT_LOAD(LALaserOnTarget) |
| | 4577 | COPYELEMENT_LOAD(RALaserOnTarget) |
| | 4578 | |
| | 4579 | COPYELEMENT_LOAD(head_moving) |
| | 4580 | COPYELEMENT_LOAD(la_moving) |
| | 4581 | COPYELEMENT_LOAD(ra_moving) |
| | 4582 | COPYELEMENT_LOAD(torso_moving) |
| | 4583 | |
| | 4584 | COPYELEMENT_LOAD(incidentFlag) |
| | 4585 | COPYELEMENT_LOAD(incidentTimer) |
| | 4586 | |
| | 4587 | COPYELEMENT_LOAD(head_whirr) |
| | 4588 | COPYELEMENT_LOAD(left_arm_whirr) |
| | 4589 | COPYELEMENT_LOAD(right_arm_whirr) |
| | 4590 | COPYELEMENT_LOAD(torso_whirr) |
| | 4591 | |
| | 4592 | { |
| | 4593 | int i; |
| | 4594 | for(i=0;i<3;i++) |
| | 4595 | { |
| | 4596 | COPYELEMENT_LOAD(TargetingLaser[i]) |
| | 4597 | } |
| | 4598 | } |
| | 4599 | |
| | 4600 | //load ai module pointers |
| | 4601 | xenoStatusPointer->my_module = GetPointerFromAIModuleIndex(block->my_module_index); |
| | 4602 | |
| | 4603 | //load target |
| | 4604 | COPY_NAME(xenoStatusPointer->Target_SBname,block->Target_SBname); |
| | 4605 | xenoStatusPointer->Target = FindSBWithName(xenoStatusPointer->Target_SBname); |
| | 4606 | |
| | 4607 | //copy strategy block stuff |
| | 4608 | *sbPtr->DynPtr = block->dynamics; |
| | 4609 | sbPtr->DamageBlock = block->DamageBlock; |
| | 4610 | |
| | 4611 | //load hierarchy |
| | 4612 | { |
| | 4613 | SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); |
| | 4614 | |
| | 4615 | if(hier_header) |
| | 4616 | LoadHierarchy(hier_header,&xenoStatusPointer->HModelController); |
| | 4617 | } |
| | 4618 | |
| | 4619 | //finally get the delta controller pointers |
| | 4620 | VerifyDeltaControllers(sbPtr); |
| | 4621 | |
| | 4622 | Load_SoundState(&xenoStatusPointer->soundHandle1); |
| | 4623 | Load_SoundState(&xenoStatusPointer->soundHandle2); |
| | 4624 | } |
| | 4625 | |
| | 4626 | void SaveStrategy_Xenoborg(STRATEGYBLOCK* sbPtr) |
| | 4627 | { |
| | 4628 | XENOBORG_SAVE_BLOCK* block; |
| | 4629 | |
| | 4630 | GET_STRATEGY_SAVE_BLOCK(block,sbPtr); |
| | 4631 | XENO_STATUS_BLOCK* xenoStatusPointer = (XENO_STATUS_BLOCK*) sbPtr->dataptr; |
| | 4632 | |
| | 4633 | //start copying stuff |
| | 4634 | |
| | 4635 | COPYELEMENT_SAVE(behaviourState) |
| | 4636 | COPYELEMENT_SAVE(lastState) |
| | 4637 | COPYELEMENT_SAVE(stateTimer) |
| | 4638 | COPYELEMENT_SAVE(wanderData) |
| | 4639 | COPYELEMENT_SAVE(obstruction) |
| | 4640 | COPYELEMENT_SAVE(my_spot_therin) |
| | 4641 | COPYELEMENT_SAVE(my_orientdir_therin) |
| | 4642 | COPYELEMENT_SAVE(module_range) |
| | 4643 | COPYELEMENT_SAVE(UpTime) |
| | 4644 | COPYELEMENT_SAVE(Wounds) |
| | 4645 | COPYELEMENT_SAVE(targetTrackPos) |
| | 4646 | COPYELEMENT_SAVE(Head_Pan) |
| | 4647 | COPYELEMENT_SAVE(Head_Tilt) |
| | 4648 | COPYELEMENT_SAVE(Left_Arm_Pan) |
| | 4649 | COPYELEMENT_SAVE(Left_Arm_Tilt) |
| | 4650 | COPYELEMENT_SAVE(Right_Arm_Pan) |
| | 4651 | COPYELEMENT_SAVE(Right_Arm_Tilt) |
| | 4652 | COPYELEMENT_SAVE(Torso_Twist) |
| | 4653 | COPYELEMENT_SAVE(Old_Head_Pan) |
| | 4654 | COPYELEMENT_SAVE(Old_Head_Tilt) |
| | 4655 | COPYELEMENT_SAVE(Old_Left_Arm_Pan) |
| | 4656 | COPYELEMENT_SAVE(Old_Left_Arm_Tilt) |
| | 4657 | COPYELEMENT_SAVE(Old_Right_Arm_Pan) |
| | 4658 | COPYELEMENT_SAVE(Old_Right_Arm_Tilt) |
| | 4659 | COPYELEMENT_SAVE(Old_Torso_Twist) |
| | 4660 | COPYELEMENT_SAVE(LeftMainBeam) |
| | 4661 | COPYELEMENT_SAVE(RightMainBeam) |
| | 4662 | |
| | 4663 | COPYELEMENT_SAVE(headpandir) |
| | 4664 | COPYELEMENT_SAVE(headtiltdir) |
| | 4665 | COPYELEMENT_SAVE(leftarmpandir) |
| | 4666 | COPYELEMENT_SAVE(leftarmtiltdir) |
| | 4667 | COPYELEMENT_SAVE(rightarmpandir) |
| | 4668 | COPYELEMENT_SAVE(rightarmtiltdir) |
| | 4669 | COPYELEMENT_SAVE(torsotwistdir) |
| | 4670 | |
| | 4671 | COPYELEMENT_SAVE(headLock) |
| | 4672 | COPYELEMENT_SAVE(leftArmLock) |
| | 4673 | COPYELEMENT_SAVE(rightArmLock) |
| | 4674 | COPYELEMENT_SAVE(targetSightTest) |
| | 4675 | COPYELEMENT_SAVE(IAmFar) |
| | 4676 | COPYELEMENT_SAVE(ShotThisFrame) |
| | 4677 | |
| | 4678 | COPYELEMENT_SAVE(FiringLeft) |
| | 4679 | COPYELEMENT_SAVE(FiringRight) |
| | 4680 | |
| | 4681 | COPYELEMENT_SAVE(UseHeadLaser) |
| | 4682 | COPYELEMENT_SAVE(UseLALaser) |
| | 4683 | COPYELEMENT_SAVE(UseRALaser) |
| | 4684 | |
| | 4685 | COPYELEMENT_SAVE(HeadLaserOnTarget) |
| | 4686 | COPYELEMENT_SAVE(LALaserOnTarget) |
| | 4687 | COPYELEMENT_SAVE(RALaserOnTarget) |
| | 4688 | |
| | 4689 | COPYELEMENT_SAVE(head_moving) |
| | 4690 | COPYELEMENT_SAVE(la_moving) |
| | 4691 | COPYELEMENT_SAVE(ra_moving) |
| | 4692 | COPYELEMENT_SAVE(torso_moving) |
| | 4693 | |
| | 4694 | COPYELEMENT_SAVE(incidentFlag) |
| | 4695 | COPYELEMENT_SAVE(incidentTimer) |
| | 4696 | |
| | 4697 | COPYELEMENT_SAVE(head_whirr) |
| | 4698 | COPYELEMENT_SAVE(left_arm_whirr) |
| | 4699 | COPYELEMENT_SAVE(right_arm_whirr) |
| | 4700 | COPYELEMENT_SAVE(torso_whirr) |
| | 4701 | |
| | 4702 | { |
| | 4703 | int i; |
| | 4704 | for(i=0;i<3;i++) |
| | 4705 | { |
| | 4706 | COPYELEMENT_SAVE(TargetingLaser[i]) |
| | 4707 | } |
| | 4708 | } |
| | 4709 | |
| | 4710 | //load ai module pointers |
| | 4711 | block->my_module_index = GetIndexFromAIModulePointer(xenoStatusPointer->my_module); |
| | 4712 | |
| | 4713 | //save target |
| | 4714 | COPY_NAME(block->Target_SBname,xenoStatusPointer->Target_SBname); |
| | 4715 | |
| | 4716 | //save strategy block stuff |
| | 4717 | block->dynamics = *sbPtr->DynPtr; |
| | 4718 | block->dynamics.CollisionReportPtr = 0; |
| | 4719 | block->DamageBlock = sbPtr->DamageBlock; |
| | 4720 | |
| | 4721 | //save the hierarchy |
| | 4722 | SaveHierarchy(&xenoStatusPointer->HModelController); |
| | 4723 | |
| | 4724 | Save_SoundState(&xenoStatusPointer->soundHandle1); |
| | 4725 | Save_SoundState(&xenoStatusPointer->soundHandle2); |
| | 4726 | } |