// RWH moved out here to provide easier access /* CDF 25/7/98 - A completely new file. */ #include "3dc.h" #include "inline.h" #include "module.h" #include "stratdef.h" #include "gamedef.h" #include "bh_types.h" #include "dynblock.h" #include "dynamics.h" #include "weapons.h" #include "comp_shp.h" #include "inventry.h" #include "triggers.h" #define UseLocalAssert Yes #include "ourasert.h" #include "pmove.h" #include "pvisible.h" #include "bh_swdor.h" #include "bh_plift.h" #include "load_shp.h" #include "bh_weap.h" #include "bh_debri.h" #include "lighting.h" #include "bh_lnksw.h" #include "bh_binsw.h" #include "pheromon.h" #include "bh_pred.h" #include "bh_agun.h" #include "plat_shp.h" #include "psnd.h" #include "ai_sight.h" #include "sequnces.h" #include "huddefs.h" #include "showcmds.h" #include "sfx.h" #include "bh_marin.h" #include "bh_far.h" #include "pldghost.h" #include "pheromon.h" #include "targeting.h" #include "dxlog.h" #include "los.h" #include "psndplat.h" #include "bh_dummy.h" #include "bh_corpse.h" #if SupportWindows95 /* for win95 net game support */ #include "pldghost.h" #include "pldnet.h" #endif #define SENTRYGUN_DRAMA 0 int SentrygunSpread=5; extern int NormalFrameTime; extern unsigned char Null_Name[8]; extern ACTIVESOUNDSAMPLE ActiveSounds[]; extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); void CreateSentrygun(VECTORCH *Position,int type); void AGunMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate); void AGunMovement_Centre(STRATEGYBLOCK *sbPtr,int rate); void Execute_AGun_Target(STRATEGYBLOCK *sbPtr); void AGun_MaintainGun(STRATEGYBLOCK *sbPtr); void Execute_AGun_Dying(STRATEGYBLOCK *sbPtr); SOUND3DDATA SentryFire_SoundData={ {0,0,0,}, {0,0,0,}, 20000, 40000, }; SOUND3DDATA SentryWhirr_SoundData={ {0,0,0,}, {0,0,0,}, 0, 32000, }; /* Begin Code! */ void CreatePlayerAutogun(void) { /* Yow, this actually gets called! */ } void CastSentrygun(void) { #define BOTRANGE 2000 VECTORCH position; if (AvP.Network!=I_No_Network) { NewOnScreenMessage("NO SENTRYGUNS IN MULTIPLAYER MODE"); return; } position=Player->ObStrategyBlock->DynPtr->Position; position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat31,BOTRANGE); position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat32,BOTRANGE); position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat33,BOTRANGE); CreateSentrygun(&position, 0); } void CreateSentrygun(VECTORCH *Position,int type) { STRATEGYBLOCK* sbPtr; int i; /* create and initialise a strategy block */ sbPtr = CreateActiveStrategyBlock(); if(!sbPtr) { NewOnScreenMessage("FAILED TO CREATE BOT: SB CREATION FAILURE"); return; /* failure */ } InitialiseSBValues(sbPtr); sbPtr->I_SBtype = I_BehaviourAutoGun; AssignNewSBName(sbPtr); /* create, initialise and attach a dynamics block */ sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); if(sbPtr->DynPtr) { EULER zeroEuler = {0,0,0}; DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; GLOBALASSERT(dynPtr); dynPtr->PrevPosition = dynPtr->Position = *Position; dynPtr->OrientEuler = zeroEuler; CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); TransposeMatrixCH(&dynPtr->OrientMat); dynPtr->UseDisplacement=0; dynPtr->Mass=10000; /* As opposed to 160. */ } else { /* dynamics block allocation failed... */ RemoveBehaviourStrategy(sbPtr); NewOnScreenMessage("FAILED TO CREATE GUN: DYNBLOCK CREATION FAILURE"); return; } sbPtr->shapeIndex = 0; sbPtr->maintainVisibility = 1; sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); /* create, initialise and attach an alien data block */ sbPtr->SBdataptr = (void *)AllocateMem(sizeof(AUTOGUN_STATUS_BLOCK)); if(sbPtr->SBdataptr) { SECTION *root_section; AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->SBdataptr; /* Initialise xenoborg's stats */ { NPC_DATA *NpcData; NpcData=GetThisNpcData(I_NPC_SentryGun); LOCALASSERT(NpcData); sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; } agunStatus->behaviourState=I_tracking; agunStatus->Target=NULL; COPY_NAME(agunStatus->Target_SBname,Null_Name); agunStatus->targetTrackPos.vx=0; agunStatus->targetTrackPos.vy=0; agunStatus->targetTrackPos.vz=0; agunStatus->stateTimer=0; agunStatus->Gun_Pan=0; agunStatus->Gun_Tilt=0; agunStatus->gunpandir=0; agunStatus->guntiltdir=0; agunStatus->IAmFar=1; agunStatus->Firing=0; agunStatus->Drama=0; agunStatus->OnTarget=0; agunStatus->OnTarget_LastFrame=0; agunStatus->WhirrSoundOn=0; agunStatus->GunFlash=NULL; agunStatus->soundHandle=SOUND_NOACTIVEINDEX; agunStatus->soundHandle2=SOUND_NOACTIVEINDEX; agunStatus->ammo=500; agunStatus->roundsFired=0; agunStatus->volleyFired=0; agunStatus->incidentFlag=0; agunStatus->incidentTimer=0; agunStatus->HModelController.section_data=NULL; agunStatus->HModelController.Deltas=NULL; for(i=0;ideath_target_ID[i] =0; agunStatus->death_target_sbptr=0; agunStatus->death_target_request=0; root_section=GetNamedHierarchyFromLibrary("sentry","gun"); if (!root_section) { RemoveBehaviourStrategy(sbPtr); NewOnScreenMessage("FAILED TO CREATE GUN: NO HMODEL"); return; } Create_HModel(&agunStatus->HModelController,root_section); InitHModelSequence(&agunStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED); { DELTA_CONTROLLER *delta; delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0); GLOBALASSERT(delta); delta->timer=32767; delta->Active=0; delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0); GLOBALASSERT(delta); delta->timer=32767; delta->Active=0; } /* Containment test NOW! */ if(!(sbPtr->containingModule)) { /* no containing module can be found... abort*/ RemoveBehaviourStrategy(sbPtr); NewOnScreenMessage("FAILED TO CREATE GUN: MODULE CONTAINMENT FAILURE"); return; } LOCALASSERT(sbPtr->containingModule); MakeSentrygunNear(sbPtr); NewOnScreenMessage("SENTRYGUN CREATED"); } else { /* no data block can be allocated */ RemoveBehaviourStrategy(sbPtr); NewOnScreenMessage("FAILED TO CREATE GUN: MALLOC FAILURE"); return; } if(AvP.Network != I_No_Network) { AddNetGameObjectID(sbPtr); } } void MakeSentrygunNear(STRATEGYBLOCK *sbPtr) { extern MODULEMAPBLOCK AlienDefaultMap; MODULE tempModule; DISPLAYBLOCK *dPtr; DYNAMICSBLOCK *dynPtr; AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); dynPtr = sbPtr->DynPtr; agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); LOCALASSERT(dynPtr); LOCALASSERT(sbPtr->SBdptr == NULL); AlienDefaultMap.MapShape = sbPtr->shapeIndex; tempModule.m_mapptr = &AlienDefaultMap; tempModule.m_sbptr = (STRATEGYBLOCK*)NULL; tempModule.m_numlights = 0; tempModule.m_lightarray = (struct lightblock *)0; tempModule.m_extraitemdata = (struct extraitemdata *)0; tempModule.m_dptr = NULL; AllocateModuleObject(&tempModule); dPtr = tempModule.m_dptr; if(dPtr==NULL) return; /* if cannot create displayblock, leave far */ sbPtr->SBdptr = dPtr; dPtr->ObStrategyBlock = sbPtr; dPtr->ObMyModule = NULL; /* need to initialise positional information in the new display block */ dPtr->ObWorld = dynPtr->Position; dPtr->ObEuler = dynPtr->OrientEuler; dPtr->ObMat = dynPtr->OrientMat; /* zero linear velocity in dynamics block */ sbPtr->DynPtr->LinVelocity.vx = 0; sbPtr->DynPtr->LinVelocity.vy = 0; sbPtr->DynPtr->LinVelocity.vz = 0; /* state and sequence init */ dPtr->ShapeAnimControlBlock = NULL; dPtr->ObTxAnimCtrlBlks = NULL; dPtr->HModelControlBlock=&agunStatusPointer->HModelController; ProveHModel(dPtr->HModelControlBlock,dPtr); agunStatusPointer->IAmFar=0; } void AutoGunBehaveInit(void *bhdata,STRATEGYBLOCK *sbPtr) { AUTOGUN_TOOLS_TEMPLATE *toolsData; int i; LOCALASSERT(bhdata); toolsData = (AUTOGUN_TOOLS_TEMPLATE *)bhdata; LOCALASSERT(sbPtr); /* check we're not in a net game */ if(AvP.Network != I_No_Network) { RemoveBehaviourStrategy(sbPtr); return; } /* make the assumption that the loader has initialised the strategy block sensibly... so just set the shapeIndex from the tools data & copy the name id*/ sbPtr->shapeIndex = toolsData->shapenum; for(i=0;iSBname[i] = toolsData->nameID[i]; /* create, initialise and attach a dynamics block */ sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC); if(sbPtr->DynPtr) { DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; GLOBALASSERT(dynPtr); dynPtr->PrevPosition = dynPtr->Position = toolsData->position; dynPtr->OrientEuler = toolsData->orientation; CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); TransposeMatrixCH(&dynPtr->OrientMat); dynPtr->Mass=10000; /* As opposed to 160. */ } else { /* dynamics block allocation failed... */ RemoveBehaviourStrategy(sbPtr); return; } sbPtr->maintainVisibility = 1; sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), (MODULE*)0); /* create, initialise and attach an alien data block */ sbPtr->SBdataptr = (void *)AllocateMem(sizeof(AUTOGUN_STATUS_BLOCK)); if(sbPtr->SBdataptr) { SECTION *root_section; AUTOGUN_STATUS_BLOCK *agunStatus = (AUTOGUN_STATUS_BLOCK *)sbPtr->SBdataptr; /* Initialise xenoborg's stats */ { NPC_DATA *NpcData; NpcData=GetThisNpcData(I_NPC_SentryGun); LOCALASSERT(NpcData); sbPtr->SBDamageBlock.Health=NpcData->StartingStats.Health<SBDamageBlock.Armour=NpcData->StartingStats.Armour<SBDamageBlock.SB_H_flags=NpcData->StartingStats.SB_H_flags; } if (toolsData->startInactive) { agunStatus->behaviourState=I_inactive; } else { agunStatus->behaviourState=I_tracking; } agunStatus->Target=NULL; COPY_NAME(agunStatus->Target_SBname,Null_Name); agunStatus->targetTrackPos.vx=0; agunStatus->targetTrackPos.vy=0; agunStatus->targetTrackPos.vz=0; agunStatus->stateTimer=0; agunStatus->Gun_Pan=0; agunStatus->Gun_Tilt=0; agunStatus->gunpandir=0; agunStatus->guntiltdir=0; agunStatus->IAmFar=1; agunStatus->Firing=0; agunStatus->Drama=0; agunStatus->OnTarget=0; agunStatus->OnTarget_LastFrame=0; agunStatus->WhirrSoundOn=0; agunStatus->GunFlash=NULL; agunStatus->soundHandle=SOUND_NOACTIVEINDEX; agunStatus->soundHandle2=SOUND_NOACTIVEINDEX; agunStatus->ammo=toolsData->ammo; agunStatus->roundsFired=0; agunStatus->volleyFired=0; agunStatus->incidentFlag=0; agunStatus->incidentTimer=0; agunStatus->HModelController.section_data=NULL; agunStatus->HModelController.Deltas=NULL; for(i=0;ideath_target_ID[i] =toolsData->death_target_ID[i]; agunStatus->death_target_sbptr=0; agunStatus->death_target_request=toolsData->death_target_request; root_section=GetNamedHierarchyFromLibrary("sentry","gun"); if (!root_section) { RemoveBehaviourStrategy(sbPtr); return; } Create_HModel(&agunStatus->HModelController,root_section); InitHModelSequence(&agunStatus->HModelController,HMSQT_Xenoborg,XBSS_Powered_Up_Standard,ONE_FIXED); { DELTA_CONTROLLER *delta; delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunTilt",(int)HMSQT_Xenoborg,(int)XBSS_Head_Vertical_Delta,0); GLOBALASSERT(delta); delta->timer=32767; delta->Active=0; delta=Add_Delta_Sequence(&agunStatus->HModelController,"GunPan",(int)HMSQT_Xenoborg,(int)XBSS_Head_Horizontal_Delta,0); GLOBALASSERT(delta); delta->timer=32767; delta->Active=0; } /* Containment test NOW! */ if(!(sbPtr->containingModule)) { /* no containing module can be found... abort*/ RemoveBehaviourStrategy(sbPtr); return; } LOCALASSERT(sbPtr->containingModule); } else { /* no data block can be allocated */ RemoveBehaviourStrategy(sbPtr); return; } } void MakeSentrygunFar(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; int i; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); LOCALASSERT(sbPtr->SBdptr != NULL); /* get rid of the displayblock */ i = DestroyActiveObject(sbPtr->SBdptr); LOCALASSERT(i==0); sbPtr->SBdptr = NULL; /* if we have any gun flashes, get rid of them */ if(agunStatusPointer->GunFlash) { RemoveNPCGunFlashEffect(agunStatusPointer->GunFlash); agunStatusPointer->GunFlash = NULL; } /* agun data block init */ if(agunStatusPointer->behaviourState != I_disabled) { agunStatusPointer->stateTimer=0; } /* zero linear velocity in dynamics block */ sbPtr->DynPtr->LinVelocity.vx = 0; sbPtr->DynPtr->LinVelocity.vy = 0; sbPtr->DynPtr->LinVelocity.vz = 0; agunStatusPointer->IAmFar=1; } static void Autogun_VerifyDeltaControllers(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* Nothing has deltas like a xenoborg does. */ /* But sentryguns try their best. */ agunStatusPointer->gun_pan=Get_Delta_Sequence(&agunStatusPointer->HModelController,"GunPan"); GLOBALASSERT(agunStatusPointer->gun_pan); agunStatusPointer->gun_tilt=Get_Delta_Sequence(&agunStatusPointer->HModelController,"GunTilt"); GLOBALASSERT(agunStatusPointer->gun_tilt); } static void AGun_ComputeDeltaValues(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; int angle; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* Interpret all status block values, and apply to deltas. */ /* Gun Pan first. */ angle=agunStatusPointer->Gun_Pan>>4; if (angle>=3072) angle-=4096; if (angle>=2048) angle=angle-4096; GLOBALASSERT(agunStatusPointer->gun_pan); /* Now, we have an angle. */ if (angle>SGUN_PAN_GIMBALL) { angle=SGUN_PAN_GIMBALL; } else if (angle<-SGUN_PAN_GIMBALL) { angle=-SGUN_PAN_GIMBALL; } { int fake_timer; if (angle>0) { fake_timer=DIV_FIXED(angle,(SGUN_PAN_GIMBALL<<1)); fake_timer+=32767; if (fake_timer>=65536) fake_timer=65535; if (fake_timer<=0) fake_timer=0; } else { fake_timer=DIV_FIXED(angle,(SGUN_PAN_GIMBALL<<1)); fake_timer+=32767; if (fake_timer>=65536) fake_timer=65535; if (fake_timer<=0) fake_timer=0; } GLOBALASSERT(fake_timer>=0); GLOBALASSERT(fake_timer<65536); if (agunStatusPointer->gun_pan->timer!=fake_timer) { agunStatusPointer->WhirrSoundOn=1; } agunStatusPointer->gun_pan->timer=fake_timer; } /* Gun Tilt... */ angle=agunStatusPointer->Gun_Tilt>>4; if (angle>=3072) angle-=4096; if (angle>=2048) angle=angle-3072; if (angle> 1024) angle=2048-angle; GLOBALASSERT(agunStatusPointer->gun_tilt); /* Now, we have an angle. */ if (angle>SGUN_PITCH_GIMBALL) { angle=SGUN_PITCH_GIMBALL; } else if (angle<-SGUN_PITCH_GIMBALL) { angle=-SGUN_PITCH_GIMBALL; } GLOBALASSERT(angle>=-1024); GLOBALASSERT(angle<=1024); { int fake_timer; fake_timer=1024-angle; fake_timer<<=5; if (fake_timer==65536) fake_timer=65535; fake_timer=65536-fake_timer; GLOBALASSERT(fake_timer>=0); GLOBALASSERT(fake_timer<65536); if (agunStatusPointer->gun_tilt->timer!=fake_timer) { agunStatusPointer->WhirrSoundOn=1; } agunStatusPointer->gun_tilt->timer=fake_timer; } } void AGun_UpdateTargetTrackPos(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); if (agunStatusPointer->Target==NULL) { agunStatusPointer->targetTrackPos.vx=0; agunStatusPointer->targetTrackPos.vy=0; agunStatusPointer->targetTrackPos.vz=0; return; } GetTargetingPointOfObject_Far(agunStatusPointer->Target,&agunStatusPointer->targetTrackPos); } int Autogun_TargetFilter(STRATEGYBLOCK *candidate) { /* Reject NULLs and far targets. */ if (candidate==NULL) { return(0); } if (candidate->SBdptr==NULL) { return(0); } /* Shoot pretty much anything. */ switch (candidate->I_SBtype) { case I_BehaviourMarinePlayer: case I_BehaviourAlienPlayer: case I_BehaviourPredatorPlayer: { if (Observer) { return(0); } switch(AvP.PlayerType) { case I_Alien: case I_Predator: return(1); break; case I_Marine: return(0); break; default: GLOBALASSERT(0); return(0); break; } break; } case I_BehaviourDummy: { DUMMY_STATUS_BLOCK *dummyStatusPointer; dummyStatusPointer = (DUMMY_STATUS_BLOCK *)(candidate->SBdataptr); LOCALASSERT(dummyStatusPointer); switch (dummyStatusPointer->PlayerType) { case I_Alien: case I_Predator: return(1); break; case I_Marine: return(1); break; default: GLOBALASSERT(0); return(0); break; } break; } case I_BehaviourAlien: case I_BehaviourQueenAlien: case I_BehaviourFaceHugger: case I_BehaviourPredator: case I_BehaviourPredatorAlien: { if (NPC_IsDead(candidate)) { return(0); } else { return(1); } break; } case I_BehaviourSeal: case I_BehaviourMarine: { if (NPC_IsDead(candidate)) { return(0); } else { return(0); } break; } case I_BehaviourXenoborg: return(1); break; #if SupportWindows95 case I_BehaviourNetGhost: { NETGHOSTDATABLOCK *dataptr; dataptr=candidate->SBdataptr; switch (dataptr->type) { case I_BehaviourMarinePlayer: case I_BehaviourAlienPlayer: case I_BehaviourPredatorPlayer: return(1); break; default: return(1); break; } } break; #endif default: return(0); break; } } STRATEGYBLOCK *Autogun_GetNewTarget(STRATEGYBLOCK *sbPtr) { int neardist; STRATEGYBLOCK *nearest; int a; STRATEGYBLOCK *candidate; MODULE *dmod; dmod=ModuleFromPosition((&sbPtr->DynPtr->Position),playerPherModule); LOCALASSERT(dmod); nearest=NULL; neardist=ONE_FIXED; for (a=0; aDynPtr) { if (Autogun_TargetFilter(candidate)) { VECTORCH offset; int dist; offset.vx=(&sbPtr->DynPtr->Position)->vx-candidate->DynPtr->Position.vx; offset.vy=(&sbPtr->DynPtr->Position)->vy-candidate->DynPtr->Position.vy; offset.vz=(&sbPtr->DynPtr->Position)->vz-candidate->DynPtr->Position.vz; dist=Approximate3dMagnitude(&offset); if (distcontainingModule))) { nearest=candidate; } } } } } } } } return(nearest); } int AGunSight_FrustrumReject(VECTORCH *localOffset) { VECTORCH fixed_offset; #if 0 PrintDebuggingText("Local Offset: %d %d %d\n",localOffset->vx,localOffset->vy,localOffset->vz); #endif fixed_offset=*localOffset; fixed_offset.vy-=300; /* ish */ if ((fixed_offset.vz <0) && ( ((fixed_offset.vy) < (-fixed_offset.vz))&&(fixed_offset.vy>=0)) ||((fixed_offset.vy<0)&&((-fixed_offset.vy) < (-fixed_offset.vz)) )) { /* 180 horizontal, 90 vertical. */ return(1); } else { return(0); } } void AutoGunBehaveFun(STRATEGYBLOCK* sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; int agunIsNear; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* test if we've got a containing module: if we haven't, do nothing. This is important as the object could have been marked for deletion by the visibility management system...*/ if(!sbPtr->containingModule) { DestroyAnyStrategyBlock(sbPtr); /* just to make sure */ return; } if(sbPtr->SBdptr) { agunIsNear=1; LOCALASSERT(ModuleCurrVisArray[(sbPtr->containingModule->m_index)]); } else { agunIsNear=0; } Autogun_VerifyDeltaControllers(sbPtr); /* zero velocity */ LOCALASSERT(sbPtr->DynPtr); sbPtr->DynPtr->LinVelocity.vx = 0; sbPtr->DynPtr->LinVelocity.vy = 0; sbPtr->DynPtr->LinVelocity.vz = 0; sbPtr->DynPtr->LinImpulse.vx = 0; sbPtr->DynPtr->LinImpulse.vy = 0; sbPtr->DynPtr->LinImpulse.vz = 0; /* Target handling. */ if (Validate_Target(agunStatusPointer->Target,agunStatusPointer->Target_SBname)==0) { agunStatusPointer->Target=NULL; } if (agunStatusPointer->Target) { if (!(Autogun_TargetFilter(agunStatusPointer->Target))) { agunStatusPointer->Target=NULL; } } if (agunStatusPointer->Firing) { agunStatusPointer->Firing-=NormalFrameTime; } if (agunStatusPointer->Firing<0) { agunStatusPointer->Firing=0; } if (agunStatusPointer->Target==NULL) { //if ((agunIsNear)||(agunStatusPointer->incidentFlag)) { if (agunIsNear) { /* Get new target. */ agunStatusPointer->Target=Autogun_GetNewTarget(sbPtr); if (agunStatusPointer->Target) { COPY_NAME(agunStatusPointer->Target_SBname,agunStatusPointer->Target->SBname); } AGun_UpdateTargetTrackPos(sbPtr); } } else if (NPCCanSeeTarget(sbPtr,agunStatusPointer->Target,AGUN_NEAR_VIEW_WIDTH)) { AGun_UpdateTargetTrackPos(sbPtr); } else { /* We have a target that we can't see. */ agunStatusPointer->Target=NULL; AGun_UpdateTargetTrackPos(sbPtr); } /* Unset incident flag. */ agunStatusPointer->incidentFlag=0; agunStatusPointer->incidentTimer-=NormalFrameTime; if (agunStatusPointer->incidentTimer<0) { agunStatusPointer->incidentFlag=1; agunStatusPointer->incidentTimer=32767+(FastRandom()&65535); } if (sbPtr->SBDamageBlock.IsOnFire) { /* Why not? */ CauseDamageToObject(sbPtr,&firedamage,NormalFrameTime,NULL); if (agunStatusPointer->incidentFlag) { if ((FastRandom()&65535)<32767) { sbPtr->SBDamageBlock.IsOnFire=0; } } } /* Now, switch by state. */ switch (agunStatusPointer->behaviourState) { case I_inactive: AGunMovement_Centre(sbPtr,2); agunStatusPointer->Target=NULL; break; case I_tracking: if (agunStatusPointer->Target==NULL) { AGunMovement_ScanLeftRight(sbPtr,2); } else { Execute_AGun_Target(sbPtr); } break; case I_disabled: /* Dying function. */ Execute_AGun_Dying(sbPtr); break; default: /* No action? */ break; } /* if we have actually died, we need to remove the strategyblock... so do this here */ if((agunStatusPointer->behaviourState == I_disabled)&&(agunStatusPointer->stateTimer <= 0)) { DestroyAnyStrategyBlock(sbPtr); } agunStatusPointer->WhirrSoundOn=0; AGun_ComputeDeltaValues(sbPtr); if ((agunStatusPointer->WhirrSoundOn)&&(agunStatusPointer->behaviourState!=I_disabled)) { int dist; dist=VectorDistance(&Player->ObWorld,&sbPtr->DynPtr->Position); if (distsoundHandle2==SOUND_NOACTIVEINDEX) { SentryWhirr_SoundData.position=sbPtr->DynPtr->Position; Sound_Play(SID_ED_SENTRYTURN01,"nel",&SentryWhirr_SoundData,&agunStatusPointer->soundHandle2); } else { GLOBALASSERT(ActiveSounds[agunStatusPointer->soundHandle2].soundIndex==SID_ED_SENTRYTURN01); } } else { /* Stop whirr sound. */ if (agunStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { Sound_Stop(agunStatusPointer->soundHandle2); } } } else { /* Stop whirr sound. */ if (agunStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) { Sound_Stop(agunStatusPointer->soundHandle2); } } /* Verify firing. */ if (agunStatusPointer->behaviourState == I_disabled) { agunStatusPointer->Firing=0; } ProveHModel_Far(&agunStatusPointer->HModelController,sbPtr); /* Now, are we firing? */ if (agunStatusPointer->IAmFar) { /* Just to be sure, for now. */ agunStatusPointer->Firing=0; } AGun_MaintainGun(sbPtr); /* Think sounds. */ if (agunStatusPointer->Firing==0) { if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex==SID_SENTRY_GUN) { Sound_Play(SID_SENTRY_END,"d",&sbPtr->DynPtr->Position); } Sound_Stop(agunStatusPointer->soundHandle); } /* Sequences! */ if (agunStatusPointer->HModelController.Sub_Sequence!=XBSS_Powered_Up_Standard) { InitHModelTweening(&agunStatusPointer->HModelController,(ONE_FIXED>>3),(int)HMSQT_Xenoborg,XBSS_Powered_Up_Standard,(ONE_FIXED),1); } } else { if (agunStatusPointer->HModelController.Sub_Sequence!=XBSS_Fire_Bolter) { InitHModelTweening(&agunStatusPointer->HModelController,(ONE_FIXED>>3),(int)HMSQT_Xenoborg,XBSS_Fire_Bolter,(ONE_FIXED>>2),1); } } if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { Sound_Update3d(agunStatusPointer->soundHandle,&sbPtr->DynPtr->Position); } } void AGunMovement_ScanLeftRight(STRATEGYBLOCK *sbPtr,int rate) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* Let's wave the gun around, half full tracking. */ if (agunStatusPointer->gunpandir) { agunStatusPointer->Gun_Pan+=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Pan>(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Pan=(SGUN_PAN_GIMBALL<<3); agunStatusPointer->gunpandir=0; } } else { agunStatusPointer->Gun_Pan-=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Pan<-(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Pan=-(SGUN_PAN_GIMBALL<<3); agunStatusPointer->gunpandir=1; } } if (agunStatusPointer->gun_pan) { agunStatusPointer->gun_pan->Active=1; } /* And centre tilt. */ if (agunStatusPointer->Gun_Tilt<0) { agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Tilt>(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=(SGUN_PAN_GIMBALL<<3); } else if (agunStatusPointer->Gun_Tilt>0) { agunStatusPointer->Gun_Tilt=0; } } else if (agunStatusPointer->Gun_Tilt>0) { agunStatusPointer->Gun_Tilt-=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Tilt<-(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=-(SGUN_PAN_GIMBALL<<3); } else if (agunStatusPointer->Gun_Tilt<0) { agunStatusPointer->Gun_Tilt=0; } } if (agunStatusPointer->gun_tilt) { agunStatusPointer->gun_tilt->Active=1; } } void AGunMovement_Centre(STRATEGYBLOCK *sbPtr,int rate) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* Let's centre pan... */ if (agunStatusPointer->Gun_Pan<0) { agunStatusPointer->Gun_Pan+=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Pan>(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Pan=(SGUN_PAN_GIMBALL<<3); } else if (agunStatusPointer->Gun_Pan>0) { agunStatusPointer->Gun_Pan=0; } } else if (agunStatusPointer->Gun_Pan>0) { agunStatusPointer->Gun_Pan-=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Pan<-(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Pan=-(SGUN_PAN_GIMBALL<<3); } else if (agunStatusPointer->Gun_Pan<0) { agunStatusPointer->Gun_Pan=0; } } if (agunStatusPointer->gun_pan) { agunStatusPointer->gun_pan->Active=1; } /* And centre tilt. */ if (agunStatusPointer->Gun_Tilt<0) { agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Tilt>(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=(SGUN_PAN_GIMBALL<<3); } else if (agunStatusPointer->Gun_Tilt>0) { agunStatusPointer->Gun_Tilt=0; } } else if (agunStatusPointer->Gun_Tilt>0) { agunStatusPointer->Gun_Tilt-=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Tilt<-(SGUN_PAN_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=-(SGUN_PAN_GIMBALL<<3); } else if (agunStatusPointer->Gun_Tilt<0) { agunStatusPointer->Gun_Tilt=0; } } if (agunStatusPointer->gun_tilt) { agunStatusPointer->gun_tilt->Active=1; } } void AGun_GetRelativeAngles(STRATEGYBLOCK *sbPtr, int *anglex, int *angley, VECTORCH *pivotPoint) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; MATRIXCH WtoL; VECTORCH targetPos; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* First, extract relative angle. */ WtoL=sbPtr->DynPtr->OrientMat; TransposeMatrixCH(&WtoL); targetPos=agunStatusPointer->targetTrackPos; targetPos.vx-=pivotPoint->vx; targetPos.vy-=pivotPoint->vy; targetPos.vz-=pivotPoint->vz; RotateVector(&targetPos,&WtoL); /* Now... */ { int offsetx,offsety,offsetz,offseta; offsetx=(targetPos.vx); offsety=(targetPos.vz); offseta=-(targetPos.vy); while( (offsetx>(ONE_FIXED>>2)) ||(offsety>(ONE_FIXED>>2)) ||(offseta>(ONE_FIXED>>2)) ||(offsetx<-(ONE_FIXED>>2)) ||(offsety<-(ONE_FIXED>>2)) ||(offseta<-(ONE_FIXED>>2))) { offsetx>>=1; offsety>>=1; offseta>>=1; } offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety)); if (angley) { (*angley)=ArcTan(offseta,offsetz); if ((*angley)>=3072) (*angley)-=4096; if ((*angley)>=2048) (*angley)=(*angley)-3072; if ((*angley)> 1024) (*angley)=2048-(*angley); } if (anglex) { (*anglex)=ArcTan(offsetx,offsety); if ((*anglex)>=3072) (*anglex)-=4096; if ((*anglex)>=2048) (*anglex)=(*anglex)-4096; } } } int AGunMovement_TrackToAngles(STRATEGYBLOCK *sbPtr,int rate,int in_anglex,int in_angley) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; int real_anglex,angley,online; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* Turn the gun to face a certain way. */ real_anglex=in_anglex; angley=in_angley; online=0; /* Now fix multiples. */ while ((real_anglex>4095)||(real_anglex<0)) { if (real_anglex<0) { real_anglex+=4096; } else if (real_anglex>4095) { real_anglex-=4096; } } if (real_anglex>=3072) real_anglex-=4096; if (real_anglex>=2048) real_anglex=real_anglex-3072; if (real_anglex> 1024) real_anglex=2048-real_anglex; if (angley>=3072) angley-=4096; if (angley>=2048) angley=angley-3072; if (angley> 1024) angley=2048-angley; real_anglex<<=4; angley<<=4; if (agunStatusPointer->Gun_PanGun_Pan+=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Pan>(SGUN_PAN_GIMBALL<<4)) { agunStatusPointer->Gun_Pan=(SGUN_PAN_GIMBALL<<4); } else if (agunStatusPointer->Gun_Pan>real_anglex) { agunStatusPointer->Gun_Pan=real_anglex; online++; } } else if (agunStatusPointer->Gun_Pan>real_anglex) { agunStatusPointer->Gun_Pan-=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Pan<-(SGUN_PAN_GIMBALL<<4)) { agunStatusPointer->Gun_Pan=-(SGUN_PAN_GIMBALL<<4); } else if (agunStatusPointer->Gun_PanGun_Pan=real_anglex; online++; } } else { online++; } if (agunStatusPointer->gun_pan) { agunStatusPointer->gun_pan->Active=1; } /* Now y. */ angley=-angley; /* Oops. */ /* Note that Sentryguns now only track vertically HALF their full traverse. */ /* Those shifts used to be <<4. */ if (agunStatusPointer->Gun_TiltGun_Tilt+=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Tilt>(SGUN_PITCH_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=(SGUN_PITCH_GIMBALL<<3); } else if (agunStatusPointer->Gun_Tilt>angley) { agunStatusPointer->Gun_Tilt=angley; online++; } } else if (agunStatusPointer->Gun_Tilt>angley) { agunStatusPointer->Gun_Tilt-=(NormalFrameTime>>rate); if (agunStatusPointer->Gun_Tilt<-(SGUN_PITCH_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=-(SGUN_PITCH_GIMBALL<<3); } else if (agunStatusPointer->Gun_TiltGun_Tilt=angley; online++; } } else { online++; } if (agunStatusPointer->gun_tilt) { agunStatusPointer->gun_tilt->Active=1; } if (online>1) { return(1); } else { return(0); } } void Execute_AGun_Target(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; int anglex,angley; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); { SECTION_DATA *gun_section; gun_section=GetThisSectionData(agunStatusPointer->HModelController.section_data,"gun"); GLOBALASSERT(gun_section); AGun_GetRelativeAngles(sbPtr,&anglex,&angley,&gun_section->World_Offset); } agunStatusPointer->OnTarget_LastFrame=agunStatusPointer->OnTarget; if (AGunMovement_TrackToAngles(sbPtr,2,anglex,angley)) { /* Pointing at target! */ agunStatusPointer->OnTarget=1; if (agunStatusPointer->OnTarget_LastFrame==0) { /* Newly aquired! */ //Sound_Play(SID_SENTRYGUN_LOCK,"d",&sbPtr->DynPtr->Position); agunStatusPointer->Drama=SENTRYGUN_DRAMA; } if (agunStatusPointer->Drama<=0) { if (agunStatusPointer->Firing==0) { /* Renew firing. */ agunStatusPointer->Firing=(ONE_FIXED>>1); } } else { agunStatusPointer->Firing=0; agunStatusPointer->Drama-=NormalFrameTime; if (agunStatusPointer->Drama<0) { agunStatusPointer->Drama=0; } } } else { agunStatusPointer->OnTarget=0; }; } void AGun_MaintainGun(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; SECTION_DATA *dum; VECTORCH alpha; VECTORCH beta; int multiple,volley_section,totalrounds; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); dum=GetThisSectionData(agunStatusPointer->HModelController.section_data,"flash dummy"); if ((agunStatusPointer->Firing==0)||(dum==NULL)||(agunStatusPointer->IAmFar)) { /* Not firing, go away. */ if (agunStatusPointer->GunFlash) { RemoveNPCGunFlashEffect(agunStatusPointer->GunFlash); agunStatusPointer->GunFlash = NULL; } return; } /* Okay, must be firing. Did we get anyone? */ volley_section=AGUN_ROF*NormalFrameTime; agunStatusPointer->volleyFired+=volley_section; if (agunStatusPointer->volleyFired>(AGUN_VOLLEYSIZE<volleyFired=(AGUN_VOLLEYSIZE<volleyFired>>ONE_FIXED_SHIFT; GLOBALASSERT(totalrounds>=agunStatusPointer->roundsFired); multiple=totalrounds-agunStatusPointer->roundsFired; if ((multiple)&&(agunStatusPointer->ammo==0)) { /* Click ineffectually. */ if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex!=SID_NOAMMO) { Sound_Stop(agunStatusPointer->soundHandle); } } if (agunStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { Sound_Play(SID_NOAMMO,"del",&sbPtr->DynPtr->Position,&agunStatusPointer->soundHandle); } if(agunStatusPointer->GunFlash) { RemoveNPCGunFlashEffect(agunStatusPointer->GunFlash); agunStatusPointer->GunFlash = NULL; } return; } if (multiple>agunStatusPointer->ammo) { multiple=agunStatusPointer->ammo; agunStatusPointer->ammo=0; } else { agunStatusPointer->ammo-=multiple; } agunStatusPointer->roundsFired+=multiple; /* End of volley? */ if (agunStatusPointer->volleyFired==(AGUN_VOLLEYSIZE<volleyFired=0; agunStatusPointer->roundsFired=0; agunStatusPointer->Target=NULL; } while (multiple) { /* Set up LOS. */ //get a random rotation , for error in firing direction MATRIXCH rotate; multiple--; { EULER e; //convert angle from degrees to the engine units int spread=(SentrygunSpread*4096)/360; e.EulerX=(MUL_FIXED(FastRandom()&0xffff,spread*2)-spread)&wrap360; e.EulerY=(MUL_FIXED(FastRandom()&0xffff,spread*2)-spread)&wrap360; e.EulerZ=0; CreateEulerMatrix(&e,&rotate); } alpha = dum->World_Offset; beta.vx=dum->SecMat.mat31; beta.vy=dum->SecMat.mat32; beta.vz=dum->SecMat.mat33; RotateVector(&beta,&rotate); FindPolygonInLineOfSight(&beta,&alpha,0,sbPtr->SBdptr); /* Now deal with LOS_ObjectHitPtr. */ if (LOS_ObjectHitPtr) { if (LOS_HModel_Section) { if (LOS_ObjectHitPtr->ObStrategyBlock) { if (LOS_ObjectHitPtr->ObStrategyBlock->SBdptr) { GLOBALASSERT(LOS_ObjectHitPtr->ObStrategyBlock->SBdptr->HModelControlBlock==LOS_HModel_Section->my_controller); } } } /*Don't allow the sentrygun to destroy 'special' inanimate objects. Doing so ruins some puzzles*/ if(LOS_ObjectHitPtr->ObStrategyBlock) { STRATEGYBLOCK* hit_sbptr=LOS_ObjectHitPtr->ObStrategyBlock; if(hit_sbptr->I_SBtype==I_BehaviourInanimateObject) { INANIMATEOBJECT_STATUSBLOCK* objectstatusptr=(INANIMATEOBJECT_STATUSBLOCK*)hit_sbptr->SBdataptr; if(objectstatusptr->event_target) { /*This object has best be left*/ continue; } } } /* this fn needs updating to take amount of damage into account etc. */ HandleWeaponImpact(&LOS_Point,LOS_ObjectHitPtr->ObStrategyBlock,AMMO_AUTOGUN,&beta, ONE_FIXED, LOS_HModel_Section); } } /* Do muzzle flash... */ if (agunStatusPointer->GunFlash==NULL) { agunStatusPointer->GunFlash = AddNPCGunFlashEffect( &dum->World_Offset,&dum->SecMat, SFX_MUZZLE_FLASH_SMARTGUN); } else { MaintainNPCGunFlashEffect(agunStatusPointer->GunFlash,&dum->World_Offset,&dum->SecMat); } /* Do the sound. */ if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { if (ActiveSounds[agunStatusPointer->soundHandle].soundIndex!=SID_SENTRY_GUN) { Sound_Stop(agunStatusPointer->soundHandle); } } if (agunStatusPointer->soundHandle==SOUND_NOACTIVEINDEX) { SentryFire_SoundData.position=sbPtr->DynPtr->Position; Sound_Play(SID_SENTRY_GUN,"nel",&SentryFire_SoundData,&agunStatusPointer->soundHandle); } } void Execute_AGun_Dying(STRATEGYBLOCK *sbPtr) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* Droop the gun. */ if (agunStatusPointer->Gun_Tilt<8192) { agunStatusPointer->Gun_Tilt+=(NormalFrameTime>>3); if (agunStatusPointer->Gun_Tilt>(SGUN_PITCH_GIMBALL<<3)) { agunStatusPointer->Gun_Tilt=(SGUN_PITCH_GIMBALL<<3); } else if (agunStatusPointer->Gun_Tilt>8192) { agunStatusPointer->Gun_Tilt=8192; } } { DISPLAYBLOCK *dispPtr = sbPtr->SBdptr; /* do we have a displayblock? */ if (dispPtr) { dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; dispPtr->ObFlags2 = agunStatusPointer->stateTimer/2; if (dispPtr->ObFlags2HModelController.DisableBleeding=1; } } } agunStatusPointer->stateTimer -= NormalFrameTime; } static void KillAGun(STRATEGYBLOCK *sbPtr,int wounds,DAMAGE_PROFILE *damage, int multiple,VECTORCH *incoming) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); /* make an explosion sound */ Sound_Play(SID_SENTRYGUNDEST,"d",&sbPtr->DynPtr->Position); agunStatusPointer->stateTimer=AGUN_DYINGTIME; agunStatusPointer->HModelController.Looped=0; agunStatusPointer->HModelController.LoopAfterTweening=0; /* switch state */ agunStatusPointer->behaviourState=I_disabled; /* Fiddle with sequences? */ /* Ensure sufficient sparking. */ KillRandomSections(agunStatusPointer->HModelController.section_data,(ONE_FIXED>>1)); if(agunStatusPointer->death_target_sbptr) { RequestState(agunStatusPointer->death_target_sbptr,agunStatusPointer->death_target_request, 0); } if (agunStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) { /* Well, it shouldn't be! */ Sound_Stop(agunStatusPointer->soundHandle); } } void AGunIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,VECTORCH *incoming) { AUTOGUN_STATUS_BLOCK *agunStatusPointer; LOCALASSERT(sbPtr); LOCALASSERT(sbPtr->DynPtr); agunStatusPointer = (AUTOGUN_STATUS_BLOCK *)(sbPtr->SBdataptr); LOCALASSERT(agunStatusPointer); if (sbPtr->SBDamageBlock.Health <= 0) { /* Oh yes, kill them, too. */ if (agunStatusPointer->behaviourState!=I_disabled) { KillAGun(sbPtr,wounds,damage,multiple,incoming); } } } /*--------------------** ** Loading and Saving ** **--------------------*/ #include "savegame.h" typedef struct agun_save_block { SAVE_BLOCK_STRATEGY_HEADER header; //behaviour block stuff AG_STATE behaviourState; int stateTimer; VECTORCH targetTrackPos; int Gun_Pan; int Gun_Tilt; int incidentFlag; int incidentTimer; int ammo; int roundsFired; int volleyFired; int Firing; int WhirrSoundOn; int Drama; unsigned int createdByPlayer:1; unsigned int gunpandir :1; unsigned int guntiltdir :1; unsigned int IAmFar :1; unsigned int OnTarget :1; unsigned int OnTarget_LastFrame :1; //annoying pointer related things char Target_SBname[SB_NAME_LENGTH]; //strategy block stuff int integrity; DAMAGEBLOCK SBDamageBlock; DYNAMICSBLOCK dynamics; }AGUN_SAVE_BLOCK; //defines for load/save macros #define SAVELOAD_BLOCK block #define SAVELOAD_BEHAV agunStatusPointer void LoadStrategy_Autogun(SAVE_BLOCK_STRATEGY_HEADER* header) { STRATEGYBLOCK* sbPtr; AUTOGUN_STATUS_BLOCK* agunStatusPointer; AGUN_SAVE_BLOCK* block = (AGUN_SAVE_BLOCK*) header; //check the size of the save block if(header->size!=sizeof(*block)) return; //find the existing strategy block sbPtr = FindSBWithName(header->SBname); if(!sbPtr) return; //make sure the strategy found is of the right type if(sbPtr->I_SBtype != I_BehaviourAutoGun) return; agunStatusPointer =(AUTOGUN_STATUS_BLOCK*) sbPtr->SBdataptr; //start copying stuff COPYELEMENT_LOAD(behaviourState) COPYELEMENT_LOAD(stateTimer) COPYELEMENT_LOAD(targetTrackPos) COPYELEMENT_LOAD(Gun_Pan) COPYELEMENT_LOAD(Gun_Tilt) COPYELEMENT_LOAD(incidentFlag) COPYELEMENT_LOAD(incidentTimer) COPYELEMENT_LOAD(ammo) COPYELEMENT_LOAD(roundsFired) COPYELEMENT_LOAD(volleyFired) COPYELEMENT_LOAD(Firing) COPYELEMENT_LOAD(WhirrSoundOn) COPYELEMENT_LOAD(Drama) COPYELEMENT_LOAD(createdByPlayer) COPYELEMENT_LOAD(gunpandir) COPYELEMENT_LOAD(guntiltdir) COPYELEMENT_LOAD(IAmFar) COPYELEMENT_LOAD(OnTarget) COPYELEMENT_LOAD(OnTarget_LastFrame) //load target COPY_NAME(agunStatusPointer->Target_SBname,block->Target_SBname); agunStatusPointer->Target = FindSBWithName(agunStatusPointer->Target_SBname); //copy strategy block stuff *sbPtr->DynPtr = block->dynamics; sbPtr->integrity = block->integrity; sbPtr->SBDamageBlock = block->SBDamageBlock; //load hierarchy { SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); if(hier_header) { LoadHierarchy(hier_header,&agunStatusPointer->HModelController); } } //get delta controller pointers Autogun_VerifyDeltaControllers(sbPtr); Load_SoundState(&agunStatusPointer->soundHandle); Load_SoundState(&agunStatusPointer->soundHandle2); } void SaveStrategy_Autogun(STRATEGYBLOCK* sbPtr) { AUTOGUN_STATUS_BLOCK* agunStatusPointer; AGUN_SAVE_BLOCK* block; GET_STRATEGY_SAVE_BLOCK(block,sbPtr); agunStatusPointer =(AUTOGUN_STATUS_BLOCK*) sbPtr->SBdataptr; //start copying stuff COPYELEMENT_SAVE(behaviourState) COPYELEMENT_SAVE(stateTimer) COPYELEMENT_SAVE(targetTrackPos) COPYELEMENT_SAVE(Gun_Pan) COPYELEMENT_SAVE(Gun_Tilt) COPYELEMENT_SAVE(incidentFlag) COPYELEMENT_SAVE(incidentTimer) COPYELEMENT_SAVE(ammo) COPYELEMENT_SAVE(roundsFired) COPYELEMENT_SAVE(volleyFired) COPYELEMENT_SAVE(Firing) COPYELEMENT_SAVE(WhirrSoundOn) COPYELEMENT_SAVE(Drama) COPYELEMENT_SAVE(createdByPlayer) COPYELEMENT_SAVE(gunpandir) COPYELEMENT_SAVE(guntiltdir) COPYELEMENT_SAVE(IAmFar) COPYELEMENT_SAVE(OnTarget) COPYELEMENT_SAVE(OnTarget_LastFrame) //save target COPY_NAME(block->Target_SBname,agunStatusPointer->Target_SBname); //save strategy block stuff block->dynamics = *sbPtr->DynPtr; block->dynamics.CollisionReportPtr=0; block->integrity = sbPtr->integrity; block->SBDamageBlock = sbPtr->SBDamageBlock; //save the hierarchy SaveHierarchy(&agunStatusPointer->HModelController); Save_SoundState(&agunStatusPointer->soundHandle); Save_SoundState(&agunStatusPointer->soundHandle2); }