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