#include "3dc.h" #include "inline.h" #include "module.h" #include "stratdef.h" #include "gamedef.h" #include "bh_types.h" #include "dynblock.h" #define UseLocalAssert Yes #include "ourasert.h" #include "bh_alien.h" #include "bh_marin.h" #include "bh_xeno.h" #include "bh_corpse.h" #include "bh_debri.h" #include "pldnet.h" /* this attaches runtime and precompiled object strategyblocks */ /*** exported globals *************/ int NumActiveStBlocks; STRATEGYBLOCK *ActiveStBlockList[maxstblocks]; /*** static globals ***************/ static int NumFreeStBlocks; static STRATEGYBLOCK *FreeStBlockList[maxstblocks]; static STRATEGYBLOCK **FreeStBlockListPtr = &FreeStBlockList[maxstblocks-1]; STRATEGYBLOCK FreeStBlockData[maxstblocks]; static STRATEGYBLOCK **ActiveStBlockListPtr = &ActiveStBlockList[0]; unsigned int IncrementalSBname; /**** improted globals ************/ extern int cosine[], sine[]; /* Support functions for Strategy Blocks */ void InitialiseStrategyBlocks(void) { STRATEGYBLOCK *FreeBlkPtr = &FreeStBlockData[0]; FreeStBlockListPtr = &FreeStBlockList[maxstblocks-1]; for(NumFreeStBlocks=0; NumFreeStBlocks < maxstblocks; NumFreeStBlocks++) { FreeStBlockList[NumFreeStBlocks] = FreeBlkPtr; FreeBlkPtr->SBflags.destroyed_but_preserved=0; #if debug FreeBlkPtr->SBIsValid = 0; #endif FreeBlkPtr++; } /* KJL 17:31:18 11/13/96 - seems like a logical place to initialise dynamics blocks */ InitialiseDynamicsBlocks(); NumActiveStBlocks = 0; ActiveStBlockListPtr = &ActiveStBlockList[0]; IncrementalSBname=0; } STRATEGYBLOCK* AllocateStrategyBlock(void) { STRATEGYBLOCK *FreeBlkPtr = 0; /* Default to null ptr */ int *sptr; int i; if(NumFreeStBlocks) { FreeBlkPtr = *FreeStBlockListPtr--; NumFreeStBlocks--; /* One less free block */ /* Clear the block */ sptr = (int *)FreeBlkPtr; for(i = sizeof(STRATEGYBLOCK)/4; i!=0; i--) { *sptr++ = 0; } } return(FreeBlkPtr); } void DeallocateStrategyBlock(STRATEGYBLOCK *sptr) { int a; /* Reset name */ for(a = 0; a < SB_NAME_LENGTH; a++) { sptr->SBname[a] = '\0'; } FreeStBlockListPtr++; *FreeStBlockListPtr = sptr; NumFreeStBlocks++; /* One more free block */ } STRATEGYBLOCK* CreateActiveStrategyBlock(void) { STRATEGYBLOCK *sb; sb = AllocateStrategyBlock(); if(sb) { #if debug GLOBALASSERT(sb->SBIsValid == 0); sb->SBIsValid = 1; #endif *ActiveStBlockListPtr++ = sb; NumActiveStBlocks++; } return sb; } int DestroyActiveStrategyBlock(STRATEGYBLOCK* sb) { int j = -1; int i; /* If the block ptr is OK, search the Active Blocks List */ if(sb) { for(i = 0; i < NumActiveStBlocks && j!=0; i++) { if(ActiveStBlockList[i] == sb) { ActiveStBlockList[i] = ActiveStBlockList[NumActiveStBlocks-1]; NumActiveStBlocks--; ActiveStBlockListPtr--; if(!sb->SBflags.preserve_until_end_of_level) { DeallocateStrategyBlock(sb); /* Back to Free List */ } else { sb->SBflags.destroyed_but_preserved=1; } j = 0; /* Flag OK */ } } } return(j); } STRATEGYBLOCK * AttachNewStratBlock ( MODULE* moptr, MODULEMAPBLOCK* momptr, DISPLAYBLOCK* dptr ) { /*oh for a constructor*/ /* fails if any of the above has a stratgey block attached*/ STRATEGYBLOCK* sptr; int i; GLOBALASSERT(momptr || dptr); sptr = CreateActiveStrategyBlock(); if (sptr == 0) return 0; InitialiseSBValues(sptr); for(i = 0; i < SB_NAME_LENGTH; i++); { sptr->SBname[i] = '\0'; } sptr->SBmomptr = momptr; if(moptr) { /* GLOBALASSERT(!moptr->m_sbptr); HACK*/ moptr->m_sbptr = sptr; sptr->SBmoptr = moptr; } if(dptr) { GLOBALASSERT(!dptr->ObStrategyBlock); dptr->ObStrategyBlock = sptr; sptr->SBdptr = dptr; } else { sptr->SBflags.no_displayblock = 1; } return(sptr); } void InitialiseSBValues(STRATEGYBLOCK* sptr) { sptr->I_SBtype = I_BehaviourNull; sptr->SBdataptr = (void *)0x0; sptr->SBDamageBlock.Health=0; sptr->SBDamageBlock.Armour=0; sptr->SBDamageBlock.SB_H_flags.AcidResistant=0; sptr->SBDamageBlock.SB_H_flags.FireResistant=0; sptr->SBDamageBlock.SB_H_flags.ElectricResistant=0; sptr->SBDamageBlock.SB_H_flags.PerfectArmour=0; sptr->SBDamageBlock.SB_H_flags.ElectricSensitive=0; sptr->SBDamageBlock.SB_H_flags.Indestructable=0; sptr->SBflags.please_destroy_me = 0; sptr->SBflags.no_displayblock = 0; sptr->SBflags.request_operate = 0; sptr->SBflags.preserve_until_end_of_level = 0; sptr->SBflags.destroyed_but_preserved = 0; sptr->SBflags.not_on_motiontracker = 0; sptr->integrity = 0; sptr->maintainVisibility = 0; /* patrRWH - function to search thgough the list of active*/ sptr->containingModule = (MODULE *)0; /* patrstrat blocks and return the pointer*/ sptr->shapeIndex = 0; /* patr*/ sptr->SBmoptr = (MODULE*)0x0; sptr->SBmomptr = (MODULEMAPBLOCK*)0x0; sptr->SBmorphctrl = (MORPHCTRL*)0x0; sptr->SBdptr=NULL; sptr->name=0; } /* RWH - function to search thgough the list of active strat blocks and return the pointer */ STRATEGYBLOCK* FindSBWithName(char* id_name) { int stratblock = NumActiveStBlocks; int i; GLOBALASSERT(stratblock); if(!id_name) return NULL; //If the name is all 0`s I want to return a null pointer - Richard. for(i=0;i= 0) { STRATEGYBLOCK* sbptr = ActiveStBlockList[stratblock]; GLOBALASSERT(sbptr); if(sbptr->SBname) { if(NAME_ISEQUAL(sbptr->SBname, id_name)) { return((sbptr)); } } } // we have to return null for lifts - so that // we know that the lift is outside the env return(NULL); } static STRATEGYBLOCK SB_Preserved[MAX_PRESERVED_SB]; static int Num_SB_Preserved; void InitPreservedSBs() { Num_SB_Preserved = 0; } void PreserveStBlocksInModule(MODULE* containing_mod) { // this used within level - find objects in module // all will have sbs int i; int max_x, min_x, max_y, min_y, max_z, min_z; max_x = containing_mod->m_maxx + containing_mod->m_world.vx; min_x = containing_mod->m_minx + containing_mod->m_world.vx; max_y = containing_mod->m_maxy + containing_mod->m_world.vy; min_y = containing_mod->m_miny + containing_mod->m_world.vy; max_z = containing_mod->m_maxz + containing_mod->m_world.vz; min_z = containing_mod->m_minz + containing_mod->m_world.vz; GLOBALASSERT(Num_SB_Preserved == 0); for(i = 0; i < NumActiveStBlocks && Num_SB_Preserved < MAX_PRESERVED_SB; i++) { VECTORCH obj_world; STRATEGYBLOCK *sbptr; DYNAMICSBLOCK *dynptr; sbptr = ActiveStBlockList[i]; if(!(dynptr = sbptr->DynPtr)) continue; obj_world = dynptr->Position; if(obj_world.vx < max_x) if(obj_world.vx > min_x) if(obj_world.vz < max_z) if(obj_world.vz > min_z) if(obj_world.vy < max_y) if(obj_world.vy > min_y) { // copy name into somthing if(sbptr->I_SBtype == I_BehaviourMarinePlayer || sbptr->I_SBtype == I_BehaviourMarinePlayer || sbptr->I_SBtype == I_BehaviourMarinePlayer) { SB_Preserved[Num_SB_Preserved] = *sbptr; Num_SB_Preserved++; } } } } BOOL SBNeededForNextEnv(STRATEGYBLOCK* sbptr) { int i = 0; if(Num_SB_Preserved == 0) return(0); if (sbptr->I_SBtype!=I_BehaviourMarinePlayer) if (sbptr->I_SBtype!=I_BehaviourAlienPlayer) if (sbptr->I_SBtype!=I_BehaviourPredatorPlayer) if (NAME_ISNULL(sbptr->SBname)) return(0); for(i = 0; i < Num_SB_Preserved; i++) { STRATEGYBLOCK *pres_sbptr; pres_sbptr = &SB_Preserved[i]; if(NAME_ISEQUAL(pres_sbptr->SBname, sbptr->SBname)) return(1); } return(0); } void AddPreservedSBsToActiveList() { int i; STRATEGYBLOCK *new_sbptr; for(i = 0; i < Num_SB_Preserved; i++) { new_sbptr = CreateActiveStrategyBlock(); *new_sbptr = SB_Preserved[i]; if(new_sbptr->I_SBtype == I_BehaviourMarinePlayer || new_sbptr->I_SBtype == I_BehaviourMarinePlayer || new_sbptr->I_SBtype == I_BehaviourMarinePlayer) { DYNAMICSBLOCK *playerDynPtr; Player->ObStrategyBlock = new_sbptr; playerDynPtr = Player->ObStrategyBlock->DynPtr; // Need to copy some of the preserved SB info into the appropriate places Player->ObWorld = playerDynPtr->Position; Player->ObMat = playerDynPtr->OrientMat; Player->ObEuler = playerDynPtr->OrientEuler; playerDynPtr->PrevPosition = playerDynPtr->Position; playerDynPtr->PrevOrientMat = playerDynPtr->OrientMat; playerDynPtr->PrevOrientEuler = playerDynPtr->OrientEuler; playerDynPtr->LinVelocity.vx = 0; playerDynPtr->LinVelocity.vy = 0; playerDynPtr->LinVelocity.vz = 0; playerDynPtr->LinImpulse.vx = 0; playerDynPtr->LinImpulse.vy = 0; playerDynPtr->LinImpulse.vz = 0; playerDynPtr->AngVelocity.EulerX = 0; playerDynPtr->AngVelocity.EulerY = 0; playerDynPtr->AngVelocity.EulerZ = 0; playerDynPtr->AngImpulse.EulerX = 0; playerDynPtr->AngImpulse.EulerY = 0; playerDynPtr->AngImpulse.EulerZ = 0; } // we will almost certainly need // some clean up here. esp for the // LIFT_FLOOR_SWITCHES and for objects // whose shape reference has changed } } void TeleportPreservedSBsToNewEnvModule(MODULE *new_pos, MODULE* old_pos, int orient_change) { int i; VECTORCH mod_offset; mod_offset.vx = new_pos->m_world.vx - old_pos->m_world.vx; mod_offset.vy = new_pos->m_world.vy - old_pos->m_world.vy; mod_offset.vz = new_pos->m_world.vz - old_pos->m_world.vz; for(i = 0; i < Num_SB_Preserved; i++) { VECTORCH obj_world; VECTORCH pos_rel; STRATEGYBLOCK *sbptr; DYNAMICSBLOCK *dynptr; sbptr = &SB_Preserved[i]; dynptr = sbptr->DynPtr; GLOBALASSERT(dynptr); obj_world = sbptr->DynPtr->Position; { // okay we need to find our relative position to the moduke int cos; int sin; int angle; MATRIXCH mat; pos_rel.vx = dynptr->Position.vx - old_pos->m_world.vx; pos_rel.vy = dynptr->Position.vy - old_pos->m_world.vy; pos_rel.vz = dynptr->Position.vz - old_pos->m_world.vz; if(orient_change == 1 || orient_change == -3) angle = 1024; else if(orient_change == 2 || orient_change == -2) angle = 2048; else if(orient_change == 3 || orient_change == -1) angle = 3072; else angle = 0; cos = GetCos(angle); sin = GetSin(angle); mat.mat11 = cos; mat.mat12 = 0; mat.mat13 = -sin; mat.mat21 = 0; mat.mat22 = 65536; mat.mat23 = 0; mat.mat31 = sin; mat.mat32 = 0; mat.mat33 = cos; // rotate the relative object about the center of the // module and rotate the abject about its own y-axis RotateVector(&pos_rel, &mat); MatrixMultiply(&dynptr->OrientMat,&mat,&dynptr->OrientMat); MatrixToEuler(&dynptr->OrientMat, &dynptr->OrientEuler); } #if 0 dynptr->Position.vx = mod_offset.vx; dynptr->Position.vy = mod_offset.vy; dynptr->Position.vz = mod_offset.vz; dynptr->PrevPosition.vx = mod_offset.vx; dynptr->PrevPosition.vy = mod_offset.vy; dynptr->PrevPosition.vz = mod_offset.vz; #endif dynptr->Position.vx = pos_rel.vx + new_pos->m_world.vx; dynptr->Position.vy = pos_rel.vy + new_pos->m_world.vy; dynptr->Position.vz = pos_rel.vz + new_pos->m_world.vz; dynptr->PrevPosition.vx = -pos_rel.vx + old_pos->m_world.vx; dynptr->PrevPosition.vy = -pos_rel.vy + old_pos->m_world.vy; dynptr->PrevPosition.vz = -pos_rel.vz + old_pos->m_world.vz; } } // RWH 5/6/97 these next two functions were 1, changed and 2, added // to deal with deallocating stblocks at the end of behaviours // this stops problems with accessing defunct strategy blocks // via collision reports void DestroyAnyStrategyBlock(STRATEGYBLOCK *sbptr) { GLOBALASSERT(sbptr); sbptr->SBflags.please_destroy_me = 1; } void RemoveDestroyedStrategyBlocks(void) { /* Go backwards through the strategy block. This should prevent any strategy blocks from being skipped when they get shuffled down from the end of the array. */ int i = NumActiveStBlocks; while(i) { STRATEGYBLOCK* sbptr = ActiveStBlockList[--i]; if(sbptr->SBflags.please_destroy_me) { RemoveBehaviourStrategy(sbptr); } else { /* Also... gibb aliens? */ if (sbptr->I_SBtype==I_BehaviourAlien) { ALIEN_STATUS_BLOCK *alienStatusPointer; LOCALASSERT(sbptr); LOCALASSERT(sbptr->DynPtr); alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbptr->SBdataptr); if (alienStatusPointer->GibbFactor>0) { Extreme_Gibbing(sbptr,alienStatusPointer->HModelController.section_data,alienStatusPointer->GibbFactor); alienStatusPointer->GibbFactor=0; } else if (alienStatusPointer->GibbFactor<0) { KillRandomSections(alienStatusPointer->HModelController.section_data,alienStatusPointer->GibbFactor); alienStatusPointer->GibbFactor=0; } } else if ( (sbptr->I_SBtype==I_BehaviourMarine) || (sbptr->I_SBtype==I_BehaviourSeal) ) { MARINE_STATUS_BLOCK *marineStatusPointer; LOCALASSERT(sbptr); LOCALASSERT(sbptr->DynPtr); marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbptr->SBdataptr); if (marineStatusPointer->GibbFactor>0) { Extreme_Gibbing(sbptr,marineStatusPointer->HModelController.section_data,marineStatusPointer->GibbFactor); marineStatusPointer->GibbFactor=0; } else if (marineStatusPointer->GibbFactor<0) { KillRandomSections(marineStatusPointer->HModelController.section_data,-(marineStatusPointer->GibbFactor)); marineStatusPointer->GibbFactor=0; } } else if (sbptr->I_SBtype==I_BehaviourPredator) { PREDATOR_STATUS_BLOCK *predatorStatusPointer; LOCALASSERT(sbptr); LOCALASSERT(sbptr->DynPtr); predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbptr->SBdataptr); if (predatorStatusPointer->GibbFactor>0) { Extreme_Gibbing(sbptr,predatorStatusPointer->HModelController.section_data,predatorStatusPointer->GibbFactor); predatorStatusPointer->GibbFactor=0; } else if (predatorStatusPointer->GibbFactor<0) { KillRandomSections(predatorStatusPointer->HModelController.section_data,-(predatorStatusPointer->GibbFactor)); predatorStatusPointer->GibbFactor=0; } } else if (sbptr->I_SBtype==I_BehaviourXenoborg) { XENO_STATUS_BLOCK *xenoStatusPointer; LOCALASSERT(sbptr); LOCALASSERT(sbptr->DynPtr); xenoStatusPointer=(XENO_STATUS_BLOCK *)(sbptr->SBdataptr); if (xenoStatusPointer->GibbFactor>0) { Extreme_Gibbing(sbptr,xenoStatusPointer->HModelController.section_data,xenoStatusPointer->GibbFactor); xenoStatusPointer->GibbFactor=0; } else if (xenoStatusPointer->GibbFactor<0) { KillRandomSections(xenoStatusPointer->HModelController.section_data,-(xenoStatusPointer->GibbFactor)); xenoStatusPointer->GibbFactor=0; } } else if (sbptr->I_SBtype==I_BehaviourNetCorpse) { NETCORPSEDATABLOCK *corpseStatusPointer; LOCALASSERT(sbptr); LOCALASSERT(sbptr->DynPtr); corpseStatusPointer=(NETCORPSEDATABLOCK *)(sbptr->SBdataptr); if(corpseStatusPointer->GibbFactor) { /*get a seed for the RNG so that we can send gibbing to other network players*/ int seed=FastRandom(); SetSeededFastRandom(seed); if(AvP.Network != I_No_Network) { AddNetMsg_Gibbing(sbptr,corpseStatusPointer->GibbFactor,seed); } if (corpseStatusPointer->GibbFactor>0) { Extreme_Gibbing(sbptr,corpseStatusPointer->HModelController.section_data,corpseStatusPointer->GibbFactor); corpseStatusPointer->GibbFactor=0; } else if (corpseStatusPointer->GibbFactor<0) { KillRandomSections(corpseStatusPointer->HModelController.section_data,-(corpseStatusPointer->GibbFactor)); corpseStatusPointer->GibbFactor=0; } } } else if (sbptr->I_SBtype==I_BehaviourHierarchicalFragment) { HDEBRIS_BEHAV_BLOCK *debrisStatusPointer; LOCALASSERT(sbptr); LOCALASSERT(sbptr->DynPtr); debrisStatusPointer=(HDEBRIS_BEHAV_BLOCK *)(sbptr->SBdataptr); if (debrisStatusPointer->GibbFactor>0) { Extreme_Gibbing(sbptr,debrisStatusPointer->HModelController.section_data,debrisStatusPointer->GibbFactor); debrisStatusPointer->GibbFactor=0; } else if (debrisStatusPointer->GibbFactor<0) { KillRandomSections(debrisStatusPointer->HModelController.section_data,-(debrisStatusPointer->GibbFactor)); debrisStatusPointer->GibbFactor=0; } } } } } void DestroyAllStrategyBlocks(void) { int i = 0; int a = NumActiveStBlocks; while(i < a) { RemoveBehaviourStrategy(ActiveStBlockList[i++]); } //get rid of all the strategyblocks that have been preserved until the end of the level for(i=0;i0xffffff) { IncrementalSBname=1; } *((int *)&sbPtr->SBname[4])=IncrementalSBname; if(AvP.Network != I_No_Network) { //modify name to ensure uniqueness between players extern DPID AVPDPNetID; sbPtr->SBname[SB_NAME_LENGTH-1]=+10+PlayerIdInPlayerList(AVPDPNetID); /* Just to make sure... */ } else { sbPtr->SBname[SB_NAME_LENGTH-1]=1; /* Just to make sure... */ } } void GivePlayerCloakAway(void) { PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr); playerStatusPtr->cloakPositionGivenAway = 1; playerStatusPtr->cloakPositionGivenAwayTimer = PLAYERCLOAK_POSTIONGIVENAWAYTIME; }