/*============================================================================= Name : CloakGenerator.c Purpose : Specifics for the Cloak Generator Created 01/06/1998 by bpasechn Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include "types.h" #include "spaceobj.h" #include "CloakGenerator.h" #include "SoundEvent.h" #include "linkedlist.h" #include "memory.h" #include "universe.h" #include "vector.h" #include "SaveGame.h" #include "genericinterceptor.h" #include "salcapcorvette.h" #include "attack.h" #include "battle.h" CloakGeneratorStatics CloakGeneratorStatic; CloakGeneratorStatics CloakGeneratorStaticRace1; CloakGeneratorStatics CloakGeneratorStaticRace2; scriptStructEntry CloakGeneratorStaticScriptTable[] = { { "CloakingRadius", scriptSetReal32CB, (udword) &(CloakGeneratorStatic.CloakingRadius), (udword) &(CloakGeneratorStatic) }, { "CloakingTime", scriptSetReal32CB, (udword) &(CloakGeneratorStatic.CloakingTime), (udword) &(CloakGeneratorStatic) }, { "DeCloakingTime", scriptSetReal32CB, (udword) &(CloakGeneratorStatic.DeCloakingTime), (udword) &(CloakGeneratorStatic) }, { "MaxCloakingTime", scriptSetReal32CB, (udword) &(CloakGeneratorStatic.MaxCloakingTime), (udword) &(CloakGeneratorStatic) }, { "ReChargeRate", scriptSetReal32CB, (udword) &(CloakGeneratorStatic.ReChargeRate), (udword) &(CloakGeneratorStatic) }, { "MinCharge", scriptSetReal32CB, (udword) &(CloakGeneratorStatic.MinCharge), (udword) &(CloakGeneratorStatic) }, { NULL,NULL,0,0 } }; void CloakGeneratorStaticInit(char *directory,char *filename,struct ShipStaticInfo *statinfo) { CloakGeneratorStatics *CloakGeneratorstat = (statinfo->shiprace == R1) ? &CloakGeneratorStaticRace1 : &CloakGeneratorStaticRace2; statinfo->custstatinfo = CloakGeneratorstat; scriptSetStruct(directory,filename,CloakGeneratorStaticScriptTable,(ubyte *)CloakGeneratorstat); CloakGeneratorstat->CloakingRadiusSqr = CloakGeneratorstat->CloakingRadius*CloakGeneratorstat->CloakingRadius; //Calculate Square of Cloaking Radius CloakGeneratorstat->CloakingTime = 1 / CloakGeneratorstat->CloakingTime; CloakGeneratorstat->DeCloakingTime = 1 / CloakGeneratorstat->DeCloakingTime; } void CloakGeneratorInit(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; CloakGeneratorStatics *cloakgeneratorstatics; cloakgeneratorstatics = (CloakGeneratorStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; spec->CloakOn = FALSE; spec->CloakLowWarning = FALSE; spec->CloakStatus = cloakgeneratorstatics->MaxCloakingTime; listInit(&spec->CloakList); } void CloakGeneratorAddObj(Ship *ship, SpaceObj *objtoadd) { //Adds shiptoadd to 'ship's cloaklist CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; CloakStruct *newcloakstruct; if (bitTest(objtoadd->flags,SOF_Cloaked) || bitTest(objtoadd->flags, SOF_Cloaking) || bitTest(objtoadd->flags, SOF_DeCloaking)) { //if object is cloaked, don't add it...don't even think about it. return; } newcloakstruct = memAlloc(sizeof(CloakStruct),"CloakStruct",0); newcloakstruct->CloakStatus = 0.0f; newcloakstruct->spaceobj = objtoadd; listAddNode(&spec->CloakList,&newcloakstruct->cloaknode,newcloakstruct); //temporary...later make 'cloaking' bitSet(objtoadd->flags, SOF_Cloaking); bitSet(objtoadd->flags, SOF_CloakGenField); //indicate object is in cloak field //should not have to clear the cloaked flag bitClear(objtoadd->flags, SOF_Cloaked); // bitClear(objtoadd->flags, SOF_DeCloaking); } void CloakGeneratorClose(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; listDeleteAll(&spec->CloakList); //delete the list } void CloakGeneratorDied(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; Node *cloaknode; CloakStruct *cloakstruct; cloaknode = spec->CloakList.head; while(cloaknode != NULL) { cloakstruct = (CloakStruct *)listGetStructOfNode(cloaknode); if(bitTest(cloakstruct->spaceobj->flags,SOF_Cloaked)) { bitClear(cloakstruct->spaceobj->flags,SOF_Cloaked); //Force instant decloaking if(cloakstruct->spaceobj->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)cloakstruct->spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (cloakstruct->spaceobj))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(cloakstruct->spaceobj->flags,SOF_Cloaking); bitClear(cloakstruct->spaceobj->flags,SOF_DeCloaking); bitClear(cloakstruct->spaceobj->flags,SOF_CloakGenField); cloaknode = cloaknode->next; } listDeleteAll(&spec->CloakList); //delete the list } void CloakGeneratorRemoveShipReferences(Ship *ship,Ship *shiptoremove) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; Node *cloaknode; CloakStruct *cloakstruct; SpaceObj *objtoremove = (SpaceObj *)shiptoremove; cloaknode = spec->CloakList.head; if (bitTest(objtoremove->flags,SOF_Cloaked) || //if object inquestion isn't cloaked, cloaking bitTest(objtoremove->flags,SOF_Cloaking) || //or decloaking, then we don't walk this list bitTest(objtoremove->flags,SOF_DeCloaking)) //If a cloaked fighter is passed, and it isn't in the list, it will waste time, but this is good enough :) { while(cloaknode != NULL) { cloakstruct = (CloakStruct *)listGetStructOfNode(cloaknode); if (cloakstruct->spaceobj == objtoremove) { listDeleteNode(cloaknode); //delete nodes memory...may not work as I think...ask gary.. break; //done so break and return } cloaknode = cloaknode->next; } if(bitTest(objtoremove->flags, SOF_Cloaked)) { bitClear(objtoremove->flags,SOF_Cloaked); if(objtoremove->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)objtoremove, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (objtoremove))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(objtoremove->flags,SOF_Cloaking); bitClear(objtoremove->flags,SOF_DeCloaking); bitClear(objtoremove->flags,SOF_CloakGenField); } } void CloakAddObjectsInProximity(Ship *cloakship) { Player *playerowner = cloakship->playerowner; Node *objnode = universe.ShipList.head; udword num = universe.ShipList.num; CloakGeneratorStatics *cloakgeneratorstatics; CloakGeneratorSpec *spec = (CloakGeneratorSpec *)cloakship->ShipSpecifics; //maybe don't need Ship *spaceobj; real32 distanceSqr; vector diff; cloakgeneratorstatics = (CloakGeneratorStatics *) ((ShipStaticInfo *)(cloakship->staticinfo))->custstatinfo; while (objnode != NULL) { spaceobj = (Ship *)listGetStructOfNode(objnode); //Rejections... dbgAssert(spaceobj->objtype == OBJ_ShipType); if (spaceobj->playerowner != playerowner) { goto nextnode; // must be players ship inorder to cloak } if( spaceobj->shiptype == SalCapCorvette) { if(((SalCapCorvetteSpec *)spaceobj->ShipSpecifics)->tractorBeam) { goto nextnode; } } if (bitTest(spaceobj->flags,SOF_Cloaked)) { goto nextnode; // if object is cloaked } if(bitTest(spaceobj->flags,SOF_Dead)) { goto nextnode; } if(spaceobj->shiptype == Mothership || spaceobj->shiptype == Carrier) { goto nextnode; } //add more rejections...like collision model. vecSub(diff,spaceobj->posinfo.position,cloakship->posinfo.position); distanceSqr = diff.x*diff.x + diff.y*diff.y + diff.z*diff.z; if(distanceSqr <= cloakgeneratorstatics->CloakingRadiusSqr) { CloakGeneratorAddObj(cloakship, (SpaceObj *) spaceobj); } nextnode: objnode = objnode->next; } } void DeCloakAllObjects(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; Node *cloaknode; CloakStruct *cloakstruct; cloaknode = spec->CloakList.head; while(cloaknode != NULL) { cloakstruct = (CloakStruct *)listGetStructOfNode(cloaknode); bitSet(cloakstruct->spaceobj->flags,SOF_DeCloaking); if(bitTest(cloakstruct->spaceobj->flags, SOF_Cloaked)) { bitClear(cloakstruct->spaceobj->flags,SOF_Cloaked); if(cloakstruct->spaceobj->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)cloakstruct->spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (cloakstruct->spaceobj))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(cloakstruct->spaceobj->flags,SOF_Cloaking); cloaknode = cloaknode->next; } } bool CloakGeneratorSpecialActivate(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; CloakGeneratorStatics *cloakgeneratorstatics; if(spec->CloakOn == TRUE) { //Ships cloak field is on...user wants it off... DeCloakAllObjects(ship); spec->CloakOn = FALSE; //Cloak Field goes off spec->CloakLowWarning = FALSE; //reset flag // soundEvent(ship, PowerOff); // speechEvent(ship, COMM_Cloak_Decloak, 0); if (battleCanChatterAtThisTime(BCE_Decloaking, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_Decloaking, ship, SOUND_EVENT_DEFAULT); } if(ship->playerowner->playerIndex != universe.curPlayerIndex) { /////////////// //speech event for enemy cloakgen decloaking //event num: COMM_F_Cloakgen_Decloaking //battle chatter...camera distance important! //if (battleCanChatterAtThisTime(BCE_COMM_F_Cloakgen_Decloaking, ship)) //{ // battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_COMM_F_Cloakgen_Decloaking, ship, SOUND_EVENT_DEFAULT); //} /// } } else { //Ships cloakfield is off, user wants it on cloakgeneratorstatics = (CloakGeneratorStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; if(spec->CloakStatus >= cloakgeneratorstatics->MinCharge) { //Minimum power is available spec->CloakOn = TRUE; //Cloak Field goes on // soundEvent(ship, PowerOn); // speechEvent(ship, COMM_Cloak_CloakingOn, 0); if (battleCanChatterAtThisTime(BCE_CloakingOn, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_CloakingOn, ship, SOUND_EVENT_DEFAULT); } } else { // speechEvent(ship, COMM_Cloak_InsufficientPower, 0); if (battleCanChatterAtThisTime(BCE_CloakingInsufficientPower, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_CloakingInsufficientPower, ship, SOUND_EVENT_DEFAULT); } } } return TRUE; } void CloakGeneratorJustDisabled(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; if(spec->CloakOn == TRUE) { CloakGeneratorSpecialActivate(ship); } } void CloakGeneratorHouseKeep(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; CloakGeneratorStatics *cloakgeneratorstatics; Node *cloaknode, *temp; SpaceObj *spaceobj; CloakStruct *cloakstruct; vector diff; real32 distanceSqr; cloakgeneratorstatics = (CloakGeneratorStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; if(spec->CloakOn == TRUE) //Cloaking Generator is On { //15th frame..so do a search on other ships within 'proximity' if ((universe.univUpdateCounter & CLOAKGENERATOR_CLOAKCHECK_RATE) == (ship->shipID.shipNumber & CLOAKGENERATOR_CLOAKCHECK_RATE)) { CloakAddObjectsInProximity(ship); //this opp is slow! So maybe decrease frequency } //decrement functionality time spec->CloakStatus -= universe.phystimeelapsed; if ((spec->CloakStatus <= 10.0f) && !spec->CloakLowWarning) { spec->CloakLowWarning = TRUE; // speechEvent(ship, STAT_Cloak_CloakPowerLow, (sdword)spec->CloakStatus); if (battleCanChatterAtThisTime(BCE_CloakingPowerLow, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_CloakingPowerLow, ship, (sdword)spec->CloakStatus); } } //Cloak Field has been on too long if(spec->CloakStatus <= 0.0f) { DeCloakAllObjects(ship); //decloak everything spec->CloakOn = FALSE; //reset flags spec->CloakStatus = 0.0f; //reset CloakStatus spec->CloakLowWarning = FALSE; //reset flag // soundEvent(ship, PowerOff); // speechEvent(ship, COMM_Cloak_Decloak, 0); if (battleCanChatterAtThisTime(BCE_Decloaking, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_Decloaking, ship, SOUND_EVENT_DEFAULT); } } } else //cloak field is off { //recharge cloaking juice at tunable rate spec->CloakStatus += universe.phystimeelapsed*cloakgeneratorstatics->ReChargeRate; if(spec->CloakStatus >= cloakgeneratorstatics->MaxCloakingTime) { spec->CloakStatus = cloakgeneratorstatics->MaxCloakingTime; //cap max cloaking juice } } //perform maintainence on cloaked ships (cloaking,decloaking and continual cloak) cloaknode = spec->CloakList.head; while(cloaknode != NULL) { cloakstruct = (CloakStruct *)listGetStructOfNode(cloaknode); spaceobj = cloakstruct->spaceobj; // wierd crash ... if (spaceobj==NULL) { temp = cloaknode; cloaknode = cloaknode->next; listDeleteNode(temp); continue; } //if spaceobj is dead for some reason, remove its references and stop bothering with it if (bitTest(spaceobj->flags,SOF_Dead)) { //dead so get rid of quickly... cloaknode=cloaknode->next; //we're about to delete this node so move to next CloakGeneratorRemoveShipReferences(ship,(Ship *)spaceobj); //delete everything about it continue; } //perform a change check! //this seems like a waste because we are AGAIN calculating distances. Do better later! if ((universe.univUpdateCounter & CLOAKGENERATOR_CLOAKCHECK_RATE) == (ship->shipID.shipNumber & CLOAKGENERATOR_CLOAKCHECK_RATE)) { vecSub(diff,spaceobj->posinfo.position,ship->posinfo.position); distanceSqr = vecMagnitudeSquared(diff); if(distanceSqr > cloakgeneratorstatics->CloakingRadiusSqr) //maybe add fuzzy logic so thing doesn't always pop in and out in and out in and out... { if(bitTest(spaceobj->flags,SOF_Cloaked)) { bitClear(spaceobj->flags,SOF_Cloaked); if(spaceobj->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (spaceobj))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(spaceobj->flags,SOF_Cloaking); bitSet(spaceobj->flags,SOF_DeCloaking); } //potential problem..ship flys into field..flys out.. //starts to decloak...flys back in, ship will decloak //fully before recloaking...don't worry about since //cloak times too fast too care } if(spaceobj->objtype == OBJ_ShipType) { if( ((Ship *)spaceobj)->shiptype == SalCapCorvette) { if(((SalCapCorvetteSpec *)((Ship *)spaceobj)->ShipSpecifics)->tractorBeam) { //attached so decloak if(bitTest(spaceobj->flags,SOF_Cloaked)) { bitClear(spaceobj->flags,SOF_Cloaked); if(spaceobj->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (spaceobj))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(spaceobj->flags,SOF_Cloaking); bitSet(spaceobj->flags,SOF_DeCloaking); } } } //Case 1, object is cloaking if(bitTest(spaceobj->flags,SOF_Cloaking)) { //object is cloaking..so keep cloaking it /***** calculated the inverse of CloakingTime in CloakGeneratorStaticInit and multiply instead of divide *****/ cloakstruct->CloakStatus += universe.phystimeelapsed*cloakgeneratorstatics->CloakingTime; if(cloakstruct->CloakStatus >= 1.0f) { //object is now cloaked...so stop cloaking it and make it fully 'cloaked' cloakstruct->CloakStatus = 1.0f; //set for assurance bitSet(spaceobj->flags,SOF_Cloaked); //make cloaked bitClear(spaceobj->flags,SOF_Cloaking); //stop from cloaking if(spaceobj->objtype == OBJ_ShipType) { shipHasJustCloaked((Ship *)spaceobj); SpawnCloakingEffect((Ship *)spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_ON]); //RemoveShipFromBeingTargeted(&universe.mainCommandLayer,(Ship *)spaceobj,FALSE); } else if(spaceobj->objtype == OBJ_AsteroidType) { //need to remove the asteroid from resource collectors dbgMessagef("\nMake Bryce remove asteroids from game info since you just cloaked one."); } } } else if(bitTest(spaceobj->flags,SOF_DeCloaking)) { //object is decloaking, so keep decloaking it /***** calculated the inverse of DeCloakingTime in CloakGeneratorStaticInit and multiply instead of divide *****/ cloakstruct->CloakStatus -= universe.phystimeelapsed*cloakgeneratorstatics->DeCloakingTime; if(cloakstruct->CloakStatus <= 0.0f) { //Object is now fully decloaked so stop decloaking it and remove it from the list cloaknode=cloaknode->next; //we're about to delete this node so move to next CloakGeneratorRemoveShipReferences(ship,(Ship *)spaceobj); //delete everything about it continue; //we now continue the loop rather than letting the other code continue :) } } cloaknode = cloaknode->next; } } void CloakGeneratorAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist) { attackStraightForward(ship,target,4000.0f,3000.0f); } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void SaveCloakStruct(CloakStruct *cloakStruct) { SaveChunk *chunk; CloakStruct *savecontents; chunk = CreateChunk(BASIC_STRUCTURE,sizeof(CloakStruct),cloakStruct); savecontents = (CloakStruct *)chunkContents(chunk); savecontents->spaceobj = (SpaceObj *)SpaceObjRegistryGetID(savecontents->spaceobj); SaveThisChunk(chunk); memFree(chunk); } void CloakGenerator_Save(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; Node *node = spec->CloakList.head; sdword cur = 0; SaveInfoNumber(spec->CloakList.num); while (node != NULL) { cur++; SaveCloakStruct((CloakStruct *)listGetStructOfNode(node)); node = node->next; } dbgAssert(cur == spec->CloakList.num); } CloakStruct *LoadCloakStruct(void) { SaveChunk *chunk; CloakStruct *cloakStruct; chunk = LoadNextChunk(); VerifyChunk(chunk,BASIC_STRUCTURE,sizeof(CloakStruct)); cloakStruct = memAlloc(sizeof(CloakStruct),"CloakStruct",0); memcpy(cloakStruct,chunkContents(chunk),sizeof(CloakStruct)); memFree(chunk); return cloakStruct; } void CloakGenerator_Load(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; sdword num; sdword i; CloakStruct *cloakStruct; num = LoadInfoNumber(); listInit(&spec->CloakList); for (i=0;iCloakList,&cloakStruct->cloaknode,cloakStruct); } } void CloakGenerator_Fix(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; Node *node = spec->CloakList.head; CloakStruct *cloakStruct; while (node != NULL) { cloakStruct = (CloakStruct *)listGetStructOfNode(node); cloakStruct->spaceobj = SpaceObjRegistryGetObj((sdword)cloakStruct->spaceobj); node = node->next; } } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" CustShipHeader CloakGeneratorHeader = { CloakGenerator, sizeof(CloakGeneratorSpec), CloakGeneratorStaticInit, NULL, CloakGeneratorInit, CloakGeneratorClose, CloakGeneratorAttack, NULL, NULL, CloakGeneratorSpecialActivate, NULL, CloakGeneratorHouseKeep, CloakGeneratorRemoveShipReferences, CloakGeneratorDied, NULL, CloakGenerator_Save, CloakGenerator_Load, CloakGenerator_Fix };