/*============================================================================= Name : SalCapCorvette.c Purpose : Specifics for the Salvage Capture Corvette Created 11/5/1997 by khent Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include #include #include "types.h" #include "debug.h" #include "spaceobj.h" #include "SalCapCorvette.h" #include "statscript.h" #include "gun.h" #include "attack.h" #include "DefaultShip.h" #include "select.h" #include "shipselect.h" #include "univupdate.h" #include "aiship.h" #include "aitrack.h" #include "memory.h" #include "universe.h" #include "fastmath.h" #include "dock.h" #include "vector.h" #include "commandlayer.h" #include "soundevent.h" #include "physics.h" #include "multiplayergame.h" #include "SaveGame.h" #include "aivar.h" #include "prim3d.h" #include "render.h" #include "clamp.h" #include "nis.h" #include "madlinkin.h" #include "madlinkindefs.h" #include "mothership.h" #include "collision.h" #include "carrier.h" #include "alliance.h" #include "tactics.h" #include "ping.h" #include "singleplayer.h" #include "battle.h" #include "commandwrap.h" #include "genericdefender.h" #include "gravwellgenerator.h" #include "randy.h" #define DEBUG_SALCAP #define SALVAGE_BEGIN 0 #define SAL_FLYTOTARGET 1 #define SAL_DOCKINGSTATE1 3 #define SAL_DOCKWITHLIGHTS1 4 #define SAL_DOCKWITHOUTLIGHTS1 5 #define SAL_WL_FLYTOWITHINCONE 6 #define SAL_CLAMPED 8 #define SAL_STRIPTECH 9 #define SAL_TECH_UNDOCK 10 #define SAL_SALVAGE1 11 #define SAL_UNDOCK_AND_QUIT 12 #define SAL_FLYBACK_TO_DOCKING_SHIP 13 #define SAL_DOCKINGSTAGE 14 #define SAL_TECH_TAKE_TECH_HOME 15 #define SAL_WAIT 16 #define SAL_DO_DOCK 17 #define SAL_backoff 35 #define SAL_DO_DOCK2 18 #define SAL_DO_DOCK3 19 #define SAL_DONE_DOCKING 20 #define WAYPOINTHACK2 21 #define SAL_DO_DOCK25 22 #define DOORDEAL 23 #define DO_HARVEST 24 #define SAL_DO_DAMAGE 25 #define SAL_WAYPOINTHACK 26 #define SAL_JUST_DO_DAMAGE 27 #define NO_INDEX 999192 #define SAL_GOTOPOINT_LIMITVEL 0.0f //prototyped here to avoid warning!!! void clLaunchShip(CommandLayer *comlayer,SelectCommand *selectcom,ShipPtr receiverShip); void startTractorBeam(Ship *ship, SpaceObjRotImpTargGuidanceShipDerelict *target); SalCapCorvetteStatics SalCapCorvetteStaticRace1; SalCapCorvetteStatics SalCapCorvetteStaticRace2; SalCapCorvetteStatics SalCapCorvetteStaticDawg; scriptStructEntry SalCapCorvetteStaticTable[] = { { "HealthThreshold", scriptSetReal32CB, (udword) &(SalCapCorvetteStatic.HealthThreshold), (udword) &(SalCapCorvetteStatic) }, { "healthRemovedPerSecond", scriptSetReal32CB, (udword) &(SalCapCorvetteStatic.healthRemovedPerSecond), (udword) &(SalCapCorvetteStatic) }, { "getTechTime", scriptSetReal32CB, (udword) &(SalCapCorvetteStatic.getTechTime), (udword) &(SalCapCorvetteStatic) }, { "flyToDistance", scriptSetReal32CB, (udword) &(SalCapCorvetteStatic.flyToDistance), (udword) &(SalCapCorvetteStatic) }, { "maxPushingVelocitySingle", scriptSetReal32CB, (udword) &(SalCapCorvetteStatic.maxPushingVelocitySingle), (udword) &(SalCapCorvetteStatic) }, { "noLightClampingDistance", scriptSetReal32CB, (udword) &(SalCapCorvetteStatic.noLightClampingDistance), (udword) &(SalCapCorvetteStatic) }, { NULL,NULL,0,0 } }; udword salvageNumNeeded(Ship *ship, SpaceObjRotImpTarg *target); void salvageSetDockVector(Ship *ship, Ship *dockwith,vector *trackHeading, vector *trackUp,vector *coneheadingInWorldCoordSys); bool salvageTargetTrackVector(Ship *ship, vector *trackvector); bool handOffTargetToDockWith(Ship *ship); void SalCapRemoveShipReferences(Ship *ship, Ship *shiptoremove); void SalCapCorvetteStaticInit(char *directory,char *filename,struct ShipStaticInfo *statinfo) { SalCapCorvetteStatics *corvstat; if(statinfo->shiprace == Traders) { corvstat = &SalCapCorvetteStaticDawg; } else { corvstat = (statinfo->shiprace == R1) ? &SalCapCorvetteStaticRace1 : &SalCapCorvetteStaticRace2; } memset(corvstat,sizeof(*corvstat),0); scriptSetStruct(directory,filename,AttackSideStepParametersScriptTable,(ubyte *)&corvstat->sidestepParameters); scriptSetStruct(directory,filename,SalCapCorvetteStaticTable,(ubyte *)corvstat); statinfo->custstatinfo = corvstat; } /*----------------------------------------------------------------------------- Name : CleanSalCapSpec(ship) Description : initializes the sal/cap's special variables Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void CleanSalCapSpec(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; spec->target = NULL; if(!spec->groupme) spec->dockwith = NULL; spec->dockindex = 0; spec->salvageIndex = NO_INDEX; //init it with this! spec->salvageState = SALVAGE_BEGIN; spec->salvageAttributes = 0; spec->timeCounter = 0.0f; spec->getTechTime=0.0f; spec->tractorBeam=FALSE; spec->noAvoid=FALSE; bitClear(ship->specialFlags,SPECIAL_BrokenFormation); } void SalCapCorvetteInit(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; attackSideStepInit(&spec->attacksidestep); spec->groupme = FALSE; CleanSalCapSpec(ship); spec->noDamageTarget = NULL; spec->noDamageTargetTime = 0.0f; ship->specialFlags |= SPECIAL_IsASalvager; // set flag for the dawg and salcap ships } /* void SalCapCorvetteAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; SalCapCorvetteStatics *corvstat = (SalCapCorvetteStatics *)((ShipStaticInfo *)ship->staticinfo)->custstatinfo; attackSideStep(ship,target,&spec->attacksidestep,&corvstat->sidestepParameters); } void SalCapCorvetteAttackPassive(Ship *ship,Ship *target,bool rotate) { if ((rotate) & ((bool)((ShipStaticInfo *)(ship->staticinfo))->rotateToRetaliate)) { attackPassiveRotate(ship,target); } else { attackPassive(ship,target); } } */ //temporary test to generate a derelict bool SalCapCorvetteSpecialActivate(Ship *ship) { vector place; matGetVectFromMatrixCol3(place,ship->rotinfo.coordsys); vecScalarMultiply(place,place, 2000.0f); vecAddTo(place, ship->posinfo.position); univAddDerelict(Ghostship,&place); return TRUE; } /*----------------------------------------------------------------------------- Name : startTractorBeam Description : Starts the tractor beam effect from ship to target Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ //make tractor beam originate from 'tractor beam light' void startTractorBeam(Ship *ship, SpaceObjRotImpTargGuidanceShipDerelict *target) { ShipStaticInfo *shipstatic = (ShipStaticInfo *)ship->staticinfo; TractorBeamStatic *tractorBeamStatic = shipstatic->tractorEmitterStatic; SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; //vector beamposition; //matrix beamcoordsys; //vector beamtrajectory; //real32 beamtrajectorydist; etgeffectstatic *stat; etglod *etgLOD; sdword LOD; spec->tractorBeam = TRUE; //get tractor beams world coords...not yet known if there is a guide light for that though //matMultiplyMatByVec(&beamposition,&ship->rotinfo.coordsys,&resNozzleStatic->position); //beamposition = ship->posinfo.position; //matMultiplyMatByVec(&beamposition,&ship->rotinfo.coordsys,&tractorBeamStatic->position); //vecAddTo(beamposition,ship->posinfo.position); /* vecDivideByScalar(beamtrajectory,beamtrajectorydist,temp); matCreateCoordSysFromHeading(&beamcoordsys,&beamtrajectory); */ //create an effect for bullet, if applicable etgLOD = etgTractorBeamEffectTable[ship->shiprace]; if (etgLOD != NULL) { LOD = ship->currentLOD; if (LOD >= etgLOD->nLevels) { stat = NULL; } else { stat = etgLOD->level[LOD]; } } else { stat = NULL; } #if ETG_DISABLEABLE if (stat != NULL && etgEffectsEnabled && !etgFrequencyExceeded(stat)) #else if (stat != NULL && !etgFrequencyExceeded(stat)) #endif { ship->rceffect = etgEffectCreate(stat, ship, NULL, NULL, NULL, ship->magnitudeSquared, SOF_AttachPosition|SOF_AttachCoordsys|SOF_AttachNLips, 0); ship->rceffect->posinfo.velocity.x = ship->rceffect->posinfo.velocity.y = ship->rceffect->posinfo.velocity.z = 0.0f; ((SalCapCorvetteSpec *)ship->ShipSpecifics)->tractorBeam = TRUE; univUpdateObjRotInfo((SpaceObjRot *)ship->rceffect); ship->soundevent.specialHandle = soundEvent(ship, Ship_Salvage); } else { ship->rceffect = NULL; //play no effect } } /*----------------------------------------------------------------------------- Name : StopTractorBeam Description : Stops the tractor beam effect... Assumes a definite tractor beam existance Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void StopTractorBeam(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; etgEffectDelete(ship->rceffect); univRemoveObjFromRenderList((SpaceObj *)ship->rceffect); listDeleteNode(&ship->rceffect->objlink); ship->rceffect = NULL; } /*----------------------------------------------------------------------------- Name : salCapGetMaxPushingVelocity Description : Determines the maximum velocity a salcap target should fly at (assumes lights are attached) Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ real32 salCapGetMaxPushingVelocity(Ship *ship,Ship *target) { real32 ratio; if(target->salvageInfo == NULL) { if(target->objtype == OBJ_ShipType) return(tacticsGetShipsMaxVelocity(target)); else return(target->staticinfo->staticheader.maxvelocity); } ratio = (1-(((real32)target->salvageInfo->numSalvagePointsFree)/((real32)target->salvageInfo->numSalvagePoints))); if(target->objtype == OBJ_ShipType) ratio*=tacticsGetShipsMaxVelocity(target); else ratio*=target->staticinfo->staticheader.maxvelocity; return ratio; } /*----------------------------------------------------------------------------- Name : salCapFlyToWithInCone Description : Flys ship to within the docking cone Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SALCAP_DOCK1_DISTANCE 1000.0f #define DOCK1_INSIDE_TOLERANCE 200.0f sdword salCapFlyToWithInCone(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; vector coneheadingInWorldCoordSys; vector conepositionInWorldCoordSys; vector coneToShip; real32 coneToShipMag; real32 dotprod; vector destination; SalvageStaticPoint *salvagestaticpoint = target->salvageInfo->salvagePoints[spec->salvageIndex].salvageStaticPoint; matMultiplyMatByVec(&coneheadingInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->position); vecAddTo(conepositionInWorldCoordSys,target->posinfo.position); vecSub(coneToShip,ship->posinfo.position,conepositionInWorldCoordSys); coneToShipMag = fsqrt(vecMagnitudeSquared(coneToShip)); dotprod = vecDotProduct(coneheadingInWorldCoordSys,coneToShip); // 1.0*coneToShipMag*cos(theta) if (dotprod >= (salvagestaticpoint->coneangle*coneToShipMag)) { return TRUE; } vecScalarMultiply(destination,coneheadingInWorldCoordSys,SALCAP_DOCK1_DISTANCE); vecAddTo(destination,conepositionInWorldCoordSys); if ((MoveReachedDestinationVariable(ship,&destination,DOCK1_INSIDE_TOLERANCE))) { return TRUE; } else { aishipFlyToPointAvoidingObjs(ship,&destination,AISHIP_PointInDirectionFlying, 0.0f); return FALSE; } } /*----------------------------------------------------------------------------- Name : salCapFlyToConeOrigin Description : Flys ship to docking cone origin Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SALCAP_FINAL_DOCK_TOLERANCE 25.0f sdword salCapFlyToConeOrigin(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; vector coneheadingInWorldCoordSys; vector conepositionInWorldCoordSys; vector desiredHeading; SalvageStaticPoint *salvagestaticpoint = target->salvageInfo->salvagePoints[spec->salvageIndex].salvageStaticPoint; matMultiplyMatByVec(&coneheadingInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->position); vecAddTo(conepositionInWorldCoordSys,target->posinfo.position); if (MoveReachedDestinationVariable(ship,&conepositionInWorldCoordSys,SALCAP_FINAL_DOCK_TOLERANCE)) { ship->posinfo.velocity = target->posinfo.velocity; return TRUE; } else { vecScalarMultiply(desiredHeading,coneheadingInWorldCoordSys,-1.0f); aitrackHeading(ship,&desiredHeading,1.0); aishipFlyToPointAvoidingObjs(ship,&conepositionInWorldCoordSys,0,0.0f); return FALSE; } } /*----------------------------------------------------------------------------- Name : salCapFlyOutOfCone Description : Flys ship out of cone in an orderly way Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SALCAP_BACKOUT_TOLERANCE 250.0f #define SALCAP_BACKOUT_DISTANCE 1300.0f sdword salCapFlyOutOfCone(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target,sdword trackheading) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; vector coneheadingInWorldCoordSys; vector conepositionInWorldCoordSys; vector destination; real32 backoutdist = SALCAP_BACKOUT_DISTANCE; SalvageStaticPoint *salvagestaticpoint = target->salvageInfo->salvagePoints[spec->salvageIndex].salvageStaticPoint; if (target->staticinfo->staticheader.staticCollInfo.collspheresize > backoutdist) { backoutdist = target->staticinfo->staticheader.staticCollInfo.collspheresize + SALCAP_BACKOUT_TOLERANCE; // make sure we clear it } matMultiplyMatByVec(&coneheadingInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->position); vecAddTo(conepositionInWorldCoordSys,target->posinfo.position); vecScalarMultiply(destination,coneheadingInWorldCoordSys,backoutdist); vecAddTo(destination,target->posinfo.position); if (MoveReachedDestinationVariable(ship,&destination,SALCAP_BACKOUT_TOLERANCE)) { ship->posinfo.velocity = target->posinfo.velocity; return TRUE; } else { if(trackheading) aitrackHeading(ship,&coneheadingInWorldCoordSys,1.0); aishipFlyToPointAvoidingObjsWithVel(ship,&destination,0,-50.0f,&target->posinfo.velocity); return FALSE; } } bool isThereAnotherTargetForMe(Ship *ship,SelectAnyCommand *targets) { sdword i,index; SpaceObjRotImpTarg *t; sdword numFree; index = targets->numTargets; for(i=0;inumTargets;i++) { t = targets->TargetPtr[i]; if(t->objtype == OBJ_ShipType) { if(bitTest(((Ship *)t)->specialFlags,SPECIAL_SalvagedTargetGoingIntoDockWithShip)) { //ship is docking having been salvaged... //let it dock and don't target it! continue; } switch( ((Ship *)t)->shiptype) { case Mothership: case HeadShotAsteroid: case Drone: case P1Mothership: case P2Mothership: case P3Megaship: case FloatingCity: case CargoBarge: case MiningBase: case ResearchStation: case JunkYardDawg: case JunkYardHQ: //case Ghostship: Ghostship is now salvageable! case ResearchShip: case Junk_LGun: case Junk_SGun: //fix later! negatory speech event! continue; case SalCapCorvette: { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)((Ship *)t)->ShipSpecifics; if(spec->salvageState > SAL_WL_FLYTOCONEORIGIN) { continue; } } break; default: //valid ship break; } } else if(t->objtype == OBJ_DerelictType) { if(!multiPlayerGame) { //don't salavage derelicts in single player game! if(!((Derelict *)t)->staticinfo->salvageable) { continue; } if(t->objtype == OBJ_DerelictType) { if(((Derelict *)t)->attributes & ATTRIBUTES_StripTechnology) { //derelict is to be stripped of TECH !! //so only let ONE ship attach to it lest we //have to add other code... if(((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageNumTagged[ship->playerowner->playerIndex] > 0) { //no good....its been targetted already by this player continue; } } } } } else { continue; //bad target in list..ok though } if(((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageInfo != NULL) { numFree =((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageInfo->numSalvagePoints - ((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageNumTagged[ship->playerowner->playerIndex]; } else { //no salvage lights, so only 1 possible spot numFree = 1 - ((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageNumTagged[ship->playerowner->playerIndex]; } if(numFree == 0) { //no spots...so shouldn't head to ship continue; } return TRUE; } return FALSE; } /*----------------------------------------------------------------------------- Name : salCapGetTarget Description : returns a valid (best) target from list Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ SpaceObjRotImpTargGuidanceShipDerelict *salCapGetTarget(Ship *ship,SelectAnyCommand *targets, sdword worry, sdword *flyandwait) { sdword i,index; SpaceObjRotImpTarg *t; real32 dist = REALlyBig; real32 tempdist; vector sep; sdword numFree; sdword flyandwaitvar=-1; //variable set to true if target is 'busyied' by other salcaps...salcap will fly close and just wait until //the target is no longer worthless. *flyandwait = FALSE; index = targets->numTargets; for(i=0;inumTargets;i++) { t = targets->TargetPtr[i]; if(t->objtype == OBJ_ShipType) { if(bitTest(((Ship *)t)->specialFlags,SPECIAL_SalvagedTargetGoingIntoDockWithShip)) { //ship is docking having been salvaged... //let it dock and don't target it! continue; } switch( ((Ship *)t)->shiptype) { case Mothership: case HeadShotAsteroid: case Drone: case P2Mothership: case P3Megaship: case FloatingCity: case CargoBarge: case MiningBase: case ResearchStation: case JunkYardDawg: case JunkYardHQ: //case Ghostship: Ghostship is now salvageable! case ResearchShip: case Junk_LGun: case Junk_SGun: //fix later! negatory speech event! continue; case GravWellGenerator: if(((GravWellGeneratorSpec *)((Ship *)t)->ShipSpecifics)->GravDerelict) { //gravwell is a derelict //don't salavage it //maybe put speech event? continue; } case SalCapCorvette: { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)((Ship *)t)->ShipSpecifics; if(spec->salvageState > SAL_WL_FLYTOCONEORIGIN) { continue; } } break; default: //valid ship break; } } else if(t->objtype == OBJ_DerelictType) { if(!multiPlayerGame) { //don't salavage derelicts in single player game! if(!((Derelict *)t)->staticinfo->salvageable) { continue; } if(t->objtype == OBJ_DerelictType) { if(((Derelict *)t)->attributes & ATTRIBUTES_StripTechnology) { //derelict is to be stripped of TECH !! //so only let ONE ship attach to it lest we //have to add other code... if(((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageNumTagged[ship->playerowner->playerIndex] > 0) { //no good....its been targetted already by this player continue; } } } } } else { //shouldn't be in list... targets->numTargets--; targets->TargetPtr[i]=targets->TargetPtr[targets->numTargets]; continue; } if(((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageInfo != NULL) { numFree =((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageInfo->numSalvagePoints - ((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageNumTagged[ship->playerowner->playerIndex]; } else { //no salvage lights, so only 1 possible spot numFree = 1 - ((SpaceObjRotImpTargGuidanceShipDerelict *)t)->salvageNumTagged[ship->playerowner->playerIndex]; } if(numFree == 0) { //no spots...so shouldn't head to ship if((!*flyandwait)) { flyandwaitvar = i; *flyandwait=TRUE; } continue; } vecSub(sep,t->posinfo.position,ship->posinfo.position); tempdist = vecMagnitudeSquared(sep); if(tempdist < dist) { index = i; dist = tempdist; } } if(index == targets->numTargets) { //if (battleCanChatterAtThisTime(BCE_CannotComply, ship)) //{ // battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_CannotComply, ship, SOUND_EVENT_DEFAULT); //} if((*flyandwait) && worry) { return((SpaceObjRotImpTargGuidanceShipDerelict *)targets->TargetPtr[flyandwaitvar]); } else { return NULL; } } *flyandwait = FALSE; //reset to FALSE here incase multiple targets in list. ((SpaceObjRotImpTargGuidanceShipDerelict *)targets->TargetPtr[index])->salvageNumTagged[ship->playerowner->playerIndex]++; return((SpaceObjRotImpTargGuidanceShipDerelict *)targets->TargetPtr[index]); } void docapture(Ship *ship,Ship *target) { if(target->shiptype == CryoTray) { //don't capture a cryotray return; } if(universe.curPlayerIndex == ship->playerowner->playerIndex) { speechEventFleetSpec(ship, STAT_F_EnemyShipCaptured,target->shiptype,ship->playerowner->playerIndex); } if(ship->shiptype == Mothership) { MothershipSpec *spec = (MothershipSpec *)ship->ShipSpecifics; if(spec->CAP_NumInBuildCue < (SALVAGE_MAX_CAPTURABLE-1)) { spec->CAPTimeToBuildShip[spec->CAP_NumInBuildCue] = max(SALVAGE_MIN_RETROFIT_TIME,SALVAGE_MAX_RETROFIT_TIME*(1.0f - target->health/target->staticinfo->maxhealth)); spec->CAPshiptype[spec->CAP_NumInBuildCue] = target->shiptype; spec->CAPshiprace[spec->CAP_NumInBuildCue] = target->staticinfo->shiprace; spec->CAPcolorScheme[spec->CAP_NumInBuildCue] = target->colorScheme; spec->CAP_NumInBuildCue++; } } else if(ship->shiptype == Carrier) { CarrierSpec *spec = (CarrierSpec *)ship->ShipSpecifics; if(spec->CAP_NumInBuildCue < (SALVAGE_MAX_CAPTURABLE-1)) { spec->CAPTimeToBuildShip[spec->CAP_NumInBuildCue] = max(SALVAGE_MIN_RETROFIT_TIME,SALVAGE_MAX_RETROFIT_TIME*(1.0f - target->health/target->staticinfo->maxhealth)); spec->CAPshiptype[spec->CAP_NumInBuildCue] = target->shiptype; spec->CAPshiprace[spec->CAP_NumInBuildCue] = target->staticinfo->shiprace; spec->CAPcolorScheme[spec->CAP_NumInBuildCue] = target->colorScheme; spec->CAP_NumInBuildCue++; } } else { dbgFatalf(DBG_Loc,"\nUnknown type of ship receiveing captured ship. NOT a carrier or mothership"); } } /*----------------------------------------------------------------------------- Name : salCapHarvestTarget Description : name says it all! Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void salCapHarvestTarget(SpaceObjRotImpTargGuidanceShipDerelict *target,Ship *dockwith) { bool spm3AlreadySalvaged = FALSE; // TRUE if the player has already salvaged a frigate in Mission 3 switch(target->objtype) { case OBJ_ShipType: if (!singlePlayerGame) { if (bitTest(tpGameCreated.flag,MG_CaptureCapitalShip)) { if ((isCapitalShip((Ship *)target)) && (((Ship *)target)->playerowner->playerIndex!=dockwith->playerowner->playerIndex) && (!allianceIsShipAlly((Ship *)target,dockwith->playerowner)) ) { universe.CapitalShipCaptured |= (1 << ((Ship *)target)->playerowner->playerIndex); universe.PlayerWhoWon |= (1 << dockwith->playerowner->playerIndex); if (((Ship *)target)->playerowner->playerState == PLAYER_ALIVE) { univKillPlayer(((Ship *)target)->playerowner->playerIndex,PLAYERKILLED_CAPTUREDSHIP); CheckPlayerWin(); } } } } else { AIVar *var; //more specific aivars created for capturing cryotrays and assault frigates if (((Ship *)target)->shiptype == CryoTray) { if ((var = aivarFind("SalvageCryoTray")) == NULL) { var = aivarCreate("SalvageCryoTray"); } aivarValueSet(var, TRUE); } else if (((Ship *)target)->shiptype == StandardFrigate) { if ((var = aivarFind("SalvageFrigate")) == NULL) { var = aivarCreate("SalvageFrigate"); } else { spm3AlreadySalvaged = TRUE; } aivarValueSet(var, TRUE); } else { if ((var = aivarFind("SalvageTS")) == NULL) { var = aivarCreate("SalvageTS"); } aivarValueSet(var, TRUE); } } //!!!Single Player Game Mission Specific Code!!! if((((Ship *)target)->shiptype == ResearchShip) || (((Ship *)target)->shiptype == TargetDrone) || (singlePlayerGame && (((Ship *)target)->shiptype == StandardFrigate) && (singlePlayerGameInfo.currentMission == 3) && (!spm3AlreadySalvaged))) { //don't capture research ships //don't capture targetdrones //don't capture the first frigate in singleplayer game mission 3 dockwith->playerowner->resourceUnits = (sdword)( dockwith->playerowner->resourceUnits + ((Ship *)target)->staticinfo->buildCost*0.7f); universe.gameStats.playerStats[dockwith->playerowner->playerIndex].totalResourceUnitsCollected = (sdword) (universe.gameStats.playerStats[dockwith->playerowner->playerIndex].totalResourceUnitsCollected + ((Ship *)target)->staticinfo->buildCost*0.7f); } else { docapture(dockwith,(Ship *)target); } //check if we just brutalized the player univKillOtherPlayersIfDead((Ship*)target); //ditch ship from universe bitSet(target->specialFlags,SPECIAL_Harvested); univRemoveShipFromOutside((Ship *)target); ((Ship *)target)->howDidIDie = DEATH_I_DIDNT_DIE_I_WAS_SALAVAGED; ((Ship *)target)->whoKilledMe = dockwith->playerowner->playerIndex; univDeleteWipeInsideShipOutOfExistence((Ship *)target); break; case OBJ_DerelictType: //later make own univRemoveDerelictFromOutside) dockwith->playerowner->resourceUnits += 250; universe.gameStats.playerStats[dockwith->playerowner->playerIndex].totalResourceUnitsCollected+= 250; bitSet(target->specialFlags,SPECIAL_Harvested); AddTargetToDeleteList((SpaceObjRotImpTarg *)target,-1); break; #ifdef DEBUG_SALCAP default: dbgFatalf(DBG_Loc,"\nSal/Cap: Trying to convert an unknown object type to RU's."); break; #endif } //thanks lukina de pooina //ship->playerowner->resourceUnits -= ship->playerowner->resourceUnits / 3; } /*----------------------------------------------------------------------------- Name : salCapGetAndBusySalvageIndex Description : finds the best docking index to use and busy's it Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sdword salCapGetAndBusySalvageIndex(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { sdword i; SalvagePoint *salvagePoint; if(target->salvageInfo != NULL) { for (i = 0;isalvageInfo->numSalvagePoints;i++) { salvagePoint = &target->salvageInfo->salvagePoints[i]; if(!salvagePoint->busy) { //not busy salvagePoint->busy = TRUE; target->salvageInfo->numSalvagePointsFree--; return i; } } return NO_INDEX; } #ifndef HW_Release dbgFatalf(DBG_Loc,"\nShips salvage static info doesn't exist!."); #endif return NO_INDEX; } /*----------------------------------------------------------------------------- Name : salCapUnBusySalvagePoint Description : unbusy's targets docking point Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void salCapUnBusySalvagePoint(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; if(spec->target->salvageInfo != NULL) { target->salvageInfo->salvagePoints[spec->salvageIndex].busy = 0; target->salvageInfo->numSalvagePointsFree++; if(ship->clampInfo != NULL) { //don't decrease this quantity unless we're clamped to the ship! dbgAssert(ship->clampInfo->host == ((SpaceObjRotImpTarg *)target)); target->salvageInfo->numNeededForSalvage++; if(spec->target->salvageInfo->numNeededForSalvage > spec->target->staticinfo->salvageStaticInfo->numNeededForSalvage) { spec->target->salvageInfo->numNeededForSalvage = spec->target->staticinfo->salvageStaticInfo->numNeededForSalvage; } } } spec->salvageIndex = NO_INDEX; } sdword salCapFitCarrier(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { sdword needBig; if(target->salvageInfo != NULL) { needBig = target->staticinfo->salvageStaticInfo->willFitCarrier; } else { if(target->objtype==OBJ_DerelictType) { needBig = FALSE; } else if(((Ship *)target)->staticinfo->shipclass == CLASS_HeavyCruiser || ((Ship *)target)->staticinfo->shipclass == CLASS_Carrier || ((Ship *)target)->staticinfo->shipclass == CLASS_Destroyer || ((Ship *)target)->staticinfo->shipclass == CLASS_Frigate || ((Ship *)target)->staticinfo->shiptype == ResourceController || ((Ship *)target)->staticinfo->shiptype == CryoTray) { needBig = FALSE; } else { needBig = TRUE; } } return needBig; } /*----------------------------------------------------------------------------- Name : salCapNeedBig Description : returns needbig status..:) whether or not a mothership bay door is required for salvage deposit Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sdword salCapNeedBig(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { sdword needBig; if(target->salvageInfo != NULL) { if(ship->shiprace == R1) { needBig = target->staticinfo->salvageStaticInfo->needBigR1; } else { needBig = target->staticinfo->salvageStaticInfo->needBigR2; } } else { if(target->objtype==OBJ_DerelictType) { needBig = TRUE; } else if(((Ship *)target)->staticinfo->shipclass == CLASS_HeavyCruiser || ((Ship *)target)->staticinfo->shipclass == CLASS_Carrier || ((Ship *)target)->staticinfo->shipclass == CLASS_Destroyer || ((Ship *)target)->staticinfo->shipclass == CLASS_Frigate || ((Ship *)target)->staticinfo->shiptype == CryoTray) { needBig = TRUE; } else { needBig = FALSE; } } return needBig; } /*----------------------------------------------------------------------------- Name : salCapFindDockWith Description : finds a viable ship for the target to dockwith Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ Ship *salCapFindDockWith(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; Node *node = universe.ShipList.head; Ship *dockwith,*dockwithpos; sdword needBig; real32 mindist,distsqr; vector distvec; //do we need a mothership? needBig = !salCapFitCarrier(ship,target); if(needBig) { if(ship->playerowner != NULL) { if(ship->playerowner->PlayerMothership != NULL) { if(ship->playerowner->PlayerMothership->shiptype == Mothership) { return(ship->playerowner->PlayerMothership); } } } return NULL; //motherships 'big' bay not found } dockwith = NULL; mindist = REALlyBig; //searching for mothership or carrier here! or other dockable ship while(node != NULL) { dockwithpos = (Ship *)listGetStructOfNode(node); if(dockwithpos->shiptype != Carrier && dockwithpos->shiptype != Mothership ) goto nextnode; else if(dockwithpos->playerowner != ship->playerowner) goto nextnode; //found players carrier vecSub(distvec,dockwithpos->posinfo.position,spec->target->posinfo.position); distsqr = vecMagnitudeSquared(distvec); if(distsqr < mindist) { mindist = distsqr; dockwith = dockwithpos; } nextnode: node = node->next; } return dockwith; } /*----------------------------------------------------------------------------- Name : salCapSetNewCoordSys Description : Sets up targets coordinate system based on specified salvage lights Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void salCapSetNewCoordSys(SpaceObjRotImpTargGuidanceShipDerelict *target,vector *heading,vector *velocityN) { sdword i; sdword good = FALSE; *velocityN = target->posinfo.velocity; vecNormalize(velocityN); for(i=0;isalvageInfo->numSalvagePoints;i++) { if(target->salvageInfo->salvagePoints[i].salvageStaticPoint->type == Heading) { matMultiplyMatByVec(heading,&target->rotinfo.coordsys,&target->salvageInfo->salvagePoints[i].salvageStaticPoint->conenormal); good = TRUE; break; } } if(!good) { #ifdef DEBUG_SAL dbgMessagef("\nNO HEADING VECTOR FOUND! in SALVAGEINFO"); #endif *heading = *velocityN; return; } } /*----------------------------------------------------------------------------- Name : salCapTrackHeadingAndUp Description : tracks the docking heading if the lights are placed Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sdword salCapTrackHeadingAndUp(SpaceObjRotImpTargGuidanceShipDerelict *target,real32 withinAngle) { matrix rotMatrix; vector fakeHeading,velocityN; vector realHeading,neededHeading,planePerp; real32 cosAngle,Angle; //create coordsys from salvage heading lights... //salCapSetNewCoordSys(target,&fakeHeading,&velocityN); velocityN = target->posinfo.velocity; vecNormalize(&velocityN); aitrackHeadingWithFlags((Ship *)target,&velocityN,0.999f,0); return FALSE; matGetVectFromMatrixCol1(realHeading,target->rotinfo.coordsys); cosAngle = vecDotProduct(fakeHeading,velocityN); if(cosAngle > 1.0f) cosAngle = 1.0f; else if(cosAngle < -1.0f) cosAngle = -1.0f; Angle = acos(cosAngle); if(Angle <= withinAngle) { //no need to adjust return TRUE; } vecCrossProduct(planePerp,velocityN,fakeHeading); vecNormalize(&planePerp); nisRotateAboutVector((real32 *) &rotMatrix, &planePerp, Angle); matMultiplyVecByMat(&neededHeading,&realHeading,&rotMatrix); //matMultiplyMatByVec(&neededHeading,&rotMatrix,&realHeading); aitrackHeadingWithFlags((Ship *)target,&neededHeading,0.999f,AITRACKHEADING_IGNOREUPVEC); return FALSE; } /*----------------------------------------------------------------------------- Name : salCapFlyToWithinDockingRange Description : fly's the target to within docking range Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SAL_WITHIN_DOCKING_RANGE 6000.0f sdword salCapFlyToWithinDockingRange(Ship *ship) { SalCapCorvetteStatics *salcapcorvettestatics = ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; real32 maxpushvelocity; SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; if(MoveReachedDestinationVariable((Ship *)spec->target,&spec->dockwith->posinfo.position,SAL_WITHIN_DOCKING_RANGE)) { return TRUE; } //fly to point maxpushvelocity = salCapGetMaxPushingVelocity(ship,(Ship *)spec->target); if(spec->target->objtype == OBJ_ShipType) { if(((Ship *)spec->target)->specialFlags2 & SPECIAL_2_SalvageTargetAlreadyDriven) { goto dontflyme1; } } aishipFlyToPointAvoidingObjs((Ship *)spec->target,&spec->dockwith->posinfo.position,AISHIP_PointInDirectionFlying,maxpushvelocity); salCapTrackHeadingAndUp(spec->target,0.999f); if(spec->target->objtype == OBJ_ShipType) { ((Ship *)spec->target)->specialFlags2 |= SPECIAL_2_SalvageTargetAlreadyDriven; } dontflyme1:; return FALSE; } sdword getDockIndex(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target,Ship *dockwith) { sdword i; sdword needBig; sdword willfitcarrier; //determines if need a LARGE door needBig = salCapNeedBig(ship,target); willfitcarrier = salCapFitCarrier(ship,target); if(needBig && !willfitcarrier) { //needs a mothership BIG door //and WON'T fit in the carrier for(i=0;dockwith->dockInfo->numDockPoints;i++) { if(strcmp(dockwith->dockInfo->dockpoints[i].dockstaticpoint->name,"Big") == 0) { return(i); } } } else { if(dockwith->shiprace == R1 || dockwith->shiptype == Carrier) { for(i=0;dockwith->dockInfo->numDockPoints;i++) { if(strcmp(dockwith->dockInfo->dockpoints[i].dockstaticpoint->name,"Frigate") == 0) { return(i); } } } else { //ship race is R2 and not a carrier! for(i=0;dockwith->dockInfo->numDockPoints;i++) { if(strcmp(dockwith->dockInfo->dockpoints[i].dockstaticpoint->name,"Big") == 0) { return(i); } } } } //for now die later, error handle by returning an informative flag that //indicates to deattach and go home with tail between legs dbgAssert(FALSE); return 0; } /*----------------------------------------------------------------------------- Name : salCapFlyToDockingPoint1 Description : Performs a stage in the salvage Docking process inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SALCAP_1over2Tolerance 800.0f #define SALCAP_1over2HEADINGSCALAR 3500.0f sdword salCapFlyToDockingPoint1over2(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; SalCapCorvetteStatics *salcapcorvettestatics = ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; vector coneheadingInWorldCoordSys,conepositionInWorldCoordSys; vector destination,dockwithHeading; matGetVectFromMatrixCol3(dockwithHeading,spec->dockwith->rotinfo.coordsys); vecScalarMultiply(dockwithHeading,dockwithHeading,SALCAP_1over2HEADINGSCALAR); matMultiplyMatByVec(&coneheadingInWorldCoordSys,&spec->dockwith->rotinfo.coordsys,&spec->dockwith->dockInfo->dockpoints[spec->dockindex].dockstaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&spec->dockwith->rotinfo.coordsys,&spec->dockwith->dockInfo->dockpoints[spec->dockindex].dockstaticpoint->position); vecAddTo(conepositionInWorldCoordSys,spec->dockwith->posinfo.position); vecAdd(destination,dockwithHeading,conepositionInWorldCoordSys); if (MoveReachedDestinationVariable((Ship *)target,&destination,SALCAP_1over2Tolerance)) { return TRUE; } else { aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,AISHIP_PointInDirectionFlying,SAL_GOTOPOINT_LIMITVEL,&spec->dockwith->posinfo.velocity); return FALSE; } } /*----------------------------------------------------------------------------- Name : salCapFlyToDockingPoint1 Description : Performs a stage in the salvage Docking process inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SALCAP_ReverseDockTolerance1 1500.0f #define SALCAP_HeadingTrackTolerance 2000.0f //#define DOOR_DOCKING_NAV1 2500.0f //#define DOOR_DOCKING_NAV2 575.0f #define HEADING_SCALAR 2500.0f #define SALCAP_DOCKCONE_SCALAR_BIG_DOOR 1000.0f #define SALCAP_DOCKCONE_SCALAR_OTHER 2000.0f sdword salCapFlyToDockingPoint1(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; SalCapCorvetteStatics *salcapcorvettestatics = ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; vector coneheadingInWorldCoordSys,conepositionInWorldCoordSys; vector dockwithUp,dockwithHeading,dockwithRight,navpoint; vector desiredHeading,desiredUp,destination; vector positionWS,doorRight,doorUp; matrix coordsysWS; sdword needDest; sdword NO; NO = FALSE; if(spec->dockwith->shiptype == Mothership) { if(spec->dockwith->shiprace == R1) { if(salCapNeedBig(ship,target)) { madLinkInGetDoorInfo(spec->dockwith,&coordsysWS,&positionWS); matGetVectFromMatrixCol1(doorUp,coordsysWS); matGetVectFromMatrixCol2(doorRight,coordsysWS); //vecScalarMultiply(doorLeft,doorRight,-1.0f); desiredHeading = doorUp; desiredUp = doorRight; NO = TRUE; } } } matGetVectFromMatrixCol1(dockwithUp,spec->dockwith->rotinfo.coordsys); matGetVectFromMatrixCol2(dockwithRight,spec->dockwith->rotinfo.coordsys); matGetVectFromMatrixCol3(dockwithHeading,spec->dockwith->rotinfo.coordsys); if(!NO) { if(spec->dockwith->shiprace == R1) { desiredHeading = dockwithUp; vecScalarMultiply(desiredUp,dockwithRight,-1.0f); } else { desiredHeading = dockwithHeading; desiredUp = dockwithUp; } } matMultiplyMatByVec(&coneheadingInWorldCoordSys,&spec->dockwith->rotinfo.coordsys,&spec->dockwith->dockInfo->dockpoints[spec->dockindex].dockstaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&spec->dockwith->rotinfo.coordsys,&spec->dockwith->dockInfo->dockpoints[spec->dockindex].dockstaticpoint->position); vecAddTo(conepositionInWorldCoordSys,spec->dockwith->posinfo.position); needDest = TRUE; if(spec->dockwith->shiptype == Mothership) { if(spec->dockwith->shiprace == R1) { if(salCapNeedBig(ship,target)) { vecScalarMultiply(destination,coneheadingInWorldCoordSys,SALCAP_DOCKCONE_SCALAR_BIG_DOOR); vecAddTo(destination,conepositionInWorldCoordSys); vecScalarMultiply(navpoint,dockwithHeading,HEADING_SCALAR); vecAddTo(destination,navpoint); needDest=FALSE; } } } if(needDest) { vecScalarMultiply(destination,coneheadingInWorldCoordSys,SALCAP_DOCKCONE_SCALAR_OTHER); vecAddTo(destination,conepositionInWorldCoordSys); } if (MoveReachedDestinationVariable((Ship *)target,&destination,SALCAP_ReverseDockTolerance1)) { return TRUE; } else { if (MoveReachedDestinationVariable((Ship *)target,&destination,SALCAP_HeadingTrackTolerance)) { if(salCapNeedBig(ship,target)) { aitrackHeadingAndUp((Ship *)target,&desiredHeading,&desiredUp,1.0); } else { vector smallHeading; vecScalarMultiply(smallHeading,coneheadingInWorldCoordSys,-1.0f); aitrackHeadingAndUp((Ship *)target,&smallHeading,&dockwithUp,1.0); } //aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,0,-salcapcorvettestatics->maxPushingVelocitySingle,&spec->dockwith->posinfo.velocity); aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,0,SAL_GOTOPOINT_LIMITVEL,&spec->dockwith->posinfo.velocity); } else { //aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,AISHIP_PointInDirectionFlying,-salcapcorvettestatics->maxPushingVelocitySingle,&spec->dockwith->posinfo.velocity); aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,AISHIP_PointInDirectionFlying,SAL_GOTOPOINT_LIMITVEL,&spec->dockwith->posinfo.velocity); } return FALSE; } } /*----------------------------------------------------------------------------- Name : salCapFlyToDockingPoint2 Description : Performs a stage in the salvage Docking process inputs : Outputs : Return : ----------------------------------------------------------------------------*/ #define SALCAP_ReverseDockTolerance3 200.0f #define SALCAP_STAGE2_DOCKWITHUP_SCALAR 0.0f #define SALCAP_STAGE2_DOCKWITHRIGHT_SCALAR 1000.0f #define SALCAP_STAGE2_DOCKWITHHEADING_SCALAR 1500.0f #define SALCAP_WEIRD_DOCKING_DISTANCE2 2000.0f sdword salCapFlyToDockingPoint2(Ship *dockwith,SpaceObjRotImpTargGuidanceShipDerelict *target,sdword dockindex) { vector coneheadingInWorldCoordSys,conepositionInWorldCoordSys; vector dockwithUp,dockwithHeading,dockwithRight,navpoint; vector desiredHeading,desiredUp,desiredRight,destination; vector positionWS,doorRight,doorUp; matrix coordsysWS; sdword NO; NO = FALSE; if(dockwith->shiptype == Mothership) { if(dockwith->shiprace == R1) { if(salCapNeedBig(dockwith,target)) { //madLinkInGetDoorInfo(dockwith,&coordsysWS,&positionWS); mothershipGetCargoPosition(dockwith,target,&positionWS,&coordsysWS,&desiredHeading,&desiredUp,&desiredRight); matGetVectFromMatrixCol1(doorUp,coordsysWS); matGetVectFromMatrixCol2(doorRight,coordsysWS); //vecScalarMultiply(doorLeft,doorRight,-1.0f); //desiredHeading = doorUp; //desiredUp = doorRight; NO = TRUE; } } } matGetVectFromMatrixCol1(dockwithUp,dockwith->rotinfo.coordsys); matGetVectFromMatrixCol2(dockwithRight,dockwith->rotinfo.coordsys); matGetVectFromMatrixCol3(dockwithHeading,dockwith->rotinfo.coordsys); if(!NO) { if(dockwith->shiprace == R1) { desiredHeading = dockwithUp; vecScalarMultiply(desiredUp,dockwithRight,-1.0f); } else { desiredHeading = dockwithHeading; desiredUp = dockwithUp; } } matMultiplyMatByVec(&coneheadingInWorldCoordSys,&dockwith->rotinfo.coordsys,&dockwith->dockInfo->dockpoints[dockindex].dockstaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&dockwith->rotinfo.coordsys,&dockwith->dockInfo->dockpoints[dockindex].dockstaticpoint->position); vecAddTo(conepositionInWorldCoordSys,dockwith->posinfo.position); destination = conepositionInWorldCoordSys; NO = FALSE; if(dockwith->shiptype == Mothership) { if(dockwith->shiprace == R1) { //if using big! if(salCapNeedBig(dockwith,target)) { vecScalarMultiply(navpoint,dockwithUp,SALCAP_STAGE2_DOCKWITHUP_SCALAR); vecAddTo(destination,navpoint); vecScalarMultiply(navpoint,dockwithRight,-SALCAP_STAGE2_DOCKWITHRIGHT_SCALAR); vecAddTo(destination,navpoint); vecScalarMultiply(navpoint,dockwithHeading,SALCAP_STAGE2_DOCKWITHHEADING_SCALAR); vecAddTo(destination,navpoint); NO = TRUE; } } } if(!NO) { vecScalarMultiply(navpoint,coneheadingInWorldCoordSys,SALCAP_WEIRD_DOCKING_DISTANCE2); vecAddTo(destination,navpoint); } if (MoveReachedDestinationVariable((Ship *)target,&destination,SALCAP_ReverseDockTolerance3)) { return TRUE; } else { if(salCapNeedBig(dockwith,target)) { aitrackHeadingAndUp((Ship *)target,&desiredHeading,&desiredUp,1.0); } else { vector smallHeading; vecScalarMultiply(smallHeading,coneheadingInWorldCoordSys,-1.0f); aitrackHeadingAndUp((Ship *)target,&smallHeading,&dockwithUp,1.0); } //aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,0,-salcapcorvettestatics->maxPushingVelocitySingle,&spec->dockwith->posinfo.velocity); aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,0,SAL_GOTOPOINT_LIMITVEL,&dockwith->posinfo.velocity); return FALSE; } return FALSE; } /*----------------------------------------------------------------------------- Name : salCapFlyToDockingPoint3 Description : Performs a stage in the salvage Docking process inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sdword salCapFlyToDockingPoint3(Ship *dockwith,SpaceObjRotImpTargGuidanceShipDerelict *target,sdword dockindex) { vector coneheadingInWorldCoordSys,conepositionInWorldCoordSys; vector dockwithUp,dockwithHeading,dockwithRight; vector desiredHeading,desiredUp,desiredRight,destination; vector doorRight,doorUp; matrix coordsysWS; sdword NO; NO = FALSE; if(dockwith->shiptype == Mothership) { if(dockwith->shiprace == R1) { if(salCapNeedBig(dockwith,target)) { mothershipGetCargoPosition(dockwith,(SpaceObjRotImpTargGuidanceShipDerelict *)target, &destination,&coordsysWS,&desiredHeading,&desiredUp,&desiredRight); //madLinkInGetDoorInfo(spec->dockwith,&coordsysWS,&positionWS); matGetVectFromMatrixCol1(doorUp,coordsysWS); matGetVectFromMatrixCol2(doorRight,coordsysWS); //vecScalarMultiply(doorLeft,doorRight,-1.0f); //desiredHeading = doorUp; //desiredUp = doorRight; NO = TRUE; } } } matGetVectFromMatrixCol1(dockwithUp,dockwith->rotinfo.coordsys); matGetVectFromMatrixCol2(dockwithRight,dockwith->rotinfo.coordsys); matGetVectFromMatrixCol3(dockwithHeading,dockwith->rotinfo.coordsys); if(!NO) { if(dockwith->shiprace == R1) { desiredHeading = dockwithUp; vecScalarMultiply(desiredUp,dockwithRight,-1.0f); } else { desiredHeading = dockwithHeading; desiredUp = dockwithUp; } matMultiplyMatByVec(&coneheadingInWorldCoordSys,&dockwith->rotinfo.coordsys,&dockwith->dockInfo->dockpoints[dockindex].dockstaticpoint->conenormal); matMultiplyMatByVec(&conepositionInWorldCoordSys,&dockwith->rotinfo.coordsys,&dockwith->dockInfo->dockpoints[dockindex].dockstaticpoint->position); vecAddTo(conepositionInWorldCoordSys,dockwith->posinfo.position); destination = conepositionInWorldCoordSys; } if (MoveReachedDestinationVariable((Ship *)target,&destination,TW_R1_DOOR_DOCK_TOLERANCE)) { return TRUE; } else { if(salCapNeedBig(dockwith,target)) { //if using big! /* if(spec->dockwith->shiprace == R1) { //do final door matrix tracking matrix doormatSS,doormatWS; vector doorposSS,doorposWS; madLinkInGetDoorInfo(spec->dockwith,&doormatSS,&doorposSS); matMultiplyMatByMat(&doormatWS,&spec->dockwith->rotinfo.coordsys,&doormatSS); matMultiplyVecByMat(&doorposWS,&doorposSS,&spec->dockwith->rotinfo.coordsys); vecAddTo(doorposWS,spec->dockwith->posinfo.position); matGetVectFromMatrixCol1(desiredHeading,doormatWS); matGetVectFromMatrixCol2(dockwithRight,doormatWS); vecScalarMultiply(desiredUp,dockwithRight,-1.0f); } */ aitrackHeadingAndUp((Ship *)target,&desiredHeading,&desiredUp,1.0); } else { vector smallHeading; vecScalarMultiply(smallHeading,coneheadingInWorldCoordSys,-1.0f); aitrackHeadingAndUp((Ship *)target,&smallHeading,&dockwithUp,1.0); } aishipFlyToPointAvoidingObjsWithVel((Ship *)target,&destination,0,SAL_GOTOPOINT_LIMITVEL,&dockwith->posinfo.velocity); return FALSE; } return FALSE; } void salCapPointAtTarget(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; vector conepositionInWorldCoordSys,heading; SalvageStaticPoint *salvagestaticpoint; if(target->salvageInfo != NULL) { salvagestaticpoint = target->salvageInfo->salvagePoints[spec->salvageIndex].salvageStaticPoint; matMultiplyMatByVec(&conepositionInWorldCoordSys,&target->rotinfo.coordsys,&salvagestaticpoint->position); vecAddTo(conepositionInWorldCoordSys,target->posinfo.position); vecSub(heading,conepositionInWorldCoordSys,ship->posinfo.position); vecNormalize(&heading); } else { conepositionInWorldCoordSys = target->posinfo.position; vecSub(heading,conepositionInWorldCoordSys,ship->posinfo.position); vecNormalize(&heading); } aitrackHeading(ship,&heading,0.999f); } void removeTargetFromSelection(SpaceObjRotImpTarg *target,SelectAnyCommand *targets) { sdword i=0; for(i=0;inumTargets;) { if(target == targets->TargetPtr[i]) { targets->numTargets--; targets->TargetPtr[i] = targets->TargetPtr[targets->numTargets]; continue; } i++; } } /*----------------------------------------------------------------------------- Name : SalCapCorvetteSpecialTarget Description : Performs salvageing! Hopefully Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ bool SalCapCorvetteSpecialTarget(Ship *ship, void *custom) { SelectAnyCommand *targets; SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; SalCapCorvetteStatics *salcapcorvettestatics = ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; SelectCommand selection; sdword waittarget; targets = (SelectAnyCommand *)custom; if(targets->numTargets == 0 && spec->target == NULL) { //no targets left, so cleanup and finish SelectCommand selection; spec->tractorBeam = FALSE; //if(spec->target != NULL) //{ // bitClear(((Ship *)spec->target)->dontrotateever,1); // bitClear(((Ship *)spec->target)->dontapplyforceever,1); // } //make sure clampinfo doesn't get fucked here! if(ship->rceffect) StopTractorBeam(ship); CleanSalCapSpec(ship); selection.numShips = 1; selection.ShipPtr[0] = ship; clHalt(&universe.mainCommandLayer,&selection); return TRUE; } if(spec->target == NULL) { if(spec->salvageState != SALVAGE_BEGIN ) { if(ship->rceffect != NULL) StopTractorBeam(ship); CleanSalCapSpec(ship); return FALSE; //let it re-enter and do normal stuff. } } if(bitTest(ship->specialFlags,SPECIAL_Kamikaze)) { ship->attackvars.attacktarget=targets->TargetPtr[0]; doKamikazeAttack(ship,targets->TargetPtr[0]); return FALSE; } //check if target has been harvested and not had references removed this //univupdate if(spec->target != NULL) { if(spec->target->specialFlags & SPECIAL_Harvested) { //target JUST harvested this univupdate...so ditch it.. spec->tractorBeam = FALSE; if(ship->rceffect) StopTractorBeam(ship); CleanSalCapSpec(ship); return TRUE; } } //begin state machine switch(spec->salvageState) { case SALVAGE_BEGIN: //get target from target list using some sort of criteria :) if(spec->target != NULL) { SelectCommand *targetShips = (SelectCommand *)targets; if(ShipInSelection(targetShips,(Ship *)spec->target)) { //assume already clamped! spec->salvageState = SAL_SALVAGE1; break; } } if((spec->target = salCapGetTarget(ship,targets,TRUE,&waittarget))==NULL) { //no viable target in list aitrackStabilizeShip(ship); //if ship is in a command, this will get //called over and over until all ships are done! aitrackZeroVelocity(ship); CleanSalCapSpec(ship); return TRUE; } if(waittarget) { //target is special...we need to wait for it to be free... if(!MoveReachedDestinationVariable(ship,&spec->target->posinfo.position,salcapcorvettestatics->flyToDistance*4)) { //not close enough to begin proper docking sequence, so fly closer to target if (aishipFlyToPointAvoidingObjs(ship,&spec->target->posinfo.position,AISHIP_PointInDirectionFlying|AISHIP_DontFlyToObscuredPoints|AISHIP_ReturnImmedIfPointObscured,0.0f) & AISHIP_FLY_OBJECT_IN_WAY) goto reachedit; } else { reachedit: aitrackZeroVelocity(ship); aitrackStabilizeShip(ship); } spec->target=NULL; //reset to NULL because it isn't really going after it. break; } spec->salvageState = SAL_FLYTOTARGET; //don't let a salcap salvage a derelict twice if tech is what be gotten if(singlePlayerGame) { if(spec->target->objtype == OBJ_DerelictType) { if(((Derelict *)spec->target)->attributes & ATTRIBUTES_StripTechnology) { if(universe.DerelictTech) { //Already Been salvaged...don't allow again //no viable target in list ((SpaceObjRotImpTargGuidanceShipDerelict *)spec->target)->salvageNumTagged[ship->playerowner->playerIndex]--; aitrackStabilizeShip(ship); //if ship is in a command, this will get //called over and over until all ships are done! aitrackZeroVelocity(ship); CleanSalCapSpec(ship); return TRUE; } } } } break; case SAL_FLYTOTARGET: //fly to within a certain range of the target if(spec->target->clampInfo != NULL) { //someone is salvaging this target already spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } if(!MoveReachedDestinationVariable(ship,&spec->target->posinfo.position,salcapcorvettestatics->flyToDistance)) { //not close enough to begin proper docking sequence, so fly closer to target if ((aishipFlyToPointAvoidingObjs(ship,&spec->target->posinfo.position,AISHIP_DontFlyToObscuredPoints|AISHIP_PointInDirectionFlying,0.0f) & AISHIP_FLY_OBJECT_IN_WAY) == 0) break; } if(spec->target->objtype != OBJ_DerelictType) { if(!salCapAreEnoughSalvagersTargettingThisTarget(ship,spec->target)) { //not enough doods targetting this bizitch...play sound event //with ye'old battler chatter of course bloot:; } } spec->salvageState = SAL_DOCKINGSTATE1; break; case SAL_DOCKINGSTATE1: //choose salvaging docking method //1-with salvage lights on target //2-without salvage lights if(spec->target->clampInfo != NULL) { //someone is salvaging this target already spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } if( spec->target->salvageInfo != NULL) { spec->salvageState = SAL_DOCKWITHLIGHTS1; } else { spec->salvageState = SAL_DOCKWITHOUTLIGHTS1; } //fix formation anoyances! ship->specialFlags |= SPECIAL_BrokenFormation; break; case SAL_DOCKWITHOUTLIGHTS1: //default harvest method with no Salvage Lights on target if(spec->target->clampInfo != NULL) { //someone is salvaging this target already spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } { vector trajectory,heading; sdword or; real32 range; spec->noAvoid = TRUE; //set noAvoid variable so collision avoidence will not avoid the salcaps target! aishipGetTrajectory(ship,(SpaceObjRotImpTarg *)spec->target,&trajectory); range = RangeToTarget(ship,(SpaceObjRotImpTarg *)spec->target,&trajectory); aishipFlyToPointAvoidingObjs(ship,&spec->target->posinfo.position,0,0.0f); vecSub(heading,spec->target->posinfo.position,ship->posinfo.position); vecNormalize(&heading); or = aitrackHeadingWithFlags(ship,&heading,0.98f,AITRACKHEADING_IGNOREUPVEC); if(range <= salcapcorvettestatics->noLightClampingDistance && or) { //Salcap is theoretically on the hull of the other ship at this point //couldn't use colboxindirection function because turned out to be //unreliable // //now clamp object to salcap and tell it to dock for targetDeposit if(ship->shiptype == JunkYardDawg) { clampObjToObj((SpaceObjRotImpTargGuidance *)spec->target,(SpaceObjRotImpTargGuidance *)ship); } else { //clampObjToObj((SpaceObjRotImpTargGuidance *)ship,(SpaceObjRotImpTargGuidance *)spec->target); clampObjToObj((SpaceObjRotImpTargGuidance *)spec->target,(SpaceObjRotImpTargGuidance *)ship); } dbgAssert(ship->rceffect == NULL); startTractorBeam(ship,spec->target); spec->salvageState = SAL_CLAMPED; } } break; case SAL_DOCKWITHLIGHTS1: if(spec->target->clampInfo != NULL) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } if(spec->target->salvageInfo->numSalvagePointsFree == 0) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } //Free salvaging Point! if((spec->salvageIndex = salCapGetAndBusySalvageIndex(ship,spec->target)) == NO_INDEX) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } spec->salvageState = SAL_WL_FLYTOWITHINCONE; break; case SAL_WL_FLYTOWITHINCONE: if(spec->target->clampInfo != NULL) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } if(salCapFlyToWithInCone(ship,spec->target)) { spec->noAvoid = TRUE; spec->salvageState = SAL_WL_FLYTOCONEORIGIN; } if(spec->target->objtype == OBJ_ShipType) { bitSet(((Ship *)spec->target)->dontrotateever,1); bitSet(((Ship *)spec->target)->dontapplyforceever,1); } vecScalarMultiply(spec->target->posinfo.velocity,spec->target->posinfo.velocity,0.90f); vecScalarMultiply(spec->target->rotinfo.rotspeed,spec->target->rotinfo.rotspeed,0.90f); break; case SAL_WL_FLYTOCONEORIGIN: if(spec->target->clampInfo != NULL) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } removeTargetFromSelection((SpaceObjRotImpTarg *)spec->target,targets); CleanSalCapSpec(ship); return FALSE; } if(salCapFlyToConeOrigin(ship,spec->target)) { //we are now in clamp teritory... if(ship->shiptype == JunkYardDawg) { clampObjToObj((SpaceObjRotImpTargGuidance *)spec->target,(SpaceObjRotImpTargGuidance *)ship); } else { //do clamp clampObjToObj((SpaceObjRotImpTargGuidance *)ship,(SpaceObjRotImpTargGuidance *)spec->target); } //declare that we are latched on spec->target->salvageInfo->numNeededForSalvage--; spec->salvageState = SAL_CLAMPED; if(ship->shiptype == JunkYardDawg) { //grip ship... madLinkInCloseSpecialShip(ship); } } if(spec->target->objtype == OBJ_ShipType) { bitSet(((Ship *)spec->target)->dontrotateever,1); bitSet(((Ship *)spec->target)->dontapplyforceever,1); } vecScalarMultiply(spec->target->posinfo.velocity,spec->target->posinfo.velocity,0.90f); vecScalarMultiply(spec->target->rotinfo.rotspeed,spec->target->rotinfo.rotspeed,0.90f); break; case SAL_CLAMPED: //check if we need to rip tech from the object instead // speechEvent(ship, STAT_SCVette_TargetAcquired, 0); //close all animations if a ship if (battleCanChatterAtThisTime(BCE_SalvageTargetAcquired, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_SalvageTargetAcquired, ship, ranRandom(RAN_Sound) % 4); } if(spec->target->objtype == OBJ_DerelictType) { if(((Derelict *)spec->target)->attributes & ATTRIBUTES_StripTechnology) { spec->salvageState = SAL_STRIPTECH; spec->salvageAttributes |= SALVAGE_AT_GET_TECH; break; } spec->salvageState = SAL_SALVAGE1; } else if(spec->target->objtype == OBJ_ShipType) { if(((Ship *)spec->target)->attributes & ATTRIBUTES_StripTechnology) { spec->salvageState = SAL_STRIPTECH; spec->salvageAttributes |= SALVAGE_AT_GET_TECH; break; } bitClear(((Ship *)spec->target)->dontrotateever,1); bitClear(((Ship *)spec->target)->dontapplyforceever,1); spec->salvageState = SAL_DO_DAMAGE; if(spec->target->objtype != OBJ_DerelictType) { if(!salCapAreEnoughSalvagersTargettingThisTarget(ship,spec->target)) { //not enough doods targetting this bizitch...play sound event blooty:; } } } break; case SAL_DO_DAMAGE: if(spec->target->salvageInfo == NULL) { //don't do damage for these, just give a docking order... spec->salvageState = SAL_SALVAGE1; break; } //go through list and DON'T do damage to special cases! if(spec->target->objtype == OBJ_ShipType) { switch(((Ship *)spec->target)->shiptype) { case CryoTray: spec->salvageState = SAL_SALVAGE1; break; default: break; } if(spec->salvageState == SAL_SALVAGE1) { //we don'twant to do damage...so special case //jump out of case statement! break; } } if(spec->target->health*spec->target->staticinfo->oneOverMaxHealth < salcapcorvettestatics->HealthThreshold) { spec->salvageState = SAL_SALVAGE1; } else { if(ship->playerowner != NULL) { ApplyDamageToTarget((SpaceObjRotImpTarg *)spec->target,salcapcorvettestatics->healthRemovedPerSecond*universe.phystimeelapsed,-1,DEATH_Killed_By_Player,ship->playerowner->playerIndex); } else { ApplyDamageToTarget((SpaceObjRotImpTarg *)spec->target,salcapcorvettestatics->healthRemovedPerSecond*universe.phystimeelapsed,-1,DEATH_Killed_By_Dead_Player,99); } if(spec->target->objtype == OBJ_ShipType) { ((Ship *)spec->target)->gettingrocked = ship; ((Ship *)spec->target)->recentAttacker = ship; ((Ship *)spec->target)->recentlyAttacked = RECENT_ATTACK_DURATION; // start counting down } //spec->target->health -= salcapcorvettestatics->healthRemovedPerSecond*universe.phystimeelapsed; } break; case SAL_JUST_DO_DAMAGE: //if theres no place to dock with, ships will go to this state and just //do damage to a ship if(ship->playerowner != NULL) { ApplyDamageToTarget((SpaceObjRotImpTarg *)spec->target,salcapcorvettestatics->healthRemovedPerSecond*universe.phystimeelapsed,-1,DEATH_Killed_By_Player,ship->playerowner->playerIndex); } else { ApplyDamageToTarget((SpaceObjRotImpTarg *)spec->target,salcapcorvettestatics->healthRemovedPerSecond*universe.phystimeelapsed,-1,DEATH_Killed_By_Dead_Player,99); } if(spec->target->objtype == OBJ_ShipType) { ((Ship *)spec->target)->gettingrocked = ship; ((Ship *)spec->target)->recentAttacker = ship; ((Ship *)spec->target)->recentlyAttacked = RECENT_ATTACK_DURATION; // start counting down } break; case SAL_SALVAGE1: //don't do dockwith check if JunkYardDawg if(ship->shiptype != JunkYardDawg) { if((spec->dockwith = salCapFindDockWith(ship,spec->target)) == NULL) { spec->salvageState = SAL_JUST_DO_DAMAGE; break; } if(spec->target->salvageInfo == NULL) { bitSet(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); selection.numShips = 1; selection.ShipPtr[0] = ship; clDock(&universe.mainCommandLayer,&selection,DOCK_FOR_BOTHREFUELANDREPAIR|DOCK_AT_SPECIFIC_SHIP,spec->dockwith); } else { spec->salvageState = SAL_FLYBACK_TO_DOCKING_SHIP; if(ship->shiptype == SalCapCorvette) //the dawg only needs 1! { //check if we still need people to attach if(spec->target->salvageInfo->numNeededForSalvage > 0) break; } } } if(spec->target->objtype == OBJ_ShipType) { if(!bitTest(spec->target->flags,SOF_Disabled)) { if(universe.curPlayerIndex == ((Ship *)spec->target)->playerowner->playerIndex) { /////////////////////////// //Ship has been stolen... //event num: STAT_F_ShipStolen //battle chatter maybe... if (ship->playerowner->playerIndex != universe.curPlayerIndex) { speechEventFleetSpec((Ship *)spec->target, STAT_F_ShipStolen, ((Ship *)spec->target)->shiptype, universe.curPlayerIndex); } } } //disable ship here selection.numShips = 1; selection.ShipPtr[0] = (Ship *)spec->target; RemoveShipsFromDoingStuff(&universe.mainCommandLayer,&selection); bitClear(spec->target->flags, SOF_Selectable); bitSet(spec->target->flags,SOF_Disabled); bitSet(spec->target->flags,SOF_DontDrawTrails); shipHasJustBeenDisabled((Ship *)spec->target); if(spec->target->objtype == OBJ_ShipType) { bitClear(spec->target->specialFlags,SPECIAL_SinglePlayerLimitSpeed); } clRemoveTargetFromSelection((SelectAnyCommand *)&selSelected,(SpaceObjRotImpTarg *)spec->target); if(ship->shiptype == JunkYardDawg) { AIVar *var; var = aivarCreate("DawgHasBone"); aivarValueSet(var,TRUE); //disable this ship FOREVER! bitSet(((Ship *)spec->target)->specialFlags2,SPECIAL_2_DisabledForever); //Allow movement for junkyarddawg by settinbg special flag bitSet(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); return TRUE; } if(singlePlayerGame) { AIVar *var; var = aivarCreate("SalvageTD"); aivarValueSet(var, TRUE); } } break; case SAL_FLYBACK_TO_DOCKING_SHIP: if(spec->target->salvageInfo != NULL) { if(spec->target->salvageInfo->numNeededForSalvage > 0) break; } bitClear(spec->target->flags, SOF_Selectable); if(salCapFlyToWithinDockingRange(ship)) { //we are within range spec->salvageState = SAL_DOCKINGSTAGE; } break; case SAL_DOCKINGSTAGE: bitClear(spec->target->flags, SOF_Selectable); spec->dockindex = getDockIndex(ship,spec->target,spec->dockwith); spec->salvageState = SAL_WAIT; break; case SAL_WAIT: bitClear(spec->target->flags, SOF_Selectable); if(!spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy) { bitSet(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint); spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy++; //busy port bitSet(spec->target->specialFlags,SPECIAL_BUSY_BECAUSE_SALVAGE_DOCKING); spec->salvageState = SAL_WAYPOINTHACK; } //docking point busy, so lets wait: if(spec->target->specialFlags & SPECIAL_BUSY_BECAUSE_SALVAGE_DOCKING) { spec->salvageState = SAL_WAYPOINTHACK; } aitrackZeroVelocity((Ship *)spec->target); aitrackSteadyShip((Ship *)spec->target); break; case SAL_WAYPOINTHACK: { vector between,dockwithRight; if(spec->dockwith->shiprace == R1) { if(spec->dockwith->shiptype == Mothership) { vecSub(between,spec->target->posinfo.position,spec->dockwith->posinfo.position); matGetVectFromMatrixCol2(dockwithRight,spec->dockwith->rotinfo.coordsys); if(vecDotProduct(between,dockwithRight) > 0) { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 0.5"); #endif spec->salvageState = WAYPOINTHACK2; } else { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 1"); #endif spec->salvageState = SAL_DO_DOCK; } } else { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 1"); #endif spec->salvageState = SAL_DO_DOCK; } } else { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 1"); #endif spec->salvageState = SAL_DO_DOCK; } } break; case WAYPOINTHACK2: if(salCapFlyToDockingPoint1over2(ship,spec->target)) { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 1"); spec->salvageState = SAL_DO_DOCK; } break; #endif case SAL_DO_DOCK: bitClear(spec->target->flags, SOF_Selectable); if(salCapFlyToDockingPoint1(ship,spec->target)) { //check to see if we need to opendoors if(spec->dockwith->shiprace == R1) { if(spec->dockwith->shiptype == Mothership) { if(salCapNeedBig(ship,spec->target)) { //request, nay, demand mothership door ship opens! madLinkInOpenDoor(spec->dockwith); } } } #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 2"); #endif spec->salvageState = SAL_DO_DOCK2; spec->target->dockingship = spec->dockwith; unClampObj((SpaceObjRotImpTargGuidance *)ship); spec->noDamageTargetTime = universe.totaltimeelapsed; spec->noDamageTarget = spec->target; if(spec->target->salvageInfo != NULL) { spec->target->salvageInfo->numSalvagePointsFree++; //its ok to decrease this here..we were just clmaped spec->target->salvageInfo->numNeededForSalvage++; if(spec->target->salvageInfo->numNeededForSalvage > spec->target->staticinfo->salvageStaticInfo->numNeededForSalvage) { spec->target->salvageInfo->numNeededForSalvage = spec->target->staticinfo->salvageStaticInfo->numNeededForSalvage; } } } break; case SAL_DO_DOCK2: { //needto restore selectabled and disabled flags to //proper values after call to cleanup function SpaceObjRotImpTargGuidanceShipDerelict *targ; Ship *dockwith; sdword groupme = TRUE; //this could potentially screw up... //if we have say a valid target left, but multiple people to go after it, they will all //register a valid target, and not get grouped..then they will //have there order terminated shortly after this bit of code and end up dead //in space not grouped. Very insignificant... if(targets->numTargets > 1 && isThereAnotherTargetForMe(ship,targets)) { //we aren't done groupme = FALSE; } dockwith = spec->dockwith; targ = spec->target; if(!handOffTargetToDockWith(ship)) { //docking ship is BUSY...so we must wait here... return FALSE; } if (singlePlayerGame) { AIVar *var; if ((var = aivarFind("SalvageHandOff")) == NULL) { var = aivarCreate("SalvageHandOff"); } aivarValueSet(var, TRUE); } //clear just in case...only be handing off if we were shure... bitClear(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); SalCapOrderChangedCleanUp(ship); bitClear(targ->flags,SOF_Selectable); bitSet(targ->flags,SOF_Disabled); bitSet(targ->flags,SOF_DontDrawTrails); if(groupme) { //set flag to give grouporder in housekeep function spec->groupme = TRUE; spec->dockwith = dockwith; } } //return FALSE and let end code settle things return FALSE; case SAL_STRIPTECH: spec->timeCounter += universe.phystimeelapsed; if(spec->timeCounter > salcapcorvettestatics->getTechTime) { //tech aquired //autodocking... if(singlePlayerGame) { AIVar *var; var = aivarFind("TechRemoved"); if (var == NULL) { var = aivarCreate("TechRemoved"); } aivarValueSet(var, 100); bitSet(ship->specialFlags, SPECIAL_SalvageTakingHomeTechnology); universe.DerelictTech = TRUE; //indicate that derelict is not to be salvaged again... } // strip any pings associated with it if (spec->target) pingRemovePingByOwner((SpaceObj *)spec->target); // enable appropriate tech //enable(aivarValueGet(aivarFind("TechToEnable"))); //unclamp ship unClampObj((SpaceObjRotImpTargGuidance *)ship); spec->noDamageTargetTime = universe.totaltimeelapsed; spec->noDamageTarget = spec->target; spec->tractorBeam = FALSE; if(ship->rceffect) { StopTractorBeam(ship); } if(spec->target->salvageInfo != NULL) { spec->target->salvageInfo->numSalvagePointsFree++; //its ok to do this here, we we just clamped spec->target->salvageInfo->numNeededForSalvage++; if(spec->target->salvageInfo->numNeededForSalvage > spec->target->staticinfo->salvageStaticInfo->numNeededForSalvage) { spec->target->salvageInfo->numNeededForSalvage = spec->target->staticinfo->salvageStaticInfo->numNeededForSalvage; } } spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; spec->salvageState = SAL_TECH_UNDOCK; } else { //set the aivar to the precentage of stripping that has been done if (singlePlayerGame) { AIVar *var; var = aivarFind("TechRemoved"); if (var == NULL) { var = aivarCreate("TechRemoved"); } aivarValueSet(var, (sdword)((100 * spec->timeCounter) / salcapcorvettestatics->getTechTime)); } } //kas function returns striptech timeCounter break; case SAL_UNDOCK_AND_QUIT: if(spec->target->salvageInfo != NULL) { if(salCapFlyOutOfCone(ship,spec->target,TRUE)) { return TRUE; } } else { return TRUE; } break; case SAL_TECH_UNDOCK: if(spec->target->salvageInfo != NULL) { if(salCapFlyOutOfCone(ship,spec->target,TRUE)) { spec->salvageState = SAL_TECH_TAKE_TECH_HOME; } } else { spec->salvageState = SAL_TECH_TAKE_TECH_HOME; } break; case SAL_TECH_TAKE_TECH_HOME: selection.numShips = 1; selection.ShipPtr[0] = ship; //later..change to dock for tech deposit later... bitClear(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); SalCapOrderChangedCleanUp(ship); if (ship->playerowner->PlayerMothership) { clDock(&universe.mainCommandLayer,&selection,DOCK_AT_SPECIFIC_SHIP,ship->playerowner->PlayerMothership); } else { clDock(&universe.mainCommandLayer,&selection,DOCK_FOR_BOTHREFUELANDREPAIR,NULL); } break; default: dbgFatalf(DBG_Loc,"\nUnknown SalCap AI State %d",spec->salvageState); } return FALSE; } #define DROP_BEGIN 0 #define DROP_DOCK2 1 #define DROP_DONEDOCKING 2 #define DROP_DOORDEAL 3 #define DROP_DO_HARVEST 4 bool handOffTargetToDockWith(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; sdword i; /////////////////// //salcap drop off target speech event //event num: STAT_SCVette_DroppingOff //battle chatter needed if(ship->playerowner->playerIndex == universe.curPlayerIndex) { if (battleCanChatterAtThisTime(BCE_STAT_SCVette_DroppingOff, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_STAT_SCVette_DroppingOff, ship, ship->shiptype); } } /////// if(spec->dockwith->shiptype == Mothership) { MothershipSpec *mspec = (MothershipSpec *)spec->dockwith->ShipSpecifics; for(i=0;idroptarget[i] == spec->target) { //already handed off..don't do. goto handed; } } for(i=0;idroptarget[i] == NULL) { mspec->dropstate[i] = DROP_BEGIN; mspec->droptarget[i] = spec->target; mspec->dockindex[i] = spec->dockindex; goto handed; } } } else { //assumed to be carrier CarrierSpec *cspec = (CarrierSpec *)spec->dockwith->ShipSpecifics; for(i=0;idroptarget[i] == spec->target) { //already handed off..don't do. goto handed; } } for(i=0;idroptarget[i] == NULL) { cspec->dropstate[i] = DROP_BEGIN; cspec->droptarget[i] = spec->target; cspec->dockindex[i] = spec->dockindex; goto handed; } } } //if we get here...we didn't find an attachment point...so we should wait!!! return FALSE; handed: bitSet(spec->target->specialFlags,SPECIAL_SalvagedTargetGoingIntoDockWithShip); return TRUE; } bool DropTargetInShip(Ship *dockwith,sdword *targetDepotState, SpaceObjRotImpTargGuidanceShipDerelict *target,sdword *dockindex) { switch(*targetDepotState) { case DROP_BEGIN: bitClear(target->flags, SOF_Selectable); bitSet(target->flags,SOF_Disabled); bitSet(target->flags,SOF_DontDrawTrails); if(target->objtype == OBJ_ShipType) { SelectCommand selection; selection.numShips = 1; selection.ShipPtr[0] = (Ship *)target; RemoveShipsFromDoingStuff(&universe.mainCommandLayer,&selection); shipHasJustBeenDisabled((Ship *)target); } if(salCapFlyToDockingPoint2(dockwith,target,*dockindex)) { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock 2"); #endif *targetDepotState = DROP_DOCK2; } break; case DROP_DOCK2: bitClear(target->flags, SOF_Selectable); if(salCapFlyToDockingPoint3(dockwith,target,*dockindex)) { #ifdef DEBUG_SALCAP dbgMessagef("\nSAL:dock DONE"); #endif *targetDepotState = DROP_DONEDOCKING; } break; case DROP_DONEDOCKING: bitClear(target->flags, SOF_Selectable); if(dockwith->shiptype == Mothership) { if(dockwith->shiprace == R1) { //if big dock if(salCapNeedBig(dockwith,target)) { MothershipAttachObjectToDoor(dockwith,target); madLinkInCloseDoor(dockwith); *targetDepotState = DROP_DOORDEAL; break; } } } *targetDepotState = DROP_DO_HARVEST; break; case DROP_DOORDEAL: if(dockwith->madDoorStatus != MAD_STATUS_DOOR_CLOSED) { //not done yet break; } //done door closeing //fall through to harvesting... case DROP_DO_HARVEST: //GroupShip(&universe.mainCommandLayer,ship,spec->dockwith); //have ship groupup outside dockwith ship if(bitTest(target->specialFlags2,SPECIAL_2_BusiedDockPoint)) { if(dockwith->dockInfo->dockpoints[*dockindex].thisDockBusy) { bitClear(target->specialFlags2,SPECIAL_2_BusiedDockPoint); dockwith->dockInfo->dockpoints[*dockindex].thisDockBusy--; } } bitClear(target->specialFlags,SPECIAL_BUSY_BECAUSE_SALVAGE_DOCKING); salCapHarvestTarget(target,dockwith); //unbusy dockpoint return TRUE; } return FALSE; } /* case SALVAGE_GET_TECH: spec->time_counter += universe.phystimeelapsed; if(spec->time_counter salcapcorvettestatics->getTechTime) { //tech aquired //autodocking... AIVar *var; var = aivarCreate("TechRemoved"); aivarValueSet(var, TRUE); // enable appropriate tech //enable(aivarValueGet(aivarFind("TechToEnable"))); selection.numShips = 1; selection.ShipPtr[0] = ship; clDock(&universe.mainCommandLayer,&selection,DOCK_FOR_BOTHREFUELANDREPAIR,NULL); } break; */ //housekeep function...we don't really need this I think...it is out of the header file void SalCapCorvetteHouseKeep(Ship *ship) { //was going to slowly rotate small ships.. SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; if((universe.totaltimeelapsed - spec->noDamageTargetTime) > 5.0f) { //turn off no damage vars spec->noDamageTargetTime = 0.0f; spec->noDamageTarget = NULL; } //if we're latched on, and effect ISN'T player;..start playing it. if(!ship->rceffect) { if(spec->target != NULL) { if(spec->target->clampInfo != NULL && spec->target->clampInfo->host == (SpaceObjRotImpTarg *)ship) { startTractorBeam(ship, (SpaceObjRotImpTargGuidanceShipDerelict *)spec->target); } else if(ship->clampInfo != NULL && ship->clampInfo->host == (SpaceObjRotImpTarg *)spec->target) { startTractorBeam(ship, (SpaceObjRotImpTargGuidanceShipDerelict *)spec->target); } } } if(spec->groupme) { Ship *dockwith; SelectCommand selectone; selectone.numShips = 1; selectone.ShipPtr[0] = ship; dockwith = spec->dockwith; spec->dockwith = NULL; spec->groupme = FALSE; //clHalt(&universe.mainCommandLayer,&selectone); RemoveShipsFromDoingStuff(&universe.mainCommandLayer,&selectone); if(dockwith != NULL) { GroupShipIntoMilitaryParade(&universe.mainCommandLayer,ship,dockwith); } } /* SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; vector ShipRight,ShipHeading; vector newHeading,newUp,CurrentUp,CurrentHeading,rotateAxis; matrix rotmat; if(spec->target != NULL) { if(spec->target->clampInfo != NULL && spec->target->clamInfo->host == (SpaceObjRotImpTarg *)ship) { //we have a small ship attached to the salcap corvette //lets rotate it SLOWLY to face a certain direction! if((universe.univUpdateCounter & 7) == 0) { matGetVectFromMatrixCol1(ShipRight,ship->rotinfo.coordsys); matGetVectFromMatrixCol3(ShipHeading,ship->rotinfo.coordsys); newHeading = ShipRight; newUp = ShipHeding; matGetVectFromMatrixCol2(CurrentUp,spec->target->clamInfo->clampCoordsys); matGetVectFromMatrixCol3(CurrentHeading,spec->target->clamInfo->clampCoordsys); if(acos(vecDotProduct(newHeding,CurrentHeading)) < 10.0f } } } */ } //Don't forget to clear tractorbeaminfo in ship and derelict structures.! void SalCapClose(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; } void salCapClearTechBool() { universe.DerelictTech = FALSE; } void SalCapDied(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; spec->tractorBeam = FALSE; if(bitTest(ship->specialFlags, SPECIAL_SalvageTakingHomeTechnology)) { universe.DerelictTech = FALSE; //indicate that derelict is not to be salvaged again... } if(ship->rceffect != NULL) StopTractorBeam(ship); if(spec->target != NULL) { if(spec->salvageState > SALVAGE_BEGIN) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } } unClampObj((SpaceObjRotImpTargGuidance *)spec->target); //if(ship->shiptype != JunkYardDawg) //{ if(spec->target->objtype == OBJ_ShipType) { bitClear(((Ship *)spec->target)->dontrotateever,1); bitClear(((Ship *)spec->target)->dontapplyforceever,1); if(!bitTest(((Ship *)spec->target)->specialFlags2,SPECIAL_2_DisabledForever)) { //if it isn't disabled forever bitClear(spec->target->flags,SOF_Disabled); if (((Ship *)spec->target)->shiptype != CryoTray) { if(((Ship *)spec->target)->playerowner->playerState == PLAYER_ALIVE) { bitSet(spec->target->flags,SOF_Selectable); } } } if(bitTest(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint)) { bitClear(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint); if(spec->dockwith != NULL) { if(spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy) spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy--; } } } //} } } void salCapCleanUpCloakingTarget(Ship *ship, Ship *shiptoremove) { SalCapRemoveShipReferences(ship,shiptoremove); } void SalCapRemoveShipReferences(Ship *ship, Ship *shiptoremove) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; if(shiptoremove == (Ship *)spec->target) { //clear variable just for the heck of it... bitClear(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); if(spec->salvageIndex != NO_INDEX) { salCapUnBusySalvagePoint(ship,spec->target); } if(ship->shiptype == JunkYardDawg) { //release grip on ship... madLinkInOpenSpecialShip(ship); } if(spec->salvageState > SALVAGE_BEGIN) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } } if(bitTest(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint)) { bitClear(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint); if(spec->dockwith != NULL) { if(spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy) spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy--; } } spec->tractorBeam = FALSE; if(ship->rceffect) StopTractorBeam(ship); if(ship->clampInfo != NULL) { #ifdef DEBUG_SALCAP dbgAssert(ship->clampInfo->host == (SpaceObjRotImpTarg *)shiptoremove); #endif unClampObj((SpaceObjRotImpTargGuidance *)ship); } else if(spec->target->clampInfo != NULL) { if(spec->target->clampInfo->host == ((SpaceObjRotImpTarg *)ship)) { unClampObj((SpaceObjRotImpTargGuidance *)spec->target); } } if(spec->target->salvageInfo == NULL) { CommandToDo *command = getShipAndItsCommand(&universe.mainCommandLayer,ship); if(command != NULL) if(command->ordertype.order == COMMAND_DOCK) { //ship is docking AND //shiptoremove is a 'no light' ship...so lets halt this salcap SelectCommand selection; selection.numShips = 1; selection.ShipPtr[0] = ship; clHalt(&universe.mainCommandLayer,&selection); } } CleanSalCapSpec(ship); } if(shiptoremove == spec->dockwith) { //We are screwed here depending on what state we're in...ideally, lets just //reset a few variables and then set the state back to just //after clamping! if(spec->salvageState == SAL_DO_DOCK2 || spec->salvageState == SAL_backoff) { //don't do any real cleanup...since already cleanish SalCapOrderChangedCleanUp(ship); return; } if(spec->target->salvageInfo != NULL) { //this is a no light ship //so we're no longer executing the special command! SelectCommand selection; selection.numShips = 1; selection.ShipPtr[0] = ship; if((spec->dockwith = salCapFindDockWith(ship,spec->target)) == NULL) { bitClear(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); if(spec->salvageState > SALVAGE_BEGIN) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } } clHalt(&universe.mainCommandLayer,&selection); return; } else { clDock(&universe.mainCommandLayer,&selection,DOCK_FOR_BOTHREFUELANDREPAIR,spec->dockwith); } } spec->dockwith = NULL; spec->salvageState = SAL_SALVAGE1; } if(shiptoremove == (Ship *)spec->noDamageTarget) { spec->noDamageTargetTime = 0.0f; spec->noDamageTarget = NULL; } } void salCapRemoveDerelictReferences(Ship *ship,Derelict *d) { SalCapRemoveShipReferences(ship, (Ship *)d); } // Called only when user hits HALT. (clHalt). void SalCapCancelOrder(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; if(spec->target != NULL) { if(bitTest(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint)) { bitClear(spec->target->specialFlags2,SPECIAL_2_BusiedDockPoint); if(spec->dockwith != NULL) { if(spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy) spec->dockwith->dockInfo->dockpoints[spec->dockindex].thisDockBusy--; } } } } //Called when a new order is given to the salvage capture corvette void SalCapOrderChangedCleanUp(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; sdword unclamped = FALSE; bitClear(ship->specialFlags,SPECIAL_Kamikaze); ship->attackvars.attacktarget=NULL; ship->kamikazeState=0; if(!(ship->specialFlags & SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse)) { if(spec->target != NULL) { if(spec->salvageState > SALVAGE_BEGIN) { spec->target->salvageNumTagged[ship->playerowner->playerIndex]--; if(spec->target->salvageNumTagged[ship->playerowner->playerIndex]<0) { //shouldn't go below zero! //so force to zero...these functions can be called twice..unfortunatly spec->target->salvageNumTagged[ship->playerowner->playerIndex] = 0; } } } if(spec->salvageIndex != NO_INDEX) { //twas busy with index #ifdef DEBUG_SALCAP dbgAssert(spec->target != NULL); #endif salCapUnBusySalvagePoint(ship,spec->target); if(spec->target->salvageInfo->numNeededForSalvage > 0) { //ship isn't capable of being salvaged now...so undisable it if ((spec->target->objtype == OBJ_ShipType) && (((Ship *)spec->target)->shiptype != CryoTray) && !bitTest(((Ship *)spec->target)->specialFlags2,SPECIAL_2_DisabledForever)) { if(((Ship *)spec->target)->playerowner->playerState == PLAYER_ALIVE) { bitSet(spec->target->flags,SOF_Selectable); } } bitClear(((Ship *)spec->target)->dontrotateever,1); bitClear(((Ship *)spec->target)->dontapplyforceever,1); if(!bitTest(((Ship *)spec->target)->specialFlags2,SPECIAL_2_DisabledForever)) { if(spec->target->salvageInfo->numSalvagePoints -spec->target->salvageInfo->numSalvagePointsFree > 0) { //ship ISN'T going into docking bay.. //so clear disabled flag bitClear(spec->target->flags,SOF_Disabled); } } } } if(ship->shiptype == JunkYardDawg) { if ((spec->target) && (spec->target->clampInfo != NULL)) { unClampObj((SpaceObjRotImpTargGuidance *)spec->target); unclamped = TRUE; } } else if(ship->clampInfo != NULL && ship->clampInfo->host == (SpaceObjRotImpTarg *)spec->target) { unClampObj((SpaceObjRotImpTargGuidance *)ship); unclamped = TRUE; } else if(spec->target != NULL && spec->target->clampInfo != NULL && spec->target->clampInfo->host == (SpaceObjRotImpTarg *)ship) { //other method where target is attached to ship unClampObj((SpaceObjRotImpTargGuidance *)spec->target); unclamped = TRUE; if(ship->shiptype != JunkYardDawg) { if(!(spec->target->specialFlags & SPECIAL_SalvagedTargetGoingIntoDockWithShip)) { //ship ISN'T going into docking bay.. //so clear disabled flag if(!bitTest(((Ship *)spec->target)->specialFlags2,SPECIAL_2_DisabledForever)) { bitClear(spec->target->flags,SOF_Disabled); } } if ((spec->target->objtype == OBJ_ShipType) && (((Ship *)spec->target)->shiptype != CryoTray)) { if(((Ship *)spec->target)->playerowner->playerState == PLAYER_ALIVE) { if(!bitTest(((Ship *)spec->target)->specialFlags2,SPECIAL_2_DisabledForever)) { bitSet(spec->target->flags,SOF_Selectable); } } } } } spec->tractorBeam = FALSE; if(ship->rceffect) StopTractorBeam(ship); spec->noDamageTargetTime = universe.totaltimeelapsed; spec->noDamageTarget = spec->target; CleanSalCapSpec(ship); } bitClear(ship->specialFlags,SPECIAL_BrokenFormation); } void SalCapDropTarget(Ship *ship) { SelectCommand selection; bitClear(ship->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); selection.numShips = 1; selection.ShipPtr[0] = ship; SalCapOrderChangedCleanUp(ship); if(ship->shiptype == JunkYardDawg) { //release grip on ship... madLinkInOpenSpecialShip(ship); } clHalt(&universe.mainCommandLayer,&selection); } // Save Game stuff #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void SalCapCorvette_RegisterExtraSpaceObjs(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; } void SalCapCorvette_PreFix(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; spec->target = (SpaceObjRotImpTargGuidanceShipDerelict *)SpaceObjRegistryGetID((SpaceObj *)spec->target); spec->dockwith = (Ship *) SpaceObjRegistryGetID((SpaceObj *)spec->dockwith); spec->noDamageTarget = (SpaceObjRotImpTargGuidanceShipDerelict *)SpaceObjRegistryGetID((SpaceObj *)spec->noDamageTarget); } void SalCapCorvette_Fix(Ship *ship) { SalCapCorvetteSpec *spec = (SalCapCorvetteSpec *)ship->ShipSpecifics; spec->target = (SpaceObjRotImpTargGuidanceShipDerelict *)SpaceObjRegistryGetTarget((sdword)spec->target); spec->dockwith = SpaceObjRegistryGetShip((sdword)spec->dockwith); spec->noDamageTarget = (SpaceObjRotImpTargGuidanceShipDerelict *)SpaceObjRegistryGetTarget((sdword)spec->noDamageTarget); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" CustShipHeader SalCapCorvetteHeader = { SalCapCorvette, sizeof(SalCapCorvetteSpec), SalCapCorvetteStaticInit, NULL, SalCapCorvetteInit, SalCapClose, NULL, // SalCapCorvetteAttack, NULL, // DefaultShipFire, NULL, // SalCapCorvetteAttackPassive, NULL, SalCapCorvetteSpecialTarget, SalCapCorvetteHouseKeep, SalCapRemoveShipReferences, SalCapDied, SalCapCorvette_PreFix, NULL, NULL, SalCapCorvette_Fix }; CustShipHeader JunkYardDawgHeader = { JunkYardDawg, sizeof(SalCapCorvetteSpec), SalCapCorvetteStaticInit, NULL, SalCapCorvetteInit, SalCapClose, NULL, // SalCapCorvetteAttack, NULL, // DefaultShipFire, NULL, // SalCapCorvetteAttackPassive, NULL, SalCapCorvetteSpecialTarget, SalCapCorvetteHouseKeep, SalCapRemoveShipReferences, SalCapDied, SalCapCorvette_PreFix, NULL, NULL, SalCapCorvette_Fix }; /*----------------------------------------------------------------------------- Name : dockDrawSalvageInfo Description : draws salvage docking lights Inputs : ship Outputs : Return : ----------------------------------------------------------------------------*/ #if RND_VISUALIZATION void dockDrawSalvageInfo(SpaceObjRotImpTargGuidanceShipDerelict *obj) { sdword i; vector to; StaticInfoHealthGuidanceShipDerelict *statinfo = obj->staticinfo; if(statinfo->salvageStaticInfo != NULL) { SalvageStaticInfo *salvageStaticInfo = statinfo->salvageStaticInfo; SalvageStaticPoint *salvagePoint; sdword salvageNumPoints = salvageStaticInfo->numSalvagePoints; rndLightingEnable(FALSE); rndTextureEnable(FALSE); for (i=0,salvagePoint=&salvageStaticInfo->salvageStaticPoints[0];iconenormal,2000.0f); vecAddTo(to,salvagePoint->position); if(obj->salvageInfo->salvagePoints[i].busy) { //in use, so use RED instead of fuscia primLine3(&salvagePoint->position,&to,colReddish); } else { primLine3(&salvagePoint->position,&to,colFuscia); } } /* salCapSetNewCoordSys(obj,&fakeHeading,&velocityN); matGetVectFromMatrixCol1(realHeading,obj->rotinfo.coordsys); cosAngle = vecDotProduct(fakeHeading,velocityN); Angle = acos(cosAngle); matMultiplyVecByMat(&N,&fakeHeading,&obj->rotinfo.coordsys); vecScalarMultiply(to,N,6000.0f); primLine3(&o,&to,colRGB(255, 255, 255)); vecCrossProduct(planePerp,velocityN,fakeHeading); vecNormalize(&planePerp); nisRotateAboutVector((real32 *) &rotMatrix, &planePerp, Angle); matMultiplyVecByMat(&neededHeading,&realHeading,&rotMatrix); matMultiplyVecByMat(&N,&planePerp,&obj->rotinfo.coordsys); vecScalarMultiply(to,N,6000.0f); primLine3(&o,&to,colRGB(255, 255, 0)); matMultiplyVecByMat(&N,&neededHeading,&obj->rotinfo.coordsys); vecScalarMultiply(to,N,4000.0f); primLine3(&o,&to,colRGB(0, 255, 0)); matMultiplyVecByMat(&N,&velocityN,&obj->rotinfo.coordsys); vecScalarMultiply(to,N,4000.0f); primLine3(&o,&to,colRGB(0, 0, 255)); */ rndLightingEnable(TRUE); } } #endif void salCapExtraSpecialOrderCleanUp(SelectCommand *selection,udword ordertype,Ship *dockwith,SelectCommand *targets) { sdword i; for(i=0;inumShips;i++) { //SHOULD WE DO A CHECK HERE FOR JUNKYARD DAWG!!??!?!?! if(selection->ShipPtr[i]->shiptype == SalCapCorvette) { if( ((SalCapCorvetteSpec *)selection->ShipPtr[i]->ShipSpecifics)->target != NULL) { if(((SalCapCorvetteSpec *)selection->ShipPtr[i]->ShipSpecifics)->target->clampInfo != NULL && ((SalCapCorvetteSpec *)selection->ShipPtr[i]->ShipSpecifics)->target->clampInfo->host == (SpaceObjRotImpTarg *)selection->ShipPtr[i]) { //salcap corvette is doing something new and has a target //clamped on! switch (ordertype) { case COMMAND_MOVE: case COMMAND_NULL: break; //no cleanup case COMMAND_SPECIAL: if(ShipInSelection(targets,(Ship *)((SalCapCorvetteSpec *)selection->ShipPtr[i]->ShipSpecifics)->target)) { //given command special with target already attached break; } goto ditchTarget; case COMMAND_DOCK: if(dockwith != NULL) { if(dockwith->shiptype == Mothership || dockwith->shiptype == Carrier) { //keep it clamped and simply dock with the new ship! break; } } goto ditchTarget; case COMMAND_ATTACK: case COMMAND_LAUNCHSHIP: case COMMAND_COLLECTRESOURCE: case COMMAND_BUILDINGSHIP: case COMMAND_HALT: case COMMAND_MILITARYPARADE: ditchTarget: bitClear(selection->ShipPtr[i]->specialFlags,SPECIAL_SalvagerHasSomethingAttachedAndIsDoingSomethingElse); SalCapOrderChangedCleanUp(selection->ShipPtr[i]); break; } } } } } } //counts the number of salvage corvettes in the universe targetting this same ship //must already be targetting it //returns TRUE if enough are heading towards it to get it bool salCapAreEnoughSalvagersTargettingThisTarget(Ship *ship,SpaceObjRotImpTargGuidanceShipDerelict *target) { sdword count; Node *node = universe.mainCommandLayer.todolist.head; CommandToDo *todo; sdword i; count = 0; while (node != NULL) { todo = (CommandToDo *) listGetStructOfNode(node); if(todo->ordertype.order == COMMAND_SPECIAL) { for(i=0;iselection->numShips;i++) { if(todo->selection->ShipPtr[i]->shiptype == SalCapCorvette) { //this is a salvage corvette if( ((SalCapCorvetteSpec *)todo->selection->ShipPtr[i]->ShipSpecifics)->target ==target) { //this salcorvette is targetting this target count++; } } } } node = node->next; } if(target->salvageInfo != NULL) { if(count < target->staticinfo->salvageStaticInfo->numNeededForSalvage) { return FALSE; } return TRUE; } if(count >= 1) { return TRUE; } return FALSE; }