/*============================================================================= Name : P2MultiBeamFrigate.c Purpose : Specifics for the P2MultiBeamFrigate Created 5/07/1998 by ddunlop Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include #include #include "types.h" #include "fastmath.h" #include "debug.h" #include "objtypes.h" #include "spaceobj.h" #include "collision.h" #include "physics.h" #include "universe.h" #include "p2MultiBeamFrigate.h" #include "statscript.h" #include "gun.h" #include "aiship.h" #include "aitrack.h" #include "attack.h" #include "mex.h" #include "soundevent.h" #include "flightman.h" #include "commandlayer.h" #include "univupdate.h" #include "DefaultShip.h" #define STATE_INIT 0 #define STATE_APPROACH 1 #define STATE_SPINUP 2 #define STATE_FIRE 3 #define STATE_SPINDOWN 4 //#define ROTSPEED_FACTOR 20 //#define ROTACCEL_FACTOR 100 #ifdef ddunlop #define DEBUG_FRIGATEATTACK #endif typedef struct { real32 MBRstat; real32 MultiBeamRange[NUM_TACTICS_TYPES]; real32 AttackRotationSpeed; real32 BeamFireTime; real32 fireDownTime; } P2MultiBeamFrigateStatics; P2MultiBeamFrigateStatics P2MultiBeamFrigateStatic; void P2MultiBeamFrigateAttackDoAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist,bool PassiveAttack); void P2MultiBeamFrigateFire(Ship *ship,SpaceObjRotImpTarg *target); scriptStructEntry P2MultiBeamFrigateScriptTable[] = { { "MultiBeamRange" , scriptSetReal32CB , (udword) &(P2MultiBeamFrigateStatic.MBRstat) , (udword) &(P2MultiBeamFrigateStatic) }, { "AttackRotationSpeed" , scriptSetReal32CB , (udword)&(P2MultiBeamFrigateStatic.AttackRotationSpeed) , (udword) &(P2MultiBeamFrigateStatic) }, { "BeamFireTime" , scriptSetReal32CB , (udword)&(P2MultiBeamFrigateStatic.BeamFireTime) , (udword) &(P2MultiBeamFrigateStatic) }, { "fireDownTime" , scriptSetReal32CB , (udword)&(P2MultiBeamFrigateStatic.fireDownTime) , (udword) &(P2MultiBeamFrigateStatic) }, // {"MultiBeamRange", scriptsetReal32CB, &(P2MultiBeamFrigateStatic.MultiBeamRange)}, // {"MultiBeamRange", scriptsetReal32CB, &(P2MultiBeamFrigateStatic.MultiBeamRange)}, { NULL,NULL,0,0 } }; void P2MultiBeamFrigateStaticInit(char *directory,char *filename,struct ShipStaticInfo *statinfo) { udword i; P2MultiBeamFrigateStatics *frigstat = &P2MultiBeamFrigateStatic; statinfo->custstatinfo = frigstat; scriptSetStruct(directory, filename, P2MultiBeamFrigateScriptTable, (ubyte *)frigstat); for(i=0;iMultiBeamRange[i] = frigstat->MBRstat * statinfo->bulletRange[i]; // multiply by gun range to get real beam range } } void P2MultiBeamFrigateInit(Ship *ship) { P2MultiBeamFrigateSpec *spec = (P2MultiBeamFrigateSpec *)ship->ShipSpecifics; ship->aistateattack = STATE_INIT; spec->spining = FALSE; } void P2MultiBeamFrigateAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist) { P2MultiBeamFrigateAttackDoAttack(ship,target,maxdist,FALSE); } void P2MultiBeamFrigateAttackDoAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist,bool PassiveAttack) { ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; P2MultiBeamFrigateStatics *frigstat = (P2MultiBeamFrigateStatics *)shipstaticinfo->custstatinfo; P2MultiBeamFrigateSpec *spec = (P2MultiBeamFrigateSpec *)ship->ShipSpecifics; vector trajectory; vector shipRightVec; real32 range; spec->aiattacklast = universe.totaltimeelapsed; ship->autostabilizeship = FALSE; aishipGetTrajectory(ship, target, &trajectory); range = RangeToTarget(ship,target,&trajectory); if (range > frigstat->MultiBeamRange[ship->tacticstype]) { //not in range if(!PassiveAttack) { //do aiship fly to stuff here //if not in range...fly to the ship //else track zero velocity aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying + AISHIP_CarTurn,0.0f); } return; } //we are in range vecNormalize(&trajectory); if(!PassiveAttack) { aitrackZeroVelocity(ship); } matGetVectFromMatrixCol2(shipRightVec,ship->rotinfo.coordsys); aitrackHeadingAndUp(ship,&trajectory,&shipRightVec,0.9999f); if(vecMagnitudeSquared(ship->rotinfo.rotspeed) > frigstat->AttackRotationSpeed) { if(aitrackHeadingWithFlags(ship,&trajectory,0.99f,AITRACKHEADING_IGNOREUPVEC|AITRACK_DONT_ZERO_ME)) { //rotation speed reached //lets fire guns if we can P2MultiBeamFrigateFire(ship,target); } } /* OLD SCHOOL CODE */ /* switch (ship->aistateattack) { case STATE_INIT: // deliberatly fall through to state_approach // spec->steady = FALSE; ship->aistateattack=STATE_APPROACH; case STATE_APPROACH: #ifdef DEBUG_FRIGATEATTACK dbgMessagef("\nShip %x STATE_APPROACH", (udword)ship); #endif if (spec->spining) { ship->aistateattack = STATE_SPINDOWN; break; } aishipGetTrajectory(ship, target, &trajectory); range = RangeToTarget(ship,target,&trajectory); if (range < frigstat->MultiBeamRange[ship->tacticstype] || PassiveAttack) { temp = trajectory; temp.z+=5; temp.y+=5; temp.x+=5; //vecCrossProduct(heading,trajectory,temp); //vecNormalize(&heading); vecNormalize(&trajectory); if(!PassiveAttack) { aitrackZeroVelocity(ship); } if (aitrackHeadingWithFlags(ship,&trajectory,0.99f,AITRACKHEADING_IGNOREUPVEC)) { ship->aistateattack = STATE_SPINUP; //get up vector matGetVectFromMatrixCol1(temp,ship->rotinfo.coordsys); aitrackForceHeading(ship,&trajectory,&temp); } } else { aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying + AISHIP_CarTurn,0.0f); } break; case STATE_SPINUP: #ifdef DEBUG_FRIGATEATTACK dbgMessagef("\nShip %x STATE_SPINUP", (udword)ship); #endif desiredrotspeed = frigstat->AttackRotationSpeed; if(!PassiveAttack) { aitrackZeroVelocity(ship); } aitrackHeadingAndUp(ship,&heading,&shipRightVec,0.99f); if (aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW)) { ship->aistateattack = STATE_FIRE; spec->spining = TRUE; spec->aifirestarttime = universe.totaltimeelapsed + frigstat->BeamFireTime; } break; case STATE_FIRE: #ifdef DEBUG_FRIGATEATTACK dbgMessagef("\nShip %x STATE_FIRE", (udword)ship); #endif shipstaticinfo->custshipheader.CustShipFire(ship, target); if(!PassiveAttack) { aitrackZeroVelocity(ship); } aishipGetTrajectory(ship,target,&trajectory); range = RangeToTarget(ship,target,&trajectory); if (range > frigstat->MultiBeamRange[ship->tacticstype]) ship->aistateattack = STATE_INIT; temp = trajectory; temp.z+=5; temp.y+=5; temp.x+=5; vecCrossProduct(heading,trajectory,temp); vecNormalize(&heading); vecNormalize(&trajectory); //if (aitrackHeadingWithFlags(ship,&heading,0.99f,AITRACKHEADING_IGNOREUPVEC)) // { // ship->aistateattack = STATE_INIT; // } desiredrotspeed = frigstat->AttackRotationSpeed; aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW); if(universe.totaltimeelapsed > spec->aifirestarttime) { //fire time up! start spindown ship->aistateattack = STATE_SPINDOWN; spec->aifirestarttime = universe.totaltimeelapsed + frigstat->fireDownTime; } break; case STATE_SPINDOWN: #ifdef DEBUG_FRIGATEATTACK dbgMessagef("\nShip %x STATE_SPINDOWN", (udword)ship); #endif desiredrotspeed = 0; if(!PassiveAttack) { aitrackZeroVelocity(ship); } if (aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW) && universe.totaltimeelapsed > spec->aifirestarttime) { ship->aistateattack = STATE_INIT; spec->spining = FALSE; } break; } */ } void P2MultiBeamFrigateFire(Ship *ship,SpaceObjRotImpTarg *target) { GunInfo *guninfo = ship->gunInfo; sdword numGuns; sdword i; Gun *gun; if ((guninfo == NULL)||(target == NULL)) { return; } numGuns = guninfo->numGuns; for (i=0;iguns[i]; if (gunCanShoot(ship, gun)) if (gun->gunstatic->guntype==GUN_Gimble) { gunOrientGimbleGun(ship,gun,target); gunShoot(ship,gun,target); } } } void P2MultiBeamFrigateAttackPassive(Ship *ship,Ship *target,bool rotate) { ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; P2MultiBeamFrigateSpec *spec = (P2MultiBeamFrigateSpec *)ship->ShipSpecifics; P2MultiBeamFrigateStatics *frigstat = (P2MultiBeamFrigateStatics *)shipstaticinfo->custstatinfo; vector trajectory; vector heading, temp; real32 range; P2MultiBeamFrigateAttackDoAttack(ship,(SpaceObjRotImpTarg *)target,1000.0f,TRUE); return; aishipGetTrajectory(ship, (SpaceObjRotImpTarg *)target, &trajectory); range = RangeToTarget(ship,(SpaceObjRotImpTarg *)target,&trajectory); if ( (range < frigstat->MultiBeamRange[ship->tacticstype]) && (rotate) ) { temp = trajectory; temp.z+=5; temp.y+=5; temp.x+=5; vecCrossProduct(heading,trajectory,temp); vecNormalize(&heading); vecNormalize(&trajectory); if (aitrackHeadingAndUp(ship,&heading,&trajectory,0.99f)) { if (!spec->steady) aitrackForceHeading(ship,&heading,&trajectory); spec->steady = TRUE; } else spec->steady = FALSE; } shipstaticinfo->custshipheader.CustShipFire(ship, (SpaceObjRotImpTarg *)target); } void P2MultiBeamFrigateHouseKeep(Ship *ship) { P2MultiBeamFrigateSpec *spec = (P2MultiBeamFrigateSpec *)ship->ShipSpecifics; // ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; // real32 desiredrotspeed; // real32 rotspeed; /* if (spec->spining) { if (universe.totaltimeelapsed - spec->aiattacklast > 0.15) { desiredrotspeed = 0; rotspeed = ship->rotinfo.rotspeed.z; if (rotspeed > 0.2) aitrackRotationSpeed(ship,desiredrotspeed,ROT_ABOUTZCCW); else if (aitrackStabilizeShip(ship)) { spec->spining = FALSE; aitrackForceShipZeroRotation(ship); ship->aistateattack = STATE_INIT; } } } */ } CustShipHeader P2MultiBeamFrigateHeader = { P2MultiBeamFrigate, sizeof(P2MultiBeamFrigateSpec), P2MultiBeamFrigateStaticInit, NULL, P2MultiBeamFrigateInit, NULL, P2MultiBeamFrigateAttack, // DefaultShipFire, P2MultiBeamFrigateFire, P2MultiBeamFrigateAttackPassive, NULL, NULL, P2MultiBeamFrigateHouseKeep, NULL, NULL, NULL, NULL, NULL, NULL };