/* KJL 16:23:20 10/25/96 - I'm moved all the weapon stuff to the newly created weapon.c, so player.c is looking a bit bare at the moment. */ #include "3dc.h" #include "module.h" #include "inline.h" #include "stratdef.h" #include "gamedef.h" #include "bh_types.h" #include "inventry.h" #include "gameplat.h" #include "dynblock.h" #include "dynamics.h" #include "comp_shp.h" #include "weapons.h" #include "vision.h" #include "pheromon.h" #include "avpview.h" #include "particle.h" #include "scream.h" #include "savegame.h" #if SupportWindows95 #include "rebmenus.hpp" #endif #define UseLocalAssert Yes #include "ourasert.h" #include "psnd.h" #include "psndplat.h" /* for win 95 net support */ #if SupportWindows95 #include "pldnet.h" #include "pldghost.h" #include "dp_func.h" #endif #include "ShowCmds.h" #include "BonusAbilities.h" #define PLAYER_HMODEL 0 /*KJL**************************************************************************************** * G L O B A L S * ****************************************************************************************KJL*/ VECTORCH PlayerStartLocation; MATRIXCH PlayerStartMat; extern int NormalFrameTime; extern ACTIVESOUNDSAMPLE ActiveSounds[]; extern int PlayerDamagedOverlayIntensity; extern int playerNoise; extern int predHUDSoundHandle; extern int predOVision_SoundHandle; extern int AIModuleArraySize; int GimmeChargeCalls; int HtoHStrikes; int CurrentLightAtPlayer; int TauntSoundPlayed; int TrickleCharge=9000; int CloakDrain=12000; int CloakThreshold=(5*ONE_FIXED); int CloakPowerOnDrain=(2*ONE_FIXED); extern DPID myNetworkKillerId; extern DPID myIgniterId; extern int MyHitBodyPartId; extern HMODELCONTROLLER PlayersWeaponHModelController; extern SECTION_DATA *PWMFSDP; /* PlayersWeaponMuzzleFlashSectionDataPointer */ /*KJL**************************************************************************************** * P R O T O T Y P E S * ****************************************************************************************KJL*/ void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type); void MaintainPlayer(void); void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming); static void PlayerIsDead(DAMAGE_PROFILE *damage,int multiplier,VECTORCH* incoming); extern int LightIntensityAtPoint(VECTORCH *pointPtr); extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); extern int SlotForThisWeapon(enum WEAPON_ID weaponID); extern void PointAlert(int level, VECTORCH *point); extern void RemoveAllThisPlayersDiscs(void); void ShowAdjacencies(void); extern int ShowAdj; /*KJL**************************************************************************************** * F U N C T I O N S * ****************************************************************************************KJL*/ PLAYER_STATUS* PlayerStatusPtr = NULL; static PLAYER_STATUS PlayerStatusBlock; int ShowPredoStats=0; int Observer=0; /* Patrick 22/8/97------------------------------------------------ Cloaking stuff ------------------------------------------------------------------*/ void InitPlayerCloakingSystem(void); static void DoPlayerCloakingSystem(void); void InitPlayer(STRATEGYBLOCK* sbPtr, int sb_type) { /*KJL************************************************************************************** * InitPlayer() was written by me. It attaches the extra player data to the strategy block * * and fills in some initial values. * **************************************************************************************KJL*/ SECTION *root_section; PLAYER_STATUS *psPtr = &PlayerStatusBlock; GLOBALASSERT(psPtr); GLOBALASSERT(sbPtr); // set up our global PlayerStatusPtr = psPtr; sbPtr->I_SBtype = sb_type; sbPtr->SBdataptr = (void*)psPtr; InitialisePlayersInventory(psPtr); /* Initialise Player's stats */ { NPC_DATA *NpcData; NPC_TYPES PlayerType; switch(AvP.PlayerType) { case(I_Marine): { switch (AvP.Difficulty) { case I_Easy: PlayerType=I_PC_Marine_Easy; break; default: case I_Medium: PlayerType=I_PC_Marine_Medium; break; case I_Hard: PlayerType=I_PC_Marine_Hard; break; case I_Impossible: PlayerType=I_PC_Marine_Impossible; break; } #if 0 //this hmodel isn't being set up for the moment - Richard root_section=GetNamedHierarchyFromLibrary("hnpcmarine","Template"); if (!root_section) { GLOBALASSERT(0); /* Sorry, there's just no bouncing back from this one. Fix it. */ return; } #if PLAYER_HMODEL Create_HModel(&psPtr->HModelController,root_section); InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); #endif /* Doesn't matter what the sequence is... */ #endif break; } case(I_Predator): { switch (AvP.Difficulty) { case I_Easy: PlayerType=I_PC_Predator_Easy; break; default: case I_Medium: PlayerType=I_PC_Predator_Medium; break; case I_Hard: PlayerType=I_PC_Predator_Hard; break; case I_Impossible: PlayerType=I_PC_Predator_Impossible; break; } #if 0 //this hmodel isn't being set up for the moment - Richard root_section=GetNamedHierarchyFromLibrary("hnpcpredator","Template"); if (!root_section) { GLOBALASSERT(0); /* Sorry, there's just no bouncing back from this one. Fix it. */ return; } #if PLAYER_HMODEL Create_HModel(&psPtr->HModelController,root_section); InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); #endif /* Doesn't matter what the sequence is... */ #endif break; } case(I_Alien): { switch (AvP.Difficulty) { case I_Easy: PlayerType=I_PC_Alien_Easy; break; default: case I_Medium: PlayerType=I_PC_Alien_Medium; break; case I_Hard: PlayerType=I_PC_Alien_Hard; break; case I_Impossible: PlayerType=I_PC_Alien_Impossible; break; } #if 0 //this hmodel isn't being set up for the moment - Richard root_section=GetNamedHierarchyFromLibrary("hnpcalien","alien"); if (!root_section) { GLOBALASSERT(0); /* Sorry, there's just no bouncing back from this one. Fix it. */ return; } #if PLAYER_HMODEL Create_HModel(&psPtr->HModelController,root_section); InitHModelSequence(&psPtr->HModelController,0,0,ONE_FIXED); #endif /* Doesn't matter what the sequence is... */ #endif break; } default: { LOCALASSERT(1==0); break; } } NpcData=GetThisNpcData(PlayerType); LOCALASSERT(NpcData); sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; sbPtr->SBDamageBlock.IsOnFire=0; //{ // int *nptr,i; // nptr=(int *)sbPtr->SBname; // for (i=0; i<(SB_NAME_LENGTH>>2); i++) { // *nptr=FastRandom(); // nptr++; // } // sbPtr->SBname[SB_NAME_LENGTH-1]=3; /* Just to make sure... */ //} AssignNewSBName(sbPtr); } //psPtr->Health=STARTOFGAME_MARINE_HEALTH; psPtr->Energy=STARTOFGAME_MARINE_ENERGY; //psPtr->Armour=STARTOFGAME_MARINE_ARMOUR; psPtr->Encumberance.MovementMultiple=ONE_FIXED; psPtr->Encumberance.TurningMultiple=ONE_FIXED; psPtr->Encumberance.JumpingMultiple=ONE_FIXED; psPtr->Encumberance.CanCrouch=1; psPtr->Encumberance.CanRun=1; psPtr->incidentFlag=0; psPtr->incidentTimer=0; /* CDF 16/9/97 Now, those health and armour stats are those of the last cycle. */ psPtr->Health=sbPtr->SBDamageBlock.Health; psPtr->Armour=sbPtr->SBDamageBlock.Armour; psPtr->IsAlive = 1; psPtr->IHaveAPlacedAutogun = 0; psPtr->MyFaceHugger=NULL; psPtr->MyCorpse=NULL; psPtr->tauntTimer=0; TauntSoundPlayed=0; psPtr->fireTimer=0; psPtr->invulnerabilityTimer=0; /* Better safe than sorry. */ psPtr->soundHandle=SOUND_NOACTIVEINDEX; psPtr->soundHandle3=SOUND_NOACTIVEINDEX; psPtr->soundHandle4=SOUND_NOACTIVEINDEX; psPtr->soundHandle5=SOUND_NOACTIVEINDEX; psPtr->soundHandleForPredatorCloakDamaged=SOUND_NOACTIVEINDEX; InitPlayerCloakingSystem();/* Patrick 22/8/97 : Cloaking stuff */ /* KJL 12:06:01 11/14/96 - allocate dynamics block & fill from template */ sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_MARINE_PLAYER); /* for the time being get world position and orientation from the displayblock */ { DISPLAYBLOCK *dPtr = sbPtr->SBdptr; DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; GLOBALASSERT(dPtr); GLOBALASSERT(dynPtr); dynPtr->Position = PlayerStartLocation; dynPtr->OrientMat = PlayerStartMat; MatrixToEuler(&dynPtr->OrientMat,&dynPtr->OrientEuler); //dynPtr->OrientEuler = dPtr->ObEuler; dynPtr->PrevPosition = dynPtr->Position; dynPtr->PrevOrientMat = dynPtr->OrientMat; dynPtr->PrevOrientEuler = dynPtr->OrientEuler; /* let alien walk on walls & ceiling */ if (AvP.PlayerType == I_Alien) { dynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; } /* KJL 10:56:57 11/24/97 - set ObRadius to a sensible value */ dPtr->ObRadius = 1200; /* if (AvP.PlayerType == I_Alien) sbPtr->I_SBtype = I_BehaviourAlienPlayer; if (AvP.PlayerType == I_Predator) sbPtr->I_SBtype = I_BehaviourPredatorPlayer;*/ /* KJL 18:30:09 11/11/98 - datum used for falling damage */ { extern int PlayersMaxHeightWhilstNotInContactWithGround; PlayersMaxHeightWhilstNotInContactWithGround=dynPtr->Position.vy; } } /* zero inertia values */ psPtr->ForwardInertia=0; psPtr->StrafeInertia=0; psPtr->TurnInertia=0; psPtr->IsMovingInWater = 0; PlayerDamagedOverlayIntensity = 0; /* a little addition by patrick */ InitPlayerMovementData(sbPtr); /* security clearance */ psPtr->securityClearances = 0; /* thou art mortal */ psPtr->IsImmortal = 0; if (AvP.Network==I_No_Network) { SoundSys_FadeIn(); } else { SoundSys_ResetFadeLevel(); } //restore the number of saves allowed ResetNumberOfSaves(); #if SupportWindows95 //choosing a start position now occurs later on // if(AvP.Network!=I_No_Network) TeleportNetPlayerToAStartingPosition(sbPtr, 1); #endif } void ChangeToMarine() { if(AvP.Network!=I_No_Network) { AvP.PlayerType=I_Marine; NetPlayerRespawn(Player->ObStrategyBlock); InitPlayerMovementData(Player->ObStrategyBlock); Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Marine; //reorient the player { EULER e; MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat,&e); e.EulerX=0; e.EulerZ=0; CreateEulerMatrix(&e,&Player->ObStrategyBlock->DynPtr->OrientMat); TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); Player->ObStrategyBlock->DynPtr->UseStandardGravity=1; } /* CDF 15/3/99, delete all discs... */ RemoveAllThisPlayersDiscs(); } } void ChangeToAlien() { if(AvP.Network!=I_No_Network) { AvP.PlayerType=I_Alien; NetPlayerRespawn(Player->ObStrategyBlock); InitPlayerMovementData(Player->ObStrategyBlock); Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_ALIEN; netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Alien; /* CDF 15/3/99, delete all discs... */ RemoveAllThisPlayersDiscs(); } } void ChangeToPredator() { if(AvP.Network!=I_No_Network) { AvP.PlayerType=I_Predator; NetPlayerRespawn(Player->ObStrategyBlock); InitPlayerMovementData(Player->ObStrategyBlock); Player->ObStrategyBlock->DynPtr->ToppleForce=TOPPLE_FORCE_NONE; netGameData.myCharacterType=netGameData.myNextCharacterType=NGCT_Predator; //reorient the player { EULER e; MatrixToEuler(&Player->ObStrategyBlock->DynPtr->OrientMat,&e); e.EulerX=0; e.EulerZ=0; CreateEulerMatrix(&e,&Player->ObStrategyBlock->DynPtr->OrientMat); TransposeMatrixCH(&Player->ObStrategyBlock->DynPtr->OrientMat); Player->ObStrategyBlock->DynPtr->UseStandardGravity=1; } /* CDF 15/3/99, delete all discs... */ RemoveAllThisPlayersDiscs(); } } void MaintainPlayer(void) { int rand = FastRandom(); PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); if (playerStatusPtr->IsAlive) { MaintainPlayersInventory(); } if (ShowAdj) { ShowAdjacencies(); } /* Set here, as first point. */ playerNoise=0; /* Incident handling. */ playerStatusPtr->incidentFlag=0; playerStatusPtr->incidentTimer-=NormalFrameTime; if (playerStatusPtr->incidentTimer<0) { playerStatusPtr->incidentFlag=1; playerStatusPtr->incidentTimer=32767+(FastRandom()&65535); } /* CDF 9/6/98 - I can't believe this isn't done!!! */ Player->ObStrategyBlock->containingModule = playerPherModule; if (Observer) { textprint("Observer Mode...\n"); } textprint("HtoH Strikes %d\n",HtoHStrikes); DoPlayerCloakingSystem();/* Patrick 22/8/97 : Cloaking stuff */ // HandlePredatorVisionModes(); CurrentLightAtPlayer=LightIntensityAtPoint(&Player->ObStrategyBlock->DynPtr->Position); #if 1 textprint("PlayerLight %d\n",CurrentLightAtPlayer); #endif #if SupportWindows95 #if 0//UseRebMenus if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) { REBMENUS_ProcessPauseRequest(); } #else if(AvP.Network==I_No_Network) { #if 1 if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) { // go to start menu AvP.MainLoopRunning = 0; } #endif } else if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_PauseGame) { if (AvP.Network == I_Host) { TransmitEndOfGameNetMsg(); netGameData.myGameState = NGS_EndGame; } else if (AvP.Network == I_Peer) { TransmitPlayerLeavingNetMsg(); netGameData.myGameState = NGS_Leaving; } // go to start menu AvP.MainLoopRunning = 0; } #endif #endif //Update the player's invulnerabilty timer if(playerStatusPtr->invulnerabilityTimer>0) { playerStatusPtr->invulnerabilityTimer-=NormalFrameTime; if(playerStatusPtr->invulnerabilityTimer<=0) { playerStatusPtr->invulnerabilityTimer=0; } //lose invulnerability if player is firing if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FirePrimaryWeapon) { PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); if(weaponPtr->WeaponIDNumber!=WEAPON_PRED_MEDICOMP) { playerStatusPtr->invulnerabilityTimer=0; } } if(playerStatusPtr->Mvt_InputRequests.Flags.Rqst_FireSecondaryWeapon) { //not many weapons have an offensive secondary fire PLAYER_WEAPON_DATA *weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); if(weaponPtr->WeaponIDNumber == WEAPON_PULSERIFLE || weaponPtr->WeaponIDNumber == WEAPON_CUDGEL || weaponPtr->WeaponIDNumber == WEAPON_MARINE_PISTOL || weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS || weaponPtr->WeaponIDNumber == WEAPON_PRED_WRISTBLADE || weaponPtr->WeaponIDNumber == WEAPON_ALIEN_CLAW) { playerStatusPtr->invulnerabilityTimer=0; } } } if (AvP.DestructTimer>0) { extern int NormalFrameTime; AvP.DestructTimer-=NormalFrameTime; if (AvP.DestructTimer<0) AvP.DestructTimer=0; } else if (AvP.DestructTimer==0) { // ...Destruct? CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_SADAR_TOW].MaxDamage[AvP.Difficulty], 25*ONE_FIXED,NULL); // That'll learn 'em. } /* Take speed sample. */ { int speed; speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); CurrentGameStats_SpeedSample(speed,NormalFrameTime); } /* Is the player on fire? */ if (Player->ObStrategyBlock->SBDamageBlock.IsOnFire) { myNetworkKillerId=myIgniterId; CauseDamageToObject(Player->ObStrategyBlock,&firedamage,NormalFrameTime,NULL); myNetworkKillerId=AVPDPNetID; if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { if (ActiveSounds[playerStatusPtr->soundHandle3].soundIndex!=SID_FIRE) { Sound_Stop(playerStatusPtr->soundHandle3); Sound_Play(SID_FIRE,"dlev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle3,127); } else { Sound_Update3d(playerStatusPtr->soundHandle3,&(Player->ObStrategyBlock->DynPtr->Position)); } } else if (playerStatusPtr->IsAlive) { Sound_Play(SID_FIRE,"dlev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle3,127); } /* Put the fire out... */ #if 1 { int speed; /* Go out? */ speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); if (speed>22000) { /* Jumping alien. */ playerStatusPtr->fireTimer-=(NormalFrameTime*6); } else if (speed>15000) { /* Running alien. */ playerStatusPtr->fireTimer-=(NormalFrameTime<<2); } else { /* Normal bloke. */ playerStatusPtr->fireTimer-=NormalFrameTime; } if(playerStatusPtr->invulnerabilityTimer>0) { //player is invulnerable, so put him out. playerStatusPtr->fireTimer=0; } if (playerStatusPtr->fireTimer<=0) { /* Go out. */ Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; playerStatusPtr->fireTimer=0; } } #else if (playerStatusPtr->incidentFlag) { int speed; /* Go out? */ speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); if (speed>15000) { /* Running alien. */ if ((FastRandom()&65535)<13107) { Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; } } else { /* Normal bloke. */ if ((FastRandom()&65535)<3000) { Player->ObStrategyBlock->SBDamageBlock.IsOnFire=0; } } } #endif } else { if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { Sound_Stop(playerStatusPtr->soundHandle3); } } if (playerStatusPtr->IsMovingInWater) { #if 0 if (playerStatusPtr->soundHandle4==SOUND_NOACTIVEINDEX) { switch (rand % 4) { case 0: Sound_Play(SID_SPLASH1,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); break; case 1: Sound_Play(SID_SPLASH2,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); break; case 2: Sound_Play(SID_SPLASH3,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); break; default: Sound_Play(SID_SPLASH4,"dev",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle4,127); break; } } #else /* KJL 19:07:57 25/05/98 - make a noise at most every 1/4 of a sec */ if (playerStatusPtr->soundHandle4<=0) { switch (rand&3) { case 0: Sound_Play(SID_SPLASH1,"d",&(Player->ObStrategyBlock->DynPtr->Position)); break; case 1: Sound_Play(SID_SPLASH2,"d",&(Player->ObStrategyBlock->DynPtr->Position)); break; case 2: Sound_Play(SID_SPLASH3,"d",&(Player->ObStrategyBlock->DynPtr->Position)); break; default: Sound_Play(SID_SPLASH4,"d",&(Player->ObStrategyBlock->DynPtr->Position)); break; } playerStatusPtr->soundHandle4=16384; } else { playerStatusPtr->soundHandle4-=NormalFrameTime; } #endif } /* KJL 14:54:48 25/05/98 - reset water flag to zero for next frame */ playerStatusPtr->IsMovingInWater = 0; /* Taunt effects. */ if (playerStatusPtr->tauntTimer) { int ex,ey,ez; playerNoise=1; /* An actual noise, too, would probably be good. */ if (AvP.PlayerType==I_Alien) { //if (playerStatusPtr->tauntTimer>(TAUNT_LENGTH>>1)) { if (TauntSoundPlayed==0) { /* That should make sure we don't get more than one. */ if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { #if 0 Sound_Play(SID_ALIEN_SCREAM,"de",&(Player->ObStrategyBlock->DynPtr->Position),&playerStatusPtr->soundHandle); #else PlayAlienSound(0,ASC_Taunt,0,&playerStatusPtr->soundHandle,&(Player->ObStrategyBlock->DynPtr->Position)); if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_Taunt; #endif TauntSoundPlayed=1; } } /* Wave the head around? */ ex=0; ey=0; ez=0; ex=MUL_FIXED(64,GetSin(((playerStatusPtr->tauntTimer>>6)&wrap360))); ey=MUL_FIXED(128,GetSin(((playerStatusPtr->tauntTimer>>5)&wrap360))); ez=MUL_FIXED(-64,GetSin(((playerStatusPtr->tauntTimer>>5)&wrap360))); ex&=wrap360; ey&=wrap360; ez&=wrap360; HeadOrientation.EulerX=ex; HeadOrientation.EulerY=ey; HeadOrientation.EulerZ=ez; } else if (AvP.PlayerType==I_Marine) { if (TauntSoundPlayed==0) { /* That should make sure we don't get more than one. */ if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { PlayMarineScream(0,SC_Taunt,0,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Taunt; TauntSoundPlayed=1; } } } else if (AvP.PlayerType==I_Predator) { if (TauntSoundPlayed==0) { /* That should make sure we don't get more than one. */ if (playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX) { PlayPredatorSound(0,PSC_Taunt,0,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Taunt; TauntSoundPlayed=1; } } } else { GLOBALASSERT(0); } } /* Decay alien superhealth. */ if (AvP.PlayerType==I_Alien) { NPC_DATA *NpcData; switch (AvP.Difficulty) { case I_Easy: NpcData=GetThisNpcData(I_PC_Alien_Easy); break; default: case I_Medium: NpcData=GetThisNpcData(I_PC_Alien_Medium); break; case I_Hard: NpcData=GetThisNpcData(I_PC_Alien_Hard); break; case I_Impossible: NpcData=GetThisNpcData(I_PC_Alien_Impossible); break; } LOCALASSERT(NpcData); if (Player->ObStrategyBlock->SBDamageBlock.Health>(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health-=(NormalFrameTime); if (Player->ObStrategyBlock->SBDamageBlock.Health<(NpcData->StartingStats.Health<ObStrategyBlock->SBDamageBlock.Health=NpcData->StartingStats.Health<Health=Player->ObStrategyBlock->SBDamageBlock.Health; } } } void PlayerIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiplier,VECTORCH* incoming) { int rand = FastRandom(); int pitch = (rand & 255) - 128; int deltaHealth; int deltaArmour; /* access the extra data hanging off the strategy block */ PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); GLOBALASSERT(playerStatusPtr); deltaHealth=playerStatusPtr->Health-sbPtr->SBDamageBlock.Health; deltaArmour=playerStatusPtr->Armour-sbPtr->SBDamageBlock.Armour; CurrentGameStats_DamageTaken(deltaHealth,deltaArmour); /* Patrick 4/8/97-------------------------------------------------- A little hack-et to make the predator tougher in multiplayer games ------------------------------------------------------------------*/ //if((AvP.Network!=I_No_Network)&&(AvP.PlayerType==I_Predator)) damage>>=1; /* ChrisF 16/9/97 No, predators are now... wait for it... tough. */ if (playerStatusPtr->IsAlive) { #if 0 damage <<= 16; if (playerStatusPtr->Armour > 0) { if (playerStatusPtr->Armour >= damage/2) { playerStatusPtr->Armour -= damage/2; playerStatusPtr->Health -= damage/4; } else { damage -= playerStatusPtr->Armour*2; playerStatusPtr->Health -= playerStatusPtr->Armour/2 + damage; playerStatusPtr->Armour = 0; } } else { playerStatusPtr->Health -= damage; } #endif { int maxTilt = deltaHealth>>12; int halfTilt = maxTilt/2; if (maxTilt) { HeadOrientation.EulerX = (FastRandom()%maxTilt)-halfTilt; HeadOrientation.EulerY = (FastRandom()%maxTilt)-halfTilt; HeadOrientation.EulerZ = (FastRandom()%maxTilt)-halfTilt; if (HeadOrientation.EulerX < 0) HeadOrientation.EulerX += 4096; if (HeadOrientation.EulerY < 0) HeadOrientation.EulerY += 4096; if (HeadOrientation.EulerZ < 0) HeadOrientation.EulerZ += 4096; } } if ((playerStatusPtr->soundHandle==SOUND_NOACTIVEINDEX)&&(deltaHealth||deltaArmour)) { switch (AvP.PlayerType) { case I_Alien: { if ((damage->Impact==0) &&(damage->Cutting==0) &&(damage->Penetrative==0) &&(damage->Fire>0) &&(damage->Electrical==0) &&(damage->Acid==0) ) { PlayAlienSound(0,ASC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_PC_OnFire; } else { PlayAlienSound(0,ASC_Scream_Hurt,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=ASC_Scream_Hurt; } break; } case I_Marine: { if (damage->Id==AMMO_FACEHUGGER) { PlayMarineScream(0,SC_Facehugged,pitch,&playerStatusPtr->soundHandle,NULL); } else if (damage->Id==AMMO_FALLING_POSTMAX) { PlayMarineScream(0,SC_Falling,pitch,&playerStatusPtr->soundHandle,NULL); } else if ((damage->Impact==0) &&(damage->Cutting==0) &&(damage->Penetrative==0) &&(damage->Fire==0) &&(damage->Electrical==0) &&(damage->Acid>0) ) { PlayMarineScream(0,SC_Acid,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Acid; } else if ((damage->Impact==0) &&(damage->Cutting==0) &&(damage->Penetrative==0) &&(damage->Fire>0) &&(damage->Electrical==0) &&(damage->Acid==0) ) { PlayMarineScream(0,SC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_PC_OnFire; } else { PlayMarineScream(0,SC_Pain,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=SC_Pain; } break; } case I_Predator: { if (damage->Id==AMMO_FACEHUGGER) { PlayPredatorSound(0,PSC_Facehugged,pitch,&playerStatusPtr->soundHandle,NULL); } else if ((damage->Impact==0) &&(damage->Cutting==0) &&(damage->Penetrative==0) &&(damage->Fire==0) &&(damage->Electrical==0) &&(damage->Acid>0) ) { PlayPredatorSound(0,PSC_Acid,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Acid; } else if ((damage->Impact==0) &&(damage->Cutting==0) &&(damage->Penetrative==0) &&(damage->Fire>0) &&(damage->Electrical==0) &&(damage->Acid==0) ) { PlayPredatorSound(0,PSC_PC_OnFire,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_PC_OnFire; } else { PlayPredatorSound(0,PSC_Scream_Hurt,pitch,&playerStatusPtr->soundHandle,NULL); if(AvP.Network!=I_No_Network) netGameData.myLastScream=PSC_Scream_Hurt; } break; } default: { break; } } playerNoise=1; /* Alert marines, pretty much whoever you are. */ if (AvP.PlayerType==I_Marine) { PointAlert(3, &Player->ObStrategyBlock->DynPtr->Position); } else { #if 0 PointAlert(2, &Player->ObStrategyBlock->DynPtr->Position); #endif } } { NPC_DATA *NpcData; int scaled_DeltaHealth; switch (AvP.PlayerType) { case I_Marine: switch (AvP.Difficulty) { case I_Easy: NpcData=GetThisNpcData(I_PC_Marine_Easy); break; default: case I_Medium: NpcData=GetThisNpcData(I_PC_Marine_Medium); break; case I_Hard: NpcData=GetThisNpcData(I_PC_Marine_Hard); break; case I_Impossible: NpcData=GetThisNpcData(I_PC_Marine_Impossible); break; } break; case I_Alien: switch (AvP.Difficulty) { case I_Easy: NpcData=GetThisNpcData(I_PC_Alien_Easy); break; default: case I_Medium: NpcData=GetThisNpcData(I_PC_Alien_Medium); break; case I_Hard: NpcData=GetThisNpcData(I_PC_Alien_Hard); break; case I_Impossible: NpcData=GetThisNpcData(I_PC_Alien_Impossible); break; } break; case I_Predator: switch (AvP.Difficulty) { case I_Easy: NpcData=GetThisNpcData(I_PC_Predator_Easy); break; default: case I_Medium: NpcData=GetThisNpcData(I_PC_Predator_Medium); break; case I_Hard: NpcData=GetThisNpcData(I_PC_Predator_Hard); break; case I_Impossible: NpcData=GetThisNpcData(I_PC_Predator_Impossible); break; } break; default: LOCALASSERT(0); break; } /* Compute scaled deltaHealth... */ scaled_DeltaHealth=MUL_FIXED(deltaHealth,100); scaled_DeltaHealth=DIV_FIXED(scaled_DeltaHealth,NpcData->StartingStats.Health); if (scaled_DeltaHealth>PlayerDamagedOverlayIntensity) { PlayerDamagedOverlayIntensity=scaled_DeltaHealth; } } if (deltaHealth>ONE_FIXED) { VECTORCH abovePosition = Global_VDB_Ptr->VDB_World; abovePosition.vy-=1000; switch (AvP.PlayerType) { case I_Alien: MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_ALIEN_BLOOD); break; case I_Marine: MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_HUMAN_BLOOD); break; case I_Predator: MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, deltaHealth/ONE_FIXED, PARTICLE_PREDATOR_BLOOD); break; } } if (sbPtr->SBDamageBlock.Health <= 0) { if (playerStatusPtr->IsImmortal) sbPtr->SBDamageBlock.Health=0; else { PlayerIsDead(damage,multiplier,incoming); } } playerStatusPtr->Health=sbPtr->SBDamageBlock.Health; playerStatusPtr->Armour=sbPtr->SBDamageBlock.Armour; } } extern EULER deathTargetOrientation; extern int deathFadeLevel; extern int weaponHandle; static void PlayerIsDead(DAMAGE_PROFILE* damage,int multiplier,VECTORCH* incoming) { STRATEGYBLOCK *sbPtr = Player->ObStrategyBlock; PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; /* Stop pred hud sound. */ if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) { Sound_Stop(predHUDSoundHandle); } if(predOVision_SoundHandle != SOUND_NOACTIVEINDEX) { Sound_Stop(predOVision_SoundHandle); } if(weaponHandle != SOUND_NOACTIVEINDEX) { Sound_Stop(weaponHandle); } // Do some death sounds switch (AvP.PlayerType) { case I_Alien: { PlayAlienSound(0,ASC_Scream_Dying,0,NULL,NULL); break; } case I_Marine: { if (damage->Id==AMMO_FACEHUGGER) { PlayMarineScream(0,SC_Facehugged,0,NULL,NULL); } else { PlayMarineScream(0,SC_Death,0,NULL,NULL); } break; } case I_Predator: { if (damage->Id==AMMO_FACEHUGGER) { PlayPredatorSound(0,PSC_Facehugged,0,NULL,NULL); } else { PlayPredatorSound(0,PSC_Scream_Dying,0,NULL,NULL); } { VECTORCH abovePosition = Global_VDB_Ptr->VDB_World; abovePosition.vy-=1000; MakeBloodExplosion(&Global_VDB_Ptr->VDB_World, 127, &abovePosition, 200, PARTICLE_PREDATOR_BLOOD); } break; } default: { break; } } /* Well, it was nice knowing you. */ //playerStatusPtr->Health = 0; sbPtr->SBDamageBlock.Health=0; playerStatusPtr->IsAlive = 0; /* make player fall to the ground */ // Player->ObShape=I_ShapeMarinePlayerLieDown; // MapBlockInit(Player); /* give player a little bounce */ dynPtr->Elasticity = 16384; /* but a lot of friction */ // dynPtr->Friction = 1<<20; // dynPtr->Mass = 1<<20; /* cancel any velocity */ dynPtr->LinVelocity.vx = 0; dynPtr->LinVelocity.vy = 0; dynPtr->LinVelocity.vz = 0; deathTargetOrientation.EulerX = 0;//1024-(FastRandom()&255); deathFadeLevel=65536; /* if in single player, fade out sound... */ if (AvP.Network==I_No_Network) { SoundSys_FadeOut(); } if (AvP.PlayerType == I_Alien) { sbPtr->DynPtr->UseStandardGravity=1; } /* network support... */ #if SupportWindows95 if(AvP.Network!=I_No_Network) { playerStatusPtr->MyCorpse=MakeNewCorpse(); AddNetMsg_PlayerKilled((*((int *)(&(playerStatusPtr->MyCorpse->SBname[4])))),damage); /*---------------------------------------------------------** ** handle various special body being torn apart cases ** **---------------------------------------------------------*/ /*Note that we need to apply the damage to the corpse before we can determine a suitable death anim sequence*/ if(damage) { HMODELCONTROLLER* hmodel=playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock; //was the player killed by a jaw attack? if(damage->Id==AMMO_ALIEN_BITE_KILLSECTION && AvP.PlayerType!=I_Alien) { //knock the head of the corpse SECTION_DATA *head; head=GetThisSectionData(playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock->section_data,"head"); //do lots of damage to it if(head) { CauseDamageToHModel(playerStatusPtr->MyCorpse->SBdptr->HModelControlBlock,playerStatusPtr->MyCorpse, &TemplateAmmo[AMMO_ALIEN_BITE_KILLSECTION].MaxDamage[AvP.Difficulty], ONE_FIXED,head,NULL,NULL,0); } //play the head being bitten off sound Sound_Play(SID_ALIEN_JAW_ATTACK,"d",&(Player->ObStrategyBlock->DynPtr->Position)); } //chopped by predator disc? else if(damage->Id==AMMO_PRED_DISC && AvP.PlayerType!=I_Predator) { SECTION_DATA *firstSectionPtr; SECTION_DATA *chest_section=0; firstSectionPtr=hmodel->section_data; LOCALASSERT(firstSectionPtr); LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); /* look for the object's torso in preference */ chest_section =GetThisSectionData(hmodel->section_data,"chest"); if (chest_section) { CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,incoming,&chest_section->World_Offset,0); } else { CauseDamageToObject(playerStatusPtr->MyCorpse,damage, ONE_FIXED,incoming); } } //blown up by shoulder cannon? else if(damage->Id==AMMO_PLASMACASTER_PCKILL && AvP.PlayerType!=I_Predator) { SECTION_DATA *firstSectionPtr; SECTION_DATA *chest_section=0; firstSectionPtr=hmodel->section_data; LOCALASSERT(firstSectionPtr); LOCALASSERT(firstSectionPtr->flags§ion_data_initialised); /* look for the object's torso in preference */ chest_section =GetThisSectionData(hmodel->section_data,"chest"); if (chest_section) { //spherical blood explosion for aliens if(AvP.PlayerType==I_Alien) CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,NULL,&chest_section->World_Offset,0); else CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, ONE_FIXED, chest_section,incoming,&chest_section->World_Offset,0); } else { CauseDamageToObject(playerStatusPtr->MyCorpse,damage, ONE_FIXED,NULL); } } else { SECTION_DATA *section_data=0; if(MyHitBodyPartId!=-1) { //we have the id of the section that was hit when we died //so try to find the section section_data=GetThisSectionData_FromID(hmodel->section_data,MyHitBodyPartId); } //damage the corpse with the fatal blow if(section_data) { DISPLAYBLOCK *fragged_section=0; fragged_section=CauseDamageToHModel(hmodel,playerStatusPtr->MyCorpse,damage, multiplier,section_data,incoming,NULL,0); if(fragged_section && incoming && damage->Id==AMMO_PRED_RIFLE) { //a speargun has fragged off a body part , so we need to create a spear VECTORCH direction=*incoming; RotateVector(&direction,&Player->ObMat); CreateSpearPossiblyWithFragment(fragged_section,&fragged_section->ObWorld,&direction); } } else { CauseDamageToObject(playerStatusPtr->MyCorpse,damage,multiplier,incoming); } } } /*---------------------------------** ** Choose death anim sequence ** **---------------------------------*/ { int deathId; switch(AvP.PlayerType) { case I_Marine : deathId = Deduce_PlayerMarineDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming); break; case I_Alien : deathId = Deduce_PlayerAlienDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming); break; case I_Predator : deathId = Deduce_PlayerPredatorDeathSequence(playerStatusPtr->MyCorpse,damage,multiplier,incoming); break; } //apply the animation ApplyCorpseDeathAnim(playerStatusPtr->MyCorpse,deathId); //tell everyone else about the chosen death AddNetMsg_PlayerDeathAnim(deathId,*(int*)&playerStatusPtr->MyCorpse->SBname[4]); } // if(AvP.Network==I_Host) DoNetScoresForHostDeath(); //does this death require a change in character type? if(netGameData.gameType==NGT_LastManStanding) { //Am I a marine or predator? if(AvP.PlayerType!=I_Alien) { //was I killed by an alien? if(myNetworkKillerId && myNetworkKillerId!=AVPDPNetID) { int killer_index=PlayerIdInPlayerList(myNetworkKillerId); GLOBALASSERT(killer_index!=NET_IDNOTINPLAYERLIST); if(netGameData.playerData[killer_index].characterType==NGCT_Alien) { //set the next character to be an alien then netGameData.myNextCharacterType=NGCT_Alien; } } else { //suicide , so become an alien anyway netGameData.myNextCharacterType=NGCT_Alien; } } } else if(netGameData.gameType==NGT_PredatorTag || netGameData.gameType==NGT_AlienTag) { //we may need to change character extern void SpeciesTag_DetermineMyNextCharacterType(); SpeciesTag_DetermineMyNextCharacterType(); } } #endif if (playerStatusPtr->soundHandle!=SOUND_NOACTIVEINDEX) { Sound_Stop(playerStatusPtr->soundHandle); } if (playerStatusPtr->soundHandle3!=SOUND_NOACTIVEINDEX) { Sound_Stop(playerStatusPtr->soundHandle3); } /* KJL 15:36:41 10/09/98 - don't hang around on my behalf */ DisengageGrapplingHook(); } void ActivateSelfDestructSequence (int seconds) { // Currently does nothing, called when sequence is activated if (AvP.DestructTimer==-1) { AvP.DestructTimer=ONE_FIXED*seconds; //2 1/2 mins. } } void DeInitialisePlayer(void) { /* I thought it would be logical to put it here... */ int slot = MAX_NO_OF_WEAPON_SLOTS; PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); do { TXACTRLBLK *txactrl,*txactrl_next; PLAYER_WEAPON_DATA *wdPtr = &PlayerStatusBlock.WeaponSlot[--slot]; txactrl_next = wdPtr->TxAnimCtrl; while(txactrl_next) { txactrl = txactrl_next; txactrl_next = txactrl->tac_next; DeallocateMem((void*)txactrl); } wdPtr->TxAnimCtrl=NULL; } while(slot); #if 0 //this hmodel isn't being set up for the moment - Richard Dispel_HModel(&playerStatusPtr->HModelController); #endif } static int cloakDebounce = 1; void InitPlayerCloakingSystem(void) { PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); LOCALASSERT(playerStatusPtr); playerStatusPtr->cloakOn = 0; playerStatusPtr->cloakPositionGivenAway = 0; playerStatusPtr->CloakingEffectiveness = 0; playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; playerStatusPtr->cloakPositionGivenAwayTimer = 0; playerStatusPtr->PlasmaCasterCharge=0; GimmeChargeCalls=0; HtoHStrikes=0; CurrentLightAtPlayer=0; } static void DoPlayerCloakingSystem(void) { extern int NormalFrameTime; PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); LOCALASSERT(playerStatusPtr); if(AvP.PlayerType!=I_Predator) return; if(!(playerStatusPtr->IsAlive)) return; /* Handle controls. */ if (playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision) { if (cloakDebounce) { cloakDebounce = 0; if (playerStatusPtr->cloakOn) { Sound_Play(SID_PRED_CLOAKOFF,"h"); playerStatusPtr->cloakOn = 0; //playerNoise=1; } else { /* Check validity. */ if ((playerStatusPtr->FieldCharge>CloakThreshold) &&(playerStatusPtr->FieldCharge>CloakPowerOnDrain)) { PLAYER_WEAPON_DATA *weaponPtr; TEMPLATE_WEAPON_DATA *twPtr; weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; if (!(((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)||(weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)) &&(twPtr->FireWhenCloaked==0))) { playerStatusPtr->FieldCharge-=CloakPowerOnDrain; CurrentGameStats_ChargeUsed(CloakPowerOnDrain); playerStatusPtr->cloakOn = 1; playerStatusPtr->CloakingEffectiveness = 0; Sound_Play(SID_PRED_CLOAKON,"h"); //playerNoise=1; } } } } } else { cloakDebounce = 1; if (playerStatusPtr->cloakOn) { int maxPossibleEffectiveness; VECTORCH velocity; DYNAMICSBLOCK *dynPtr=Player->ObStrategyBlock->DynPtr; velocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; velocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; velocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; if (playerStatusPtr->IsMovingInWater) { maxPossibleEffectiveness = 0; if(playerStatusPtr->soundHandleForPredatorCloakDamaged==SOUND_NOACTIVEINDEX) Sound_Play(SID_PREDATOR_CLOAKING_DAMAGED,"el",playerStatusPtr->soundHandleForPredatorCloakDamaged); } else { if(playerStatusPtr->soundHandleForPredatorCloakDamaged!=SOUND_NOACTIVEINDEX) Sound_Stop(playerStatusPtr->soundHandleForPredatorCloakDamaged); maxPossibleEffectiveness = ONE_FIXED - DIV_FIXED(Magnitude(&velocity)*2,NormalFrameTime); if (maxPossibleEffectiveness<0) maxPossibleEffectiveness = 0; } playerStatusPtr->CloakingEffectiveness += NormalFrameTime; if (playerStatusPtr->CloakingEffectiveness>maxPossibleEffectiveness) { playerStatusPtr->CloakingEffectiveness = maxPossibleEffectiveness; } } else { playerStatusPtr->CloakingEffectiveness -= NormalFrameTime; if (playerStatusPtr->CloakingEffectiveness<0) { playerStatusPtr->CloakingEffectiveness=0; } if(playerStatusPtr->soundHandleForPredatorCloakDamaged!=SOUND_NOACTIVEINDEX) Sound_Stop(playerStatusPtr->soundHandleForPredatorCloakDamaged); } } #if 1 /* position-given-away-timer runs whatever state the cloak is in */ if(playerStatusPtr->cloakPositionGivenAway) { playerStatusPtr->cloakPositionGivenAwayTimer-=NormalFrameTime; if(playerStatusPtr->cloakPositionGivenAwayTimer<=0) { playerStatusPtr->cloakPositionGivenAwayTimer = 0; playerStatusPtr->cloakPositionGivenAway = 0; playerStatusPtr->CloakingEffectiveness = 0; } } /* now sort out energy discharge/recharge */ if(playerStatusPtr->cloakOn) { int chargeUsed; chargeUsed=MUL_FIXED(NormalFrameTime,CloakDrain); if (playerStatusPtr->IsMovingInWater) { chargeUsed<<=2; } if (chargeUsed>playerStatusPtr->FieldCharge) { chargeUsed=playerStatusPtr->FieldCharge; } playerStatusPtr->FieldCharge -= chargeUsed; CurrentGameStats_ChargeUsed(chargeUsed); if(playerStatusPtr->FieldCharge <= 0) { playerStatusPtr->FieldCharge = 0; playerStatusPtr->cloakOn = 0; playerStatusPtr->Mvt_InputRequests.Flags.Rqst_ChangeVision = 1; Sound_Play(SID_PRED_CLOAKOFF,"h"); //playerNoise=1; } /* TrickleCharge Difficulty Variation! */ if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,(TrickleCharge>>1)); } else { playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,TrickleCharge); } if(playerStatusPtr->FieldCharge > PLAYERCLOAK_MAXENERGY) { playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; } } else { if(playerStatusPtr->FieldCharge < PLAYERCLOAK_MAXENERGY) { /* TrickleCharge Difficulty Variation! */ if ((AvP.Difficulty==I_Hard)||(AvP.Difficulty==I_Impossible)) { playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,(TrickleCharge>>1)); } else { playerStatusPtr->FieldCharge += MUL_FIXED(NormalFrameTime,TrickleCharge); } if(playerStatusPtr->FieldCharge > PLAYERCLOAK_MAXENERGY) { playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; } #if 0 /* Infinite field charge? */ playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; #endif } } #endif if (ShowPredoStats) { /* for testing */ PrintDebuggingText("Cloak on: %d \n",playerStatusPtr->cloakOn); PrintDebuggingText("Field Charge: %d \n",playerStatusPtr->FieldCharge); { int a; /* Speargun ammo count */ a=SlotForThisWeapon(WEAPON_PRED_RIFLE); if (a!=-1) { PrintDebuggingText("Speargun Rounds: %d Clips: %d\n",(playerStatusPtr->WeaponSlot[a].PrimaryRoundsRemaining>>ONE_FIXED_SHIFT),playerStatusPtr->WeaponSlot[a].PrimaryMagazinesRemaining); } else { PrintDebuggingText("Speargun not possessed.\n"); } } PrintDebuggingText("Cloak given away: %d \n", playerStatusPtr->cloakPositionGivenAway); PrintDebuggingText("Cloak given away timer: %d \n", playerStatusPtr->cloakPositionGivenAwayTimer); PrintDebuggingText("Cloaking Effectiveness: %d \n", playerStatusPtr->CloakingEffectiveness); PrintDebuggingText("Gimme_Charge Calls: %d \n",GimmeChargeCalls); } #if 1 /* now, if we are cloaked, lets see if we have given away our position... if we have already given away our position, we may do so again */ if(playerStatusPtr->cloakOn) { PLAYER_WEAPON_DATA *weaponPtr; TEMPLATE_WEAPON_DATA *twPtr; weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); twPtr = &TemplateWeapon[weaponPtr->WeaponIDNumber]; /* weapon fire ?*/ if(((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_PRIMARY)&&(!twPtr->PrimaryIsMeleeWeapon))|| ((PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot].CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(!twPtr->SecondaryIsMeleeWeapon))) { playerStatusPtr->cloakPositionGivenAway = 1; playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME; } /* collision with npc ?*/ { struct collisionreport *nextReport; LOCALASSERT(Player->ObStrategyBlock->DynPtr); nextReport = Player->ObStrategyBlock->DynPtr->CollisionReportPtr; while(nextReport) { if(nextReport->ObstacleSBPtr) { if((nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourAlien)|| (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourMarine)|| (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourXenoborg)|| (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourPredatorAlien)|| (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourQueenAlien)|| (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourFaceHugger)|| (nextReport->ObstacleSBPtr->I_SBtype==I_BehaviourSeal)) { playerStatusPtr->cloakPositionGivenAway = 1; playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME; break; } } nextReport = nextReport->NextCollisionReportPtr; } } } #endif if (playerStatusPtr->cloakOn) { CurrentGameStats_CloakOn(); } } void GimmeCharge(void) { PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); LOCALASSERT(playerStatusPtr); if(AvP.PlayerType!=I_Predator) return; playerStatusPtr->FieldCharge = PLAYERCLOAK_MAXENERGY; GimmeChargeCalls++; } #define AUTOSPOT_RANGE (1000) int AlienPCIsCurrentlyVisible(int checktime,STRATEGYBLOCK *sbPtr) { PLAYER_WEAPON_DATA *weaponPtr; int range; DYNAMICSBLOCK *dynPtr=(Player->ObStrategyBlock->DynPtr); PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); LOCALASSERT(playerStatusPtr); /* sbPtr is the viewer. */ if (AvP.PlayerType!=I_Alien) { /* Just to be sure. */ return(1); } weaponPtr = &(playerStatusPtr->WeaponSlot[playerStatusPtr->SelectedWeaponSlot]); /* Set a default range? */ range=-1; /* Maybe we also need an autospot range. */ if (sbPtr) { VECTORCH offset; offset.vx=dynPtr->Position.vx-sbPtr->DynPtr->Position.vx; offset.vy=dynPtr->Position.vy-sbPtr->DynPtr->Position.vy; offset.vz=dynPtr->Position.vz-sbPtr->DynPtr->Position.vz; range=Approximate3dMagnitude(&offset); /* In fact, let's turn this around... */ if (playerStatusPtr->ShapeState==PMph_Standing) { if (range>=(CurrentLightAtPlayer)+AUTOSPOT_RANGE) { return(0); } } else { if (range>=(CurrentLightAtPlayer>>1)+AUTOSPOT_RANGE) { /* Half that range if crouching? */ return(0); } } /* I guess, if we're in _pitch_ darkness... see nothing outside that range? */ if (CurrentLightAtPlayer<=2560) { if (playerStatusPtr->ShapeState==PMph_Standing) { if (range<=(CurrentLightAtPlayer)+AUTOSPOT_RANGE) { return(1); } } else { if (range<=(CurrentLightAtPlayer>>1)+AUTOSPOT_RANGE) { /* Half that range if crouching? */ return(1); } } return(0); } } if (playerStatusPtr->ShapeState==PMph_Standing) { /* Default to visible, unless stationary and in near darkness. */ if (weaponPtr->CurrentState!=WEAPONSTATE_IDLE) { /* Don't even breathe. */ return(1); } if ((dynPtr->Position.vx!=dynPtr->PrevPosition.vx)|| (dynPtr->Position.vy!=dynPtr->PrevPosition.vy)|| (dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) { /* Stand perfectly still. */ return(1); } if (checktime) { int chance; /* There is a chance of being seen regardless. */ chance=32767; /* Lets say. */ if ((FastRandom()&65535)CurrentState==WEAPONSTATE_FIRING_PRIMARY) { /* Just don't claw. */ return(1); } if (CurrentLightAtPlayer>17000) { /* It's too bright, mere crouching won't save you. */ return(1); } #if 0 if ((dynPtr->Position.vx!=dynPtr->PrevPosition.vx)|| (dynPtr->Position.vy!=dynPtr->PrevPosition.vy)|| (dynPtr->Position.vz!=dynPtr->PrevPosition.vz)) { /* Stand perfectly still? */ return(1); } #else speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity); /* Speed: < 5000 = standing. > 22000 = jumping. In practice, walk/fall = 18000 ish, jump = 27000 ish. */ if (speed>22000) { /* Not getting away with that, mate. */ return(1); } speed-=5000; if (speed<0) { speed=0; } /* Now should be 0->17000 ish. */ speed<<=1; #endif if (checktime) { int chance; /* There is a chance of being seen. */ chance=CurrentLightAtPlayer-5000; #if 1 chance+=speed; #endif if ((FastRandom()&65535)m_aimodule->m_module_ptrs))->name); thisModule=playerPherModule->m_aimodule; AdjModuleRefPtr = thisModule->m_link_ptrs; if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ { while(*AdjModuleRefPtr != 0) { /* Probably want some validity test for the link. */ if (AIModuleIsPhysical(*AdjModuleRefPtr)) { /* Probably a valid link... */ if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) { PrintDebuggingText("--AI Module of %s, general.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); } else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) { PrintDebuggingText("--AI Module of %s, alien only.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); } else { PrintDebuggingText("--AI Module of %s, fails validity test!\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); } } /* next adjacent module reference pointer */ AdjModuleRefPtr++; } } PrintDebuggingText("Adjacencies TO Player's Module:\n"); { extern AIMODULE *AIModuleArray; ModuleListPointer = AIModuleArray; } /* go through each aimodule in the environment */ for(moduleCounter = 0; moduleCounter < AIModuleArraySize; moduleCounter++) { /* get a pointer to the next current module */ thisModule = &(ModuleListPointer[moduleCounter]); LOCALASSERT(thisModule); AdjModuleRefPtr = thisModule->m_link_ptrs; if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ { while(*AdjModuleRefPtr != 0) { /* Probably want some validity test for the link. */ if (AIModuleIsPhysical(*AdjModuleRefPtr)) { /* Is this the target? */ if ((*AdjModuleRefPtr)==(playerPherModule->m_aimodule)) { /* Probably a valid link... */ if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) { PrintDebuggingText("--AI Module of %s, general.\n",(*(thisModule->m_module_ptrs))->name); } else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) { PrintDebuggingText("--AI Module of %s, alien only.\n",(*(thisModule->m_module_ptrs))->name); } else { PrintDebuggingText("--AI Module of %s, fails validity test!\n",(*(thisModule->m_module_ptrs))->name); } } } /* next adjacent module reference pointer */ AdjModuleRefPtr++; } } } } /*---------------------------** ** Loading and saving player ** **---------------------------*/ typedef struct player_save_block { SAVE_BLOCK_STRATEGY_HEADER header; //behaviour block things PLAYER_WEAPON_DATA WeaponSlot[MAX_NO_OF_WEAPON_SLOTS]; enum WEAPON_SLOT SelectedWeaponSlot; enum WEAPON_SLOT SwapToWeaponSlot; enum WEAPON_SLOT PreviouslySelectedWeaponSlot; int Health; /* in 16.16 */ int Energy; /* in 16.16 */ int Armour; /* in 16.16 */ enum player_morph_state ShapeState; /* for controlling morphing */ signed int ForwardInertia; signed int StrafeInertia; signed int TurnInertia; int ViewPanX; /* the looking up/down value that used to be in displayblock */ unsigned int securityClearances; unsigned int IsAlive :1; unsigned int IsImmortal :1; unsigned int Mvt_AnalogueTurning :1; unsigned int Mvt_AnaloguePitching :1; unsigned int Absolute_Pitching :1; unsigned int SwappingIsDebounced :1; unsigned int DemoMode :1; unsigned int IHaveAPlacedAutogun :1; unsigned int IsMovingInWater :1; unsigned int JetpackEnabled :1; unsigned int GrapplingHookEnabled :1; unsigned int MTrackerType; unsigned int cloakOn :1; unsigned int cloakPositionGivenAway :1; int FieldCharge; int cloakPositionGivenAwayTimer; int PlasmaCasterCharge; int CloakingEffectiveness; ENCUMBERANCE_STATE Encumberance; int tauntTimer; int incidentFlag; int incidentTimer; int fireTimer; //some stuff for the weapon displayblock VECTORCH Weapon_World; EULER Weapon_Euler; MATRIXCH Weapon_Matrix; //and globals enum VISION_MODE_ID CurrentVisionMode; SMARTGUN_MODES SmartgunMode; GRENADE_LAUNCHER_DATA GrenadeLauncherData; //strategy block stuff DYNAMICSBLOCK dynamics; int integrity; DAMAGEBLOCK SBDamageBlock; }PLAYER_SAVE_BLOCK; //defines for load/save macros #define SAVELOAD_BLOCK block #define SAVELOAD_BEHAV playerStatusPtr void SaveStrategy_Player(STRATEGYBLOCK* sbPtr) { PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); PLAYER_SAVE_BLOCK* block; int i; GET_STRATEGY_SAVE_BLOCK(block,sbPtr); COPYELEMENT_SAVE(SelectedWeaponSlot) COPYELEMENT_SAVE(SwapToWeaponSlot) COPYELEMENT_SAVE(PreviouslySelectedWeaponSlot) COPYELEMENT_SAVE(Health) /* in 16.16 */ COPYELEMENT_SAVE(Energy) /* in 16.16 */ COPYELEMENT_SAVE(Armour) /* in 16.16 */ COPYELEMENT_SAVE(ShapeState) /* for controlling morphing */ COPYELEMENT_SAVE(ForwardInertia) COPYELEMENT_SAVE(StrafeInertia) COPYELEMENT_SAVE(TurnInertia) COPYELEMENT_SAVE(ViewPanX) /* the looking up/down value that used to be in displayblock */ COPYELEMENT_SAVE(securityClearances) COPYELEMENT_SAVE(IsAlive) COPYELEMENT_SAVE(IsImmortal) COPYELEMENT_SAVE(Mvt_AnalogueTurning) COPYELEMENT_SAVE(Mvt_AnaloguePitching) COPYELEMENT_SAVE(Absolute_Pitching) COPYELEMENT_SAVE(SwappingIsDebounced) COPYELEMENT_SAVE(DemoMode) COPYELEMENT_SAVE(IHaveAPlacedAutogun) COPYELEMENT_SAVE(IsMovingInWater) COPYELEMENT_SAVE(JetpackEnabled) COPYELEMENT_SAVE(GrapplingHookEnabled ) COPYELEMENT_SAVE(MTrackerType) COPYELEMENT_SAVE(cloakOn) COPYELEMENT_SAVE(cloakPositionGivenAway) COPYELEMENT_SAVE(FieldCharge) COPYELEMENT_SAVE(cloakPositionGivenAwayTimer) COPYELEMENT_SAVE(PlasmaCasterCharge) COPYELEMENT_SAVE(CloakingEffectiveness) COPYELEMENT_SAVE(Encumberance) COPYELEMENT_SAVE(tauntTimer) COPYELEMENT_SAVE(incidentFlag) COPYELEMENT_SAVE(incidentTimer) COPYELEMENT_SAVE(fireTimer) for(i=0;iWeaponSlot[i].WeaponIDNumber = playerStatusPtr->WeaponSlot[i].WeaponIDNumber; block->WeaponSlot[i].CurrentState = playerStatusPtr->WeaponSlot[i].CurrentState; block->WeaponSlot[i].StateTimeOutCounter = playerStatusPtr->WeaponSlot[i].StateTimeOutCounter; block->WeaponSlot[i].PrimaryRoundsRemaining = playerStatusPtr->WeaponSlot[i].PrimaryRoundsRemaining; block->WeaponSlot[i].SecondaryRoundsRemaining = playerStatusPtr->WeaponSlot[i].SecondaryRoundsRemaining; block->WeaponSlot[i].PrimaryMagazinesRemaining = playerStatusPtr->WeaponSlot[i].PrimaryMagazinesRemaining; block->WeaponSlot[i].SecondaryMagazinesRemaining = playerStatusPtr->WeaponSlot[i].SecondaryMagazinesRemaining; block->WeaponSlot[i].PositionOffset = playerStatusPtr->WeaponSlot[i].PositionOffset; block->WeaponSlot[i].DirectionOffset = playerStatusPtr->WeaponSlot[i].DirectionOffset; block->WeaponSlot[i].Possessed = playerStatusPtr->WeaponSlot[i].Possessed; } //some stuff for the weapon displayblock block->Weapon_World = PlayersWeapon.ObWorld; block->Weapon_Euler = PlayersWeapon.ObEuler; block->Weapon_Matrix = PlayersWeapon.ObMat; //global block->CurrentVisionMode = CurrentVisionMode; block->SmartgunMode = SmartgunMode; block->GrenadeLauncherData = GrenadeLauncherData; //strategy block stuff block->integrity = sbPtr->integrity; block->SBDamageBlock = sbPtr->SBDamageBlock; block->dynamics = *sbPtr->DynPtr; block->dynamics.CollisionReportPtr=0; //save the weapon hierarchy SaveHierarchy(&PlayersWeaponHModelController); Save_SoundState(&playerStatusPtr->soundHandle); Save_SoundState(&playerStatusPtr->soundHandle3); Save_SoundState(&playerStatusPtr->soundHandle5); Save_SoundState(&playerStatusPtr->soundHandleForPredatorCloakDamaged); } void LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER* header) { PLAYER_SAVE_BLOCK* block = (PLAYER_SAVE_BLOCK*) header; STRATEGYBLOCK* sbPtr = Player->ObStrategyBlock; PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (sbPtr->SBdataptr); int i; if(block->header.size != sizeof(*block)) return; COPY_NAME(sbPtr->SBname,header->SBname); COPYELEMENT_LOAD(SelectedWeaponSlot) COPYELEMENT_LOAD(SwapToWeaponSlot) COPYELEMENT_LOAD(PreviouslySelectedWeaponSlot) COPYELEMENT_LOAD(Health) /* in 16.16 */ COPYELEMENT_LOAD(Energy) /* in 16.16 */ COPYELEMENT_LOAD(Armour) /* in 16.16 */ COPYELEMENT_LOAD(ShapeState) /* for controlling morphing */ COPYELEMENT_LOAD(ForwardInertia) COPYELEMENT_LOAD(StrafeInertia) COPYELEMENT_LOAD(TurnInertia) COPYELEMENT_LOAD(ViewPanX) /* the looking up/down value that used to be in displayblock */ COPYELEMENT_LOAD(securityClearances) COPYELEMENT_LOAD(IsAlive) COPYELEMENT_LOAD(IsImmortal) COPYELEMENT_LOAD(Mvt_AnalogueTurning) COPYELEMENT_LOAD(Mvt_AnaloguePitching) COPYELEMENT_LOAD(Absolute_Pitching) COPYELEMENT_LOAD(SwappingIsDebounced) COPYELEMENT_LOAD(DemoMode) COPYELEMENT_LOAD(IHaveAPlacedAutogun) COPYELEMENT_LOAD(IsMovingInWater) COPYELEMENT_LOAD(JetpackEnabled) COPYELEMENT_LOAD(GrapplingHookEnabled ) COPYELEMENT_LOAD(MTrackerType) COPYELEMENT_LOAD(cloakOn) COPYELEMENT_LOAD(cloakPositionGivenAway) COPYELEMENT_LOAD(FieldCharge) COPYELEMENT_LOAD(cloakPositionGivenAwayTimer) COPYELEMENT_LOAD(PlasmaCasterCharge) COPYELEMENT_LOAD(CloakingEffectiveness) COPYELEMENT_LOAD(Encumberance) COPYELEMENT_LOAD(tauntTimer) COPYELEMENT_LOAD(incidentFlag) COPYELEMENT_LOAD(incidentTimer) COPYELEMENT_LOAD(fireTimer) // playerStatusPtr->SwapToWeaponSlot = block->SelectedWeaponSlot; for(i=0;iWeaponSlot[i].WeaponIDNumber = block->WeaponSlot[i].WeaponIDNumber; playerStatusPtr->WeaponSlot[i].CurrentState = block->WeaponSlot[i].CurrentState; playerStatusPtr->WeaponSlot[i].StateTimeOutCounter = block->WeaponSlot[i].StateTimeOutCounter; playerStatusPtr->WeaponSlot[i].PrimaryRoundsRemaining = block->WeaponSlot[i].PrimaryRoundsRemaining; playerStatusPtr->WeaponSlot[i].SecondaryRoundsRemaining = block->WeaponSlot[i].SecondaryRoundsRemaining; playerStatusPtr->WeaponSlot[i].PrimaryMagazinesRemaining = block->WeaponSlot[i].PrimaryMagazinesRemaining; playerStatusPtr->WeaponSlot[i].SecondaryMagazinesRemaining = block->WeaponSlot[i].SecondaryMagazinesRemaining; playerStatusPtr->WeaponSlot[i].PositionOffset = block->WeaponSlot[i].PositionOffset; playerStatusPtr->WeaponSlot[i].DirectionOffset = block->WeaponSlot[i].DirectionOffset; playerStatusPtr->WeaponSlot[i].Possessed = block->WeaponSlot[i].Possessed; } //some stuff for the weapon displayblock PlayersWeapon.ObWorld = block->Weapon_World; PlayersWeapon.ObEuler = block->Weapon_Euler; PlayersWeapon.ObMat = block->Weapon_Matrix; //global CurrentVisionMode = block->CurrentVisionMode; SmartgunMode = block->SmartgunMode; GrenadeLauncherData = block->GrenadeLauncherData; //strategy block stuff *sbPtr->DynPtr = block->dynamics; sbPtr->integrity = block->integrity; sbPtr->SBDamageBlock = block->SBDamageBlock; { extern VIEWDESCRIPTORBLOCK* Global_VDB_Ptr; sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); Global_VDB_Ptr->VDB_World = sbPtr->DynPtr->Position; } //load the weapon hierarchy { SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); if(hier_header) { LoadHierarchy(hier_header,&PlayersWeaponHModelController); } else { Dispel_HModel(&PlayersWeaponHModelController); } } PlayersWeapon.HModelControlBlock = &PlayersWeaponHModelController; //get the section data pointers PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"dum flash"); if (PWMFSDP==NULL) { PWMFSDP=GetThisSectionData(PlayersWeaponHModelController.section_data,"Dum flash"); } Load_SoundState(&playerStatusPtr->soundHandle); Load_SoundState(&playerStatusPtr->soundHandle3); Load_SoundState(&playerStatusPtr->soundHandle5); Load_SoundState(&playerStatusPtr->soundHandleForPredatorCloakDamaged); }