/*============================================================================= Name : HeavyCorvette.c Purpose : Specifics for the Heavy Corvette Created 6/30/1997 by gshaw Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include "types.h" #include "debug.h" #include "spaceobj.h" #include "HeavyCorvette.h" #include "statscript.h" #include "gun.h" #include "attack.h" #include "DefaultShip.h" #include "shipselect.h" #include "aiship.h" #include "aitrack.h" #include "tactics.h" #include "fastmath.h" #include "universe.h" #include "soundevent.h" #include "battle.h" //#define DEBUG_HEAVYCORVETTE typedef struct { AttackSideStepParameters sidestepParameters; } HeavyCorvetteStatics; HeavyCorvetteStatics HeavyCorvetteStaticRace1; HeavyCorvetteStatics HeavyCorvetteStaticRace2; void heavyCleanSpec(Ship *ship); bool doBurstCharging(Ship *ship); bool flytoBurstPosition(Ship *ship); bool doBurstFire(Ship *ship); void HeavyCorvetteStaticInit(char *directory,char *filename,struct ShipStaticInfo *statinfo) { HeavyCorvetteStatics *corvstat = (statinfo->shiprace == R1) ? &HeavyCorvetteStaticRace1 : &HeavyCorvetteStaticRace2; memset(corvstat,sizeof(*corvstat),0); scriptSetStruct(directory,filename,AttackSideStepParametersScriptTable,(ubyte *)&corvstat->sidestepParameters); statinfo->custstatinfo = corvstat; } void HeavyCorvetteInit(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; attackSideStepInit(&spec->attacksidestep); heavyCleanSpec(ship); } void HeavyCorvetteAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; HeavyCorvetteStatics *corvstat = (HeavyCorvetteStatics *)((ShipStaticInfo *)ship->staticinfo)->custstatinfo; attackSideStep(ship,target,&spec->attacksidestep,&corvstat->sidestepParameters); } void HeavyCorvetteAttackPassive(Ship *ship,Ship *target,bool rotate) { if ((rotate) & ((bool)((ShipStaticInfo *)(ship->staticinfo))->rotateToRetaliate)) { attackPassiveRotate(ship,target); } else { attackPassive(ship,target); } } //State defines for burst attack #define BURST_Begin 0 #define BURST_FlyToFirePoint 1 #define BURST_Fire 2 bool HeavyCorvetteSpecialTarget(Ship *ship, void *custom) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; SelectAnyCommand *targets = (SelectAnyCommand *)custom; real32 tempreal; vector Av; sdword i,flag; if(spec->cooldown) { aitrackSteadyShip(ship); return FALSE; } if (targets->numTargets == 0) { return TRUE; } switch(spec->burstState) { case BURST_Begin: //get average position of targets vecSet(Av,0.0f,0.0f,0.0f); for(i=0;inumTargets;i++) { vecAddTo(Av,targets->TargetPtr[i]->collInfo.collPosition); } tempreal = 1.0f/((real32)i); vecScalarMultiply(spec->burstFireVector,Av,tempreal); /////////////////////////////// /////burst attack speech event! //event num: COMM_HVette_BurstAttack //use battle chatter if(ship->playerowner->playerIndex == universe.curPlayerIndex) { if(ship->playerowner->playerIndex == universe.curPlayerIndex) { if (battleCanChatterAtThisTime(BCE_COMM_HVette_BurstAttack, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_COMM_HVette_BurstAttack, ship, SOUND_EVENT_DEFAULT); } } } /////////////////////////////// spec->burstState=BURST_FlyToFirePoint; break; case BURST_FlyToFirePoint: flag = 0; if(doBurstCharging(ship)) { //ship is fully charged flag = 1; } if(flytoBurstPosition(ship)) { //ship is in position fire if(flag == 1) { spec->burstState=BURST_Fire; } } break; case BURST_Fire: if(doBurstFire(ship)) { spec->burstState = BURST_Begin; dbgMessagef("\nFiring Burst Fire."); } break; default: dbgFatalf(DBG_Loc,"\nUnknown BurstState %d for shiptype %d.",spec->burstState,ship->shiptype); } //perform burst attack AI here... return FALSE; } void heavyCleanSpec(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; spec->burstState = BURST_Begin; spec->burstChargeState = 0.0f; spec->burstChargeState2 = 0.0f; spec->chargeEffect = NULL; spec->cooldown = FALSE; } void heavyCorvetteOrderChanged(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; spec->burstState = BURST_Begin; } //this function charges the ship for burst fire. Specialized for //heavy corvette. // //Function also creates effect for charging bool doBurstCharging(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; if(spec->chargeEffect == NULL) { //start charging effect if not playing allready } if(spec->burstChargeState < burstChargeTime) { spec->burstChargeState += universe.phystimeelapsed; return(FALSE); } #ifdef DEBUG_HEAVYCORVETTE dbgMessagef("\nBurst Fire Charged!"); #endif return(TRUE); } //this function flys the ship to within range of the desired target location and //orients itself to fire. Returns true when in position bool flytoBurstPosition(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; vector heading; bool ready = FALSE; //maybe track to within gun gimbleness vecSub(heading,spec->burstFireVector,ship->posinfo.position); vecNormalize(&heading); if(aitrackHeadingWithFlags(ship,&heading,0.99f,AITRACKHEADING_IGNOREUPVEC)) { ready = TRUE; } if(!MoveReachedDestinationVariable(ship,&spec->burstFireVector,burstRange)) { aishipFlyToPointAvoidingObjs(ship,&spec->burstFireVector,AISHIP_FastAsPossible,0.0f); return(FALSE); } aitrackZeroVelocity(ship); return(ready); } //fires the bursts for the ship bool doBurstFire(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; GunInfo *gunInfo = ship->gunInfo; sdword numGuns = gunInfo->numGuns; //Gun *gun; sdword done; vector trajectory,heading; real32 range,one_over_range; SpaceObjRotImpTarg dummyTarg; vecSub(trajectory,spec->burstFireVector,ship->posinfo.position); range = vecMagnitudeSquared(trajectory); range = fsqrt(range); one_over_range = 1.0f/range; vecScalarMultiply(trajectory,trajectory,one_over_range); dummyTarg.objtype = OBJ_ShipType; dummyTarg.posinfo.position = spec->burstFireVector; dummyTarg.collInfo.collPosition = spec->burstFireVector; dummyTarg.currentLOD = ship->currentLOD; dummyTarg.collMyBlob = ship->collMyBlob; vecSet(dummyTarg.posinfo.velocity,0.0f,0.0f,0.0f); //track target even more precisely vecSub(heading,spec->burstFireVector,ship->posinfo.position); vecNormalize(&heading); aitrackHeadingWithFlags(ship,&heading,0.9999f,AITRACKHEADING_IGNOREUPVEC); //set special information that needs to be 'transmitted' //to the code in gunshoot. //fix later spec->bulletLifeTime = range*oneOverburstSpeed; bitSet(ship->specialFlags,SPECIAL_BurstFiring); done = gunShootGunsAtTarget(ship,&dummyTarg,0.0f,&trajectory); bitClear(ship->specialFlags,SPECIAL_BurstFiring); if(done == TRUE) { spec->cooldown = TRUE; spec->burstChargeState2 = burstCoolDownTime; } return done; } void HeavyCorvetteHouseKeep(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; if(spec->cooldown == TRUE) { spec->burstChargeState2-=universe.phystimeelapsed; #ifdef DEBUG_HEAVYCORVETTE dbgMessagef("\nCooling Down..."); #endif if(spec->burstChargeState2 <= 0.0f) { spec->burstChargeState = 0.0f; spec->cooldown = FALSE; } } } void HeavyCorvette_PreFix(Ship *ship) { HeavyCorvetteSpec *spec = (HeavyCorvetteSpec *)ship->ShipSpecifics; spec->chargeEffect = NULL; } CustShipHeader HeavyCorvetteHeader = { HeavyCorvette, sizeof(HeavyCorvetteSpec), HeavyCorvetteStaticInit, NULL, HeavyCorvetteInit, NULL, HeavyCorvetteAttack, DefaultShipFire, HeavyCorvetteAttackPassive, NULL, HeavyCorvetteSpecialTarget, HeavyCorvetteHouseKeep, NULL, NULL, HeavyCorvette_PreFix, NULL, NULL, NULL };