lod *lodLevelGet(void *spaceObj, vector *camera, vector *ship) { real32 distance; SpaceObj *obj = (SpaceObj *)spaceObj; lodinfo *info = obj->staticinfo->staticheader.LOD; dbgAssert(info != NULL); //verify the LOD table exists vecSub(obj->cameraDistanceVector,*camera,*ship); obj->cameraDistanceSquared = distance = vecMagnitudeSquared(obj->cameraDistanceVector); #if LOD_SCALE_DEBUG if (lodDebugScaleFactor != 0.0f) { lodScaleFactor = lodDebugScaleFactor; } #endif if (distance > info->level[obj->currentLOD].bOff * lodScaleFactor) { //if drop a level of detail do { obj->currentLOD++; //go to lower level if (obj->currentLOD >= info->nLevels) { obj->currentLOD = info->nLevels-1; break; } } while (distance > info->level[obj->currentLOD].bOff * lodScaleFactor); } else { while (obj->currentLOD > 0 && distance < info->level[obj->currentLOD - 1].bOn * lodScaleFactor) { //if go higher level of detail obj->currentLOD--; //go to higher level } } dbgAssert(obj->currentLOD >= 0); dbgAssert(obj->currentLOD < info->nLevels); //verify we are within the available levels of detail #if LOD_PRINT_DISTANCE if (keyIsStuck(WKEY)) { keyClearSticky(WKEY); lodScaleFactor *= 0.99f; dbgMessagef("\nlodScaleFactor = %.3f", lodScaleFactor); } if (keyIsStuck(OKEY)) { keyClearSticky(OKEY); lodScaleFactor *= 1.01f; dbgMessagef("\nlodScaleFactor = %.3f", lodScaleFactor); } if (lodTuningMode) { obj->currentLOD = min(rndLOD, info->nLevels - 1); return(&info->level[min(rndLOD, info->nLevels - 1)]); } #endif return(&info->level[obj->currentLOD]); //return pointer to lod structure }
void getRotatePoint(Ship *ship, vector *point, real32 *distance) { Node *slavenode; Ship *slave; udword count; vector dist; dbgAssertOrIgnore(ship->flags & SOF_Slaveable); //ship should be slaveable dbgAssertOrIgnore(ship->slaveinfo->slaves.num >= 5); //need enough for a pie plate! slavenode = ship->slaveinfo->slaves.head; point->x = ship->posinfo.position.x; point->y = ship->posinfo.position.y; point->z = ship->posinfo.position.z; count = 0; while (count < 5) { slave = (Ship *) listGetStructOfNode(slavenode); vecAdd(*point, *point, slave->posinfo.position); slavenode = slavenode->next; count++; } point->x /= 6.0f; point->y /= 6.0f; point->z /= 6.0f; vecSub(dist,ship->posinfo.position, *point); *distance = vecMagnitudeSquared(dist); *distance = fsqrt(*distance); }
void vecNormalize(LWONormal *a) { float mag = (float)sqrt(vecMagnitudeSquared(*a)); a->x /= mag; a->y /= mag; a->z /= mag; }
/*----------------------------------------------------------------------------- Name : vecCopyAndNormalize Description : copies a source vector to destination vector, and then normalizes the destination vector Inputs : src, dst Outputs : Return : ----------------------------------------------------------------------------*/ void vecCopyAndNormalize(vector *src,vector *dst) { real32 mag = fsqrt(vecMagnitudeSquared(*src)); real32 oneOverMag = 1.0f / mag; dst->x = src->x * oneOverMag; dst->y = src->y * oneOverMag; dst->z = src->z * oneOverMag; }
/*----------------------------------------------------------------------------- Name : vecNormalize Description : normalizes a vector (makes it a unit vector) Inputs : vector Outputs : vector is normalized Return : ----------------------------------------------------------------------------*/ void vecNormalize(vector *a) { real32 mag = fsqrt(vecMagnitudeSquared(*a)); real32 oneOverMag = 1.0f / mag; a->x *= oneOverMag; a->y *= oneOverMag; a->z *= oneOverMag; }
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); } } }
/*----------------------------------------------------------------------------- Name : vecCapMinVector Description : limits a vector's minimum magnitude from growing below a maximum magnitude Inputs : vectorToCap, minMagnitude Outputs : Return : ----------------------------------------------------------------------------*/ void vecCapMinVector(vector *vectorToCap,real32 minMagnitude) { real32 actualMag = fsqrt(vecMagnitudeSquared(*vectorToCap)); real32 ratio; if (actualMag < minMagnitude) { ratio = minMagnitude / actualMag; vectorToCap->x *= ratio; vectorToCap->y *= ratio; vectorToCap->z *= ratio; } }
//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 GenericDefenderAttack(Ship *ship,SpaceObjRotImpTarg *target,real32 maxdist) { ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; GenericDefenderStatics *defenderstat = (GenericDefenderStatics *)shipstaticinfo->custstatinfo; real32 newrange; //newrange = maxdist - defenderstat->gunRange; //newrange = defenderstat->gunRange - newrange; //newrange = defenderstat->gunRange - maxdist + defenderstat->gunRange; //could do check if maxdist == gunRange, then don't do calcs, just use //max dist vector trajectory; real32 dist; real32 range; real32 temp; real32 rightvelocity; vector right; newrange = (defenderstat->gunRange[ship->tacticstype]*2) - maxdist; if(newrange < 0.0f) newrange = defenderstat->tooCloseRange[ship->tacticstype] + 100.0f; else if(newrange > defenderstat->gunRange[ship->tacticstype]) { newrange = defenderstat->gunRange[ship->tacticstype]; } switch (ship->aistateattack) { case 0: ship->aistateattack = DEFENDER_APPROACH; // fall through to DEFENDER_APPROACH case DEFENDER_APPROACH: aishipGetTrajectory(ship,target,&trajectory); dist = fsqrt(vecMagnitudeSquared(trajectory)); range = RangeToTargetGivenDist(ship,target,dist); if (range > newrange) { aishipFlyToShipAvoidingObjsWithVel(ship,target,AISHIP_FastAsPossible|AISHIP_PointInDirectionFlying,0.0f,&target->posinfo.velocity); break; } #ifdef DEBUG_DEFENDER dbgMessagef("\n%x Changing to circle",ship); #endif ship->aistateattack = DEFENDER_CIRCLE; goto circleAlreadyCalculatedTrajectory; case DEFENDER_CIRCLE: aishipGetTrajectory(ship,target,&trajectory); dist = fsqrt(vecMagnitudeSquared(trajectory)); range = RangeToTargetGivenDist(ship,target,dist); if (range > newrange) { #ifdef DEBUG_DEFENDER dbgMessagef("\n%x Changing back to approach",ship); #endif ship->aistateattack = DEFENDER_APPROACH; break; } circleAlreadyCalculatedTrajectory: vecDivideByScalar(trajectory,dist,temp); aitrackHeading(ship,&trajectory,FLYSHIP_ATTACKACCURACY); matGetVectFromMatrixCol2(right,ship->rotinfo.coordsys); rightvelocity = vecDotProduct(right,ship->posinfo.velocity); if (rightvelocity < defenderstat->CIRCLE_RIGHT_VELOCITY) { physApplyForceToObj((SpaceObj *)ship,ship->nonstatvars.thruststrength[TRANS_RIGHT]*defenderstat->CIRCLE_RIGHT_THRUST,TRANS_RIGHT); } if (range < defenderstat->tooCloseRange[ship->tacticstype]) { aitrackZeroForwardVelocity(ship); } if (ship->attackvars.multipleAttackTargets) { gunShootGunsAtMultipleTargets(ship); } else { gunShootGunsAtTarget(ship,target,range,&trajectory); } break; default: dbgAssert(FALSE); break; } // attackStraightForward(ship,target,newrange,defenderstat->tooCloseRange[ship->tacticstype]); }
void doKamikazeAttack(Ship *ship,SpaceObjRotImpTarg *target) { real32 mag,dist,range,shipvel; vector destination,trajectory,heading,shipheading,EinsteinVelocity; ShipStaticInfo *shipstaticinfo = ship->staticinfo; vecSub(trajectory,target->collInfo.collPosition,ship->posinfo.position); mag = vecMagnitudeSquared(trajectory); dist = fsqrt(mag); destination = trajectory; vecNormalize(&destination); heading = destination; //this hokey fudge factor is needed so the kamikaze ship doesn't //slow down as it reaches its destination mag = dist + 500.0f; vecScalarMultiply(destination,destination,mag); vecAddTo(destination,target->collInfo.collPosition); range = RangeToTargetGivenDist(ship,target,dist); switch(ship->kamikazeState) { case K_Start: //if within a threshold range bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast); if(range < 500.0f) { //calculate flyby dist matGetVectFromMatrixCol3(shipheading, ship->rotinfo.coordsys); vecScalarMultiply(shipheading,shipheading,kamikazeFlyByDist); vecAdd(ship->kamikazeVector,shipheading,target->collInfo.collPosition); ship->kamikazeState = K_TurnAround; } ship->kamikazeState = K_Ram; break; case K_Ram: if (range < 400.0f) { ship->kamikazeState = K_Yell; } case K_Ram2: //lets use...mmmmm..twister theor...no...relativity vecSub(EinsteinVelocity,ship->posinfo.velocity,target->posinfo.velocity); shipvel = fsqrt(vecMagnitudeSquared(EinsteinVelocity)); if(ship->shiptype == MinelayerCorvette) { ((MinelayerCorvetteSpec *)(ship->ShipSpecifics))->mineaistate = MINE_DROP_ATTACK; } else if (ship->shiptype == DefenseFighter) { goto dontshoot; } if (isShipStaticInterceptor(shipstaticinfo)) { if (range < shipstaticinfo->bulletRange[ship->tacticstype]) { GenericInterceptorStatics *interceptorstat = (GenericInterceptorStatics *)shipstaticinfo->custstatinfo; uword targetIndex; if (target->objtype == OBJ_ShipType) { targetIndex = (uword)((ShipStaticInfo *)target->staticinfo)->shipclass; } else { targetIndex = (uword)NUM_CLASSES; } if (GenericInterceptorCanFire(ship,target,&trajectory,interceptorstat->triggerHappy[ship->tacticstype][targetIndex])) { ship->staticinfo->custshipheader.CustShipFire(ship,target); } } } else { gunShootGunsAtTarget(ship,target,range,&trajectory); } dontshoot: aishipFlyToPointAvoidingObjs(ship,&destination,AISHIP_PointInDirectionFlying | AISHIP_FirstPointInDirectionFlying | AISHIP_FastAsPossible,0.0f); if(range < 1500.0f) { bitSet(ship->specialFlags,SPECIAL_KamikazeCrazyFast); } else { bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast); } /* if(range < 400.0f && (shipvel < ship->staticinfo->staticheader.maxvelocity*0.7f || vecDotProduct(trajectory,heading) < 0)) { //ship is inside 400.0f, and isn't faceing ship, or isn't //going fast enough //calculate flyby dist matGetVectFromMatrixCol3(shipheading, ship->rotinfo.coordsys); vecScalarMultiply(shipheading,shipheading,kamikazeFlyByDist); vecAdd(ship->kamikazeVector,shipheading,target->posinfo.position); ship->kamikazeState = K_TurnAround; } */ break; case K_TurnAround: bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast); aishipFlyToPointAvoidingObjs(ship,&ship->kamikazeVector,AISHIP_PointInDirectionFlying | AISHIP_FirstPointInDirectionFlying | AISHIP_FastAsPossible,0.0f); if(MoveReachedDestinationVariable(ship,&ship->kamikazeVector,300.0f)) ship->kamikazeState = K_TurnAround2; break; case K_TurnAround2: bitClear(ship->specialFlags,SPECIAL_KamikazeCrazyFast); if(aitrackHeadingWithFlags(ship,&heading,0.90f,AITRACKHEADING_IGNOREUPVEC)) ship->kamikazeState = K_Ram; break; case K_Yell: // speechEvent(ship, COMM_LInt_Kamikaze, 0); battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_Kamikaze, ship, SOUND_EVENT_DEFAULT); ship->kamikazeState = K_Ram2; break; } //fire guns here... // // //Sound note: Could put in kamikaze state change here after // getting to within a certain distance of target // // ask bryce how to... }
void defensefightertargetbullet(Ship *ship, Bullet *bullettotarget) { DefenseFighterSpec *spec = (DefenseFighterSpec *)ship->ShipSpecifics; DefenseFighterStatics *defensefighterstatics; DefenseStruct *newdefensestruct; Bullet *laser; GunStatic *gunstatic; Gun *gun; ShipStaticInfo *shipstatic; vector positionInWorldCoordSys,tempvec; real32 floatDamage; udword intDamage; udword intVelocity; udword intLength; etgeffectstatic *stat; etglod *etgLOD; sdword LOD; Effect *newEffect; #ifdef HW_BUILD_FOR_DEBUGGING /* dbgMessagef("B: %d %x %x %f %f %f %x %f %x",universe.univUpdateCounter, bullettotarget->flags, bullettotarget->owner, bullettotarget->timelived, bullettotarget->damage, bullettotarget->damageFull, bullettotarget->SpecialEffectFlag, bullettotarget->BulletSpeed, bullettotarget); */ #endif gun = &ship->gunInfo->guns[0]; gunstatic = gun->gunstatic; shipstatic = (ShipStaticInfo *)ship->staticinfo; defensefighterstatics = (DefenseFighterStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; bitSet(bullettotarget->SpecialEffectFlag, 0x0002); //set the flag laser = memAlloc(sizeof(Bullet),"Bullet",0); memset(laser,0,sizeof(Bullet)); // for safety laser->objtype = OBJ_BulletType; laser->flags = 0; laser->staticinfo = NULL; ClearNode(laser->renderlink); laser->currentLOD = ship->currentLOD; laser->cameraDistanceSquared = ship->cameraDistanceSquared; laser->soundType = gunstatic->gunsoundtype; laser->bulletType = BULLET_Laser; laser->owner = ship; laser->gunowner = gun; laser->target = NULL; laser->bulletColor = etgBulletColor[shipstatic->shiprace][laser->soundType]; laser->bulletmass = 0.0f; //gunstatic->bulletmass; laser->lengthmag = 600.0f; laser->damage = frandombetween(defensefighterstatics->DamageReductionLow, defensefighterstatics->DamageReductionHigh); laser->timelived = 0.0f; laser->totallifetime = 100.0f; //laser will only live for a sec anyways... laser->SpecialEffectFlag = 0; laser->traveldist = gunstatic->bulletlength; laser->beamtraveldist = gunstatic->bulletlength; //SET_MOVING_LINEARLY(laser->posinfo.isMoving); //laser->posinfo.haventCalculatedDist = TRUE; laser->DFGFieldEntryTime = 0.0f; matMultiplyMatByVec(&positionInWorldCoordSys,&ship->rotinfo.coordsys,&gunstatic->position); vecAdd(laser->posinfo.position,positionInWorldCoordSys,ship->posinfo.position); vecSub(laser->lengthvec, bullettotarget->posinfo.position, laser->posinfo.position); // heading tempvec = laser->lengthvec; vecNormalize(&tempvec); //matMultiplyMatByVec(&gunheadingInWorldCoordSys, &ship->rotinfo.coordsys, &tempvec); //laser->bulletheading = gunheadingInWorldCoordSys; laser->bulletheading = tempvec; matCreateCoordSysFromHeading(&laser->rotinfo.coordsys,&tempvec); vecZeroVector(laser->posinfo.velocity); //Laser effect... floatDamage = (real32)laser->damage; intDamage = TreatAsUdword(floatDamage); intVelocity = TreatAsUdword(gunstatic->bulletspeed); intLength = TreatAsUdword(gunstatic->bulletlength); //create an effect for bullet, if applicable etgLOD = etgGunEventTable[shipstatic->shiprace][gunstatic->gunsoundtype][EGT_GunBullet];//get pointer to bullet effect //etgLOD = etgGunEventTable[0][gunstatic->gunsoundtype][EGT_GunBullet];//get pointer to bullet effect //in future change back to proper one above... if (etgLOD != NULL) { if (bullettotarget != NULL) { LOD = min(ship->currentLOD, bullettotarget->currentLOD); } else { LOD = ship->currentLOD; } if (LOD >= etgLOD->nLevels) { stat = NULL; } else { stat = etgLOD->level[LOD]; } } else { stat = NULL; } #if ETG_DISABLEABLE if (stat != NULL && etgBulletEffectsEnabled && etgEffectsEnabled && !etgFrequencyExceeded(stat)) #else if (stat != NULL && etgBulletEffectsEnabled && !etgFrequencyExceeded(stat)) #endif { laser->effect = etgEffectCreate(stat, laser, NULL, NULL, NULL, 1.0f, EAF_AllButNLips, 3, intDamage, intVelocity, intLength); // univAddObjToRenderListIf((SpaceObj *)laser->effect,(SpaceObj *)ship); // add to render list if parent ship is in render list //do length calculations :) ((real32 *)laser->effect->variable)[ETG_LengthVariable] = fsqrt(vecMagnitudeSquared(laser->lengthvec)); } else { laser->effect = NULL; //play no effect for this bullet } // laser->effect = NULL; //need for render...add later? laser->hitEffect = etgGunEventTable[shipstatic->shiprace][bullettotarget->gunowner->gunstatic->gunsoundtype][EGT_BulletDestroyed];//get pointer to bullet effect if (ship->soundevent.burstHandle < 0) { soundEventBurstFire(ship, gun); } etgLOD = etgGunEventTable[shipstatic->shiprace][gunstatic->gunsoundtype][EGT_GunFire];//get pointer to bullet effect 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 && etgFireEffectsEnabled && !etgFrequencyExceeded(stat)) #else if (stat != NULL && etgFireEffectsEnabled && !etgFrequencyExceeded(stat)) #endif { //if there is a gun fire effect newEffect = etgEffectCreate(stat, laser, NULL, NULL, NULL, 1.0f, EAF_AllButNLips, 1, intDamage); // univAddObjToRenderListIf((SpaceObj *)newEffect,(SpaceObj *)ship); // add to render list if parent ship is in render list } /* //spawn bullet hitting effect etgLOD = etgTractorBeamEffectTable[ship->shiprace]; //etgLOD = etgGunEventTable[shipstatic->shiprace][gunstatic->gunsoundtype][EGT_GunFire];//get pointer to bullet effect 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) #else if (stat != NULL) #endif { //if there is a gun fire effect // size = etgEffectSize(stat->nParticleBlocks);//compute size of effect size = stat->effectSize; newEffect = memAlloc(size, "DefenseFHittingEffect", 0); //allocate the new effect newEffect->objtype = OBJ_EffectType; newEffect->flags = SOF_Rotatable | SOF_AttachVelocity | SOF_AttachPosition | SOF_AttachCoordsys; newEffect->staticinfo = (StaticInfo *)stat; ClearNode(newEffect->renderlink); newEffect->currentLOD = LOD; newEffect->cameraDistanceSquared = ship->cameraDistanceSquared; newEffect->timeElapsed = 0.0f; //brand new heavies floatDamage = 30.0f; intDamage = TreatAsUdword(floatDamage); newEffect->rotinfo.coordsys = bullettotarget->rotinfo.coordsys; newEffect->posinfo.position = bullettotarget->posinfo.position; //start at same spot as bullet newEffect->posinfo.velocity = bullettotarget->posinfo.velocity; //start at same spot as bullet etgEffectCodeStart(stat, newEffect, 1, intDamage);//get the code a-runnin' SET_MOVING_IMMOBILE(newEffect->posinfo.isMoving); newEffect->posinfo.haventCalculatedDist = TRUE; univUpdateObjRotInfo((SpaceObjRot *)newEffect); // newEffect->owner = NULL; // nothing owns this effect newEffect->owner = (Ship *) bullettotarget; listAddNode(&universe.SpaceObjList,&(newEffect->objlink),newEffect); univAddObjToRenderListIf((SpaceObj *)newEffect,(SpaceObj *)ship); // add to render list if parent ship is in render list } */ //Not sure If I need to add... listAddNode(&universe.SpaceObjList,&(laser->objlink),laser); listAddNode(&universe.BulletList,&(laser->bulletlink),laser); univAddObjToRenderListIf((SpaceObj *)laser,(SpaceObj *)ship); // add to render list if parent ship is in render list newdefensestruct = memAlloc(sizeof(DefenseStruct),"DS(DefenseStruct)",Pyrophoric); newdefensestruct->bullet = bullettotarget; newdefensestruct->CoolDown = FALSE; newdefensestruct->CoolDownTime = 0.0f; newdefensestruct->LaserDead = FALSE; listAddNode(&spec->DefenseList,&newdefensestruct->bulletnode,newdefensestruct); newdefensestruct->laser = laser; if(bitTest(ship->flags,SOF_CloakGenField)) { bitSet(ship->flags,SOF_DeCloaking); bitClear(ship->flags,SOF_Cloaked); bitClear(ship->flags,SOF_Cloaking); } }
void defenseFighterAdjustLaser(Bullet *laser) { //calculates laser direction n' such for rendering... DefenseFighterSpec *spec; // DefenseFighterStatics *defensefighterstatics; Node *bulletnode; DefenseStruct *defensestruct; Ship *ship; vector tempvec; GunStatic *gunstatic; Gun *gun; vector positionInWorldCoordSys; if(laser->owner == NULL) return; ship = laser->owner; gun = &ship->gunInfo->guns[0]; gunstatic = gun->gunstatic; spec= (DefenseFighterSpec *)ship->ShipSpecifics; // defensefighterstatics = (DefenseFighterStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; bulletnode = spec->DefenseList.head; while (bulletnode != NULL) { //as long as theres a bullet to deal with defensestruct = (DefenseStruct *)listGetStructOfNode(bulletnode); if(defensestruct->LaserDead == TRUE) { bulletnode = bulletnode->next; continue; } if(laser == defensestruct->laser) { dbgAssertOrIgnore(defensestruct->bullet != NULL); matMultiplyMatByVec(&positionInWorldCoordSys,&ship->rotinfo.coordsys,&gunstatic->position); vecAdd(laser->posinfo.position,positionInWorldCoordSys,ship->posinfo.position); vecSub(laser->lengthvec, defensestruct->bullet->posinfo.position, laser->posinfo.position); // heading tempvec = defensestruct->laser->lengthvec; vecNormalize(&tempvec); //matMultiplyMatByVec(&gunheadingInWorldCoordSys, &ship->rotinfo.coordsys, &tempvec); //laser->bulletheading = gunheadingInWorldCoordSys; defensestruct->laser->bulletheading = tempvec; matCreateCoordSysFromHeading(&defensestruct->laser->rotinfo.coordsys,&tempvec); if(defensestruct->laser->effect != NULL) { //adjust length ((real32 *)defensestruct->laser->effect->variable)[ETG_LengthVariable] = fsqrt(vecMagnitudeSquared(defensestruct->laser->lengthvec)); } return; } bulletnode = bulletnode->next; } //we shouldn't get to this point :) //dbgMessagef("Laser Drawn doesn't exist in defense fighter records."); //on further reflection..if we kill the laster...but it doesn't go bye bye, we might get here... }
void DefenseFighterHouseKeep(Ship *ship) { DefenseFighterSpec *spec = (DefenseFighterSpec *)ship->ShipSpecifics; DefenseFighterStatics *defensefighterstatics; Node *bulletnode; Node *tempnode; DefenseStruct *defensestruct; vector seperationvector; vector tempvec,rot_vector; GunStatic *gunstatic; Gun *gun; vector positionInWorldCoordSys; gun = &ship->gunInfo->guns[0]; gunstatic = gun->gunstatic; defensefighterstatics = (DefenseFighterStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; bulletnode = spec->DefenseList.head; while (bulletnode != NULL) { //as long as theres a bullet to deal with defensestruct = (DefenseStruct *)listGetStructOfNode(bulletnode); /* if (defensestruct->bullet) dbgMessagef("DS: %d %f %d %f %d %d", universe.univUpdateCounter, defensestruct->bullet->collOptimizeDist, defensestruct->laser ? 1:0, defensestruct->CoolDownTime, defensestruct->CoolDown ? 1:0, defensestruct->LaserDead ? 1:0); else dbgMessagef("DS: %d N %d %f %d %d", universe.univUpdateCounter, defensestruct->laser ? 1:0, defensestruct->CoolDownTime, defensestruct->CoolDown ? 1:0, defensestruct->LaserDead ? 1:0);*/ if(!defensestruct->CoolDown) { //laser cannon isn't cooling down, so continue tracking if (defensestruct->bullet == NULL || defensestruct->bullet->damage <= 0) { //bullet is already dead...don't kill it again defensestruct->bullet = NULL; //destroy pointer... if (defensestruct->laser != NULL) { defensestruct->laser->timelived =10000.0f; //kill laser } defensestruct->LaserDead = TRUE; //set killed flag defensestruct->laser=NULL; defensestruct->CoolDown = TRUE; //begin laser cooldown defensestruct->CoolDownTime = 0.0f; //reset to 0 for cooldown count bulletnode=bulletnode->next; continue; } if((universe.univUpdateCounter & defensefighterstatics->DamageRate) == 0) { // Time to do damage... //Do damage to bullet defensestruct->bullet->damage = (defensestruct->bullet->damage - frandombetween(defensefighterstatics->DamageReductionLow,defensefighterstatics->DamageReductionHigh)); if(defensestruct->bullet->damage <= 0) { //bullet is destroyed DefenseFighterDestroyedABullet(ship, defensestruct->bullet, defensestruct->laser); defensestruct->bullet->damage = 0; //cap at 0; defensestruct->bullet = NULL; //destroy pointer... //dbgMessagef("Defense Fighter Destroyed A Bullet."); if (defensestruct->laser != NULL) { defensestruct->laser->timelived =10000.0f; //kill laser } defensestruct->LaserDead = TRUE; //set killed flag if(defensestruct->laser->effect != NULL) { univRemoveObjFromRenderList((SpaceObj *) defensestruct->laser->effect); } defensestruct->laser=NULL; defensestruct->CoolDown = TRUE; //begin laser cooldown defensestruct->CoolDownTime = 0.0f; //reset to 0 for cooldown count } } if(defensestruct->laser != NULL) { //check if bullet is still in range and infront... if((universe.univUpdateCounter & defensefighterstatics->RangeCheckRate) == 0) { //time to check if in front vecSub(seperationvector, ship->posinfo.position, defensestruct->bullet->posinfo.position); if(vecMagnitudeSquared(seperationvector) > ship->staticinfo->bulletRangeSquared[ship->tacticstype]) { //bullet is out of range defensestruct->laser->timelived =10000.0f; //kill laser defensestruct->LaserDead = TRUE; //set killed flag if(defensestruct->laser->effect != NULL) { univRemoveObjFromRenderList((SpaceObj *) defensestruct->laser->effect); } defensestruct->laser=NULL; //dbgMessagef("Bullet out of range."); bitClear(defensestruct->bullet->SpecialEffectFlag,0x0002); defensestruct->CoolDown = TRUE; //begin laser cooldown defensestruct->bullet = NULL; //set target to NULL so it isn't referenced again! defensestruct->CoolDownTime = 0.0f; //reset to 0 for cooldown count } else if(!defensefighterCheckInFront(ship, defensestruct->bullet)) { //if bullet ISN'T in front defensestruct->laser->timelived =10000.0f; //kill laser defensestruct->LaserDead = TRUE; //set killed flag if(defensestruct->laser->effect != NULL) { univRemoveObjFromRenderList((SpaceObj *) defensestruct->laser->effect); } defensestruct->laser=NULL; //dbgMessagef("Bullet Not infront anymore...stop tracking."); if(defensefighterstatics->MultipleTargettingofSingleBullet) { bitClear(defensestruct->bullet->SpecialEffectFlag,0x0002); } defensestruct->CoolDown = TRUE; //begin laser cooldown defensestruct->bullet = NULL; //set target to NULL so it isn't referenced again! defensestruct->CoolDownTime = 0.0f; //reset to 0 for cooldown count } } } //This code is for the sake of the visual effect which STILL won't work //properly!!! So it is temperary only! if(defensestruct->laser != NULL) { //update bullent info...for visual effect dbgAssertOrIgnore(defensestruct->bullet != NULL); matMultiplyMatByVec(&positionInWorldCoordSys,&ship->rotinfo.coordsys,&gunstatic->position); vecAdd(defensestruct->laser->posinfo.position,positionInWorldCoordSys,ship->posinfo.position); vecSub(defensestruct->laser->lengthvec, defensestruct->bullet->posinfo.position, defensestruct->laser->posinfo.position); // heading tempvec = defensestruct->laser->lengthvec; vecNormalize(&tempvec); //matMultiplyMatByVec(&gunheadingInWorldCoordSys, &ship->rotinfo.coordsys, &tempvec); //laser->bulletheading = gunheadingInWorldCoordSys; defensestruct->laser->bulletheading = tempvec; matCreateCoordSysFromHeading(&defensestruct->laser->rotinfo.coordsys,&tempvec); if(defensestruct->laser->effect != NULL) { //adjust length ((real32 *)defensestruct->laser->effect->variable)[ETG_LengthVariable] = fsqrt(vecMagnitudeSquared(defensestruct->laser->lengthvec)); } } } else { //this laser cannon is cooling, so cool it defensestruct->CoolDownTime += universe.phystimeelapsed; if(defensestruct->CoolDownTime > defensefighterstatics->CoolDownTimePerLaser) { //Laser Terminal has cooled down...so free it up tempnode = bulletnode->next; listDeleteNode(bulletnode); //dbgMessagef("Deleting defense node in CoolDown."); bulletnode = tempnode; continue; } } bulletnode = bulletnode->next; } if (spec->DefenseList.num == 0) { soundEventBurstStop(ship, gun); } //do special rotation if neccessary if(bitTest(ship->dontrotateever,1)) { //matGetVectFromMatrixCol3(rot_vector,ship->rotinfo.coordsys); vecSet(rot_vector,100.0f,0.0f,0.0f); vecAddTo(ship->rotinfo.torque, rot_vector); vecCapVectorSloppy(&ship->rotinfo.rotspeed, defensefighterstatics->max_rot_speed ); spec->rotate_time_counter -= universe.phystimeelapsed; if(spec->rotate_time_counter <= 0.0f) { bitClear(ship->dontrotateever,1); spec->DefenseFighterCanNowRotate = FALSE; } } else if (spec->DefenseFighterCanNowRotate == FALSE) { spec->rotate_time_counter += universe.phystimeelapsed; if(spec->rotate_time_counter >= defensefighterstatics->rotate_recover_time) { spec->DefenseFighterCanNowRotate = TRUE; spec->rotate_time_counter = defensefighterstatics->rotate_time; } } }
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 CloakGeneratorHouseKeep(Ship *ship) { CloakGeneratorSpec *spec = (CloakGeneratorSpec *)ship->ShipSpecifics; CloakGeneratorStatics *cloakgeneratorstatics; Node *cloaknode, *temp; SpaceObj *spaceobj; CloakStruct *cloakstruct; vector diff; real32 distanceSqr; cloakgeneratorstatics = (CloakGeneratorStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; if(spec->CloakOn == TRUE) //Cloaking Generator is On { //15th frame..so do a search on other ships within 'proximity' if ((universe.univUpdateCounter & CLOAKGENERATOR_CLOAKCHECK_RATE) == (ship->shipID.shipNumber & CLOAKGENERATOR_CLOAKCHECK_RATE)) { CloakAddObjectsInProximity(ship); //this opp is slow! So maybe decrease frequency } //decrement functionality time spec->CloakStatus -= universe.phystimeelapsed; if ((spec->CloakStatus <= 10.0f) && !spec->CloakLowWarning) { spec->CloakLowWarning = TRUE; // speechEvent(ship, STAT_Cloak_CloakPowerLow, (sdword)spec->CloakStatus); if (battleCanChatterAtThisTime(BCE_CloakingPowerLow, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_CloakingPowerLow, ship, (sdword)spec->CloakStatus); } } //Cloak Field has been on too long if(spec->CloakStatus <= 0.0f) { DeCloakAllObjects(ship); //decloak everything spec->CloakOn = FALSE; //reset flags spec->CloakStatus = 0.0f; //reset CloakStatus spec->CloakLowWarning = FALSE; //reset flag // soundEvent(ship, PowerOff); // speechEvent(ship, COMM_Cloak_Decloak, 0); if (battleCanChatterAtThisTime(BCE_Decloaking, ship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_Decloaking, ship, SOUND_EVENT_DEFAULT); } } } else //cloak field is off { //recharge cloaking juice at tunable rate spec->CloakStatus += universe.phystimeelapsed*cloakgeneratorstatics->ReChargeRate; if(spec->CloakStatus >= cloakgeneratorstatics->MaxCloakingTime) { spec->CloakStatus = cloakgeneratorstatics->MaxCloakingTime; //cap max cloaking juice } } //perform maintainence on cloaked ships (cloaking,decloaking and continual cloak) cloaknode = spec->CloakList.head; while(cloaknode != NULL) { cloakstruct = (CloakStruct *)listGetStructOfNode(cloaknode); spaceobj = cloakstruct->spaceobj; // wierd crash ... if (spaceobj==NULL) { temp = cloaknode; cloaknode = cloaknode->next; listDeleteNode(temp); continue; } //if spaceobj is dead for some reason, remove its references and stop bothering with it if (bitTest(spaceobj->flags,SOF_Dead)) { //dead so get rid of quickly... cloaknode=cloaknode->next; //we're about to delete this node so move to next CloakGeneratorRemoveShipReferences(ship,(Ship *)spaceobj); //delete everything about it continue; } //perform a change check! //this seems like a waste because we are AGAIN calculating distances. Do better later! if ((universe.univUpdateCounter & CLOAKGENERATOR_CLOAKCHECK_RATE) == (ship->shipID.shipNumber & CLOAKGENERATOR_CLOAKCHECK_RATE)) { vecSub(diff,spaceobj->posinfo.position,ship->posinfo.position); distanceSqr = vecMagnitudeSquared(diff); if(distanceSqr > cloakgeneratorstatics->CloakingRadiusSqr) //maybe add fuzzy logic so thing doesn't always pop in and out in and out in and out... { if(bitTest(spaceobj->flags,SOF_Cloaked)) { bitClear(spaceobj->flags,SOF_Cloaked); if(spaceobj->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (spaceobj))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(spaceobj->flags,SOF_Cloaking); bitSet(spaceobj->flags,SOF_DeCloaking); } //potential problem..ship flys into field..flys out.. //starts to decloak...flys back in, ship will decloak //fully before recloaking...don't worry about since //cloak times too fast too care } if(spaceobj->objtype == OBJ_ShipType) { if( ((Ship *)spaceobj)->shiptype == SalCapCorvette) { if(((SalCapCorvetteSpec *)((Ship *)spaceobj)->ShipSpecifics)->tractorBeam) { //attached so decloak if(bitTest(spaceobj->flags,SOF_Cloaked)) { bitClear(spaceobj->flags,SOF_Cloaked); if(spaceobj->objtype == OBJ_ShipType) { //if object was a ship set objects decloaking time for cloak advagtage effect SpawnCloakingEffect((Ship *)spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_OFF]); ((Ship *) (spaceobj))->shipDeCloakTime = universe.totaltimeelapsed; } } bitClear(spaceobj->flags,SOF_Cloaking); bitSet(spaceobj->flags,SOF_DeCloaking); } } } //Case 1, object is cloaking if(bitTest(spaceobj->flags,SOF_Cloaking)) { //object is cloaking..so keep cloaking it /***** calculated the inverse of CloakingTime in CloakGeneratorStaticInit and multiply instead of divide *****/ cloakstruct->CloakStatus += universe.phystimeelapsed*cloakgeneratorstatics->CloakingTime; if(cloakstruct->CloakStatus >= 1.0f) { //object is now cloaked...so stop cloaking it and make it fully 'cloaked' cloakstruct->CloakStatus = 1.0f; //set for assurance bitSet(spaceobj->flags,SOF_Cloaked); //make cloaked bitClear(spaceobj->flags,SOF_Cloaking); //stop from cloaking if(spaceobj->objtype == OBJ_ShipType) { shipHasJustCloaked((Ship *)spaceobj); SpawnCloakingEffect((Ship *)spaceobj, etgSpecialPurposeEffectTable[EGT_CLOAK_ON]); //RemoveShipFromBeingTargeted(&universe.mainCommandLayer,(Ship *)spaceobj,FALSE); } else if(spaceobj->objtype == OBJ_AsteroidType) { //need to remove the asteroid from resource collectors dbgMessagef("\nMake Bryce remove asteroids from game info since you just cloaked one."); } } } else if(bitTest(spaceobj->flags,SOF_DeCloaking)) { //object is decloaking, so keep decloaking it /***** calculated the inverse of DeCloakingTime in CloakGeneratorStaticInit and multiply instead of divide *****/ cloakstruct->CloakStatus -= universe.phystimeelapsed*cloakgeneratorstatics->DeCloakingTime; if(cloakstruct->CloakStatus <= 0.0f) { //Object is now fully decloaked so stop decloaking it and remove it from the list cloaknode=cloaknode->next; //we're about to delete this node so move to next CloakGeneratorRemoveShipReferences(ship,(Ship *)spaceobj); //delete everything about it continue; //we now continue the loop rather than letting the other code continue :) } } cloaknode = cloaknode->next; } }
void MineLayerAttackRun(Ship *ship,SpaceObjRotImpTarg *target,AttackSideStep *attacksidestep,AttackSideStepParameters *parameters) { vector trajectory; //real32 dist; real32 range; //real32 temp; // bool didshoot; ShipStaticInfo *shipstaticinfo = (ShipStaticInfo *)ship->staticinfo; Gun *gun; udword numGuns,target_class; GunInfo *guninfo = ship->gunInfo; //vector tmpvec; //real32 randegf; //sdword randeg; //matrix tmpmat; //vector targetheading; MinelayerCorvetteSpec *spec = (MinelayerCorvetteSpec *)ship->ShipSpecifics; MinelayerCorvetteStatics *minelayercorvettestatics; minelayercorvettestatics = (MinelayerCorvetteStatics *) ((ShipStaticInfo *)(ship->staticinfo))->custstatinfo; numGuns = guninfo->numGuns; gun = &guninfo->guns[0]; if(target != NULL) { if(target->objtype == OBJ_ShipType) target_class = ((Ship *)target)->staticinfo->shipclass; else target_class = CLASS_NonCombat; } switch (ship->aistateattack) { case ATTACK_INIT: case APPROACH: #ifdef DEBUG_ATTACK dbgMessagef("\nShip %x MINELAYER_ATTACK_APPROACH",(udword)ship); #endif aishipGetTrajectory(ship,target,&trajectory); aishipFlyToShipAvoidingObjs(ship,target,AISHIP_PointInDirectionFlying,0.0f); range = RangeToTarget(ship,target,&trajectory); //lets check if we want to force drop... if(target->objtype == OBJ_ShipType) { if(((Ship *)target)->shiptype == Mothership) { //its a mothership vector tempvec; real32 tempreal; vecSub(tempvec,target->collInfo.collPosition,ship->collInfo.collPosition); tempreal = vecMagnitudeSquared(tempvec); if(tempreal < mothershipDistSqr) { //we're within range of force dropping! ship->aistateattack = DROP_MOTHERSHIP; } break; } } if (range < minelayercorvettestatics->breakInAwayDist) { ship->aistateattack = BREAKPOSITION; spec->aivec.x = 0.0f; spec->aivec.y = 0.0f; spec->aivec.z = 0.0f; } break; case DROP_MOTHERSHIP: { vector tempvec; real32 tempreal; vecSub(tempvec,ship->collInfo.collPosition,target->collInfo.collPosition); tempreal = vecMagnitudeSquared(tempvec); vecNormalize(&tempvec); if(tempreal > mothershipDistSqr2) { ship->aistateattack = ATTACK_INIT; } if(aitrackHeadingWithFlags(ship,&tempvec,0.97f,AITRACKHEADING_IGNOREUPVEC)) { if(MinelayerCorvetteStaticMineDrop(ship,target)) //problem...there will be other targets...bah..lets see.. { MinelayerCorvetteOrderChangedCleanUp(ship); } } break; } case BREAKPOSITION: #ifdef DEBUG_ATTACK dbgMessagef("\nShip %x BREAKPOSITION",(udword)ship); #endif aishipGetTrajectory(ship,target,&trajectory); range = RangeToTarget(ship,target,&trajectory); vecNormalize(&trajectory); SetAIVecHeading(ship,target,&trajectory); ship->aistateattack = BREAK1; case BREAK1: #ifdef DEBUG_ATTACK dbgMessagef("\nShip %x BREAK1",(udword)ship); #endif aishipGetTrajectory(ship,target,&trajectory); range = RangeToTarget(ship,target,&trajectory); //aishipFlyToPointAvoidingObjs(ship,&spec->aivec,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY); aishipFlyToPointAvoidingObjs(ship,&target->posinfo.position,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY); if(range < minelayercorvettestatics->DropRange) { //temp vecNormalize(&trajectory); SetAIVecHeading(ship,target,&trajectory); //temp ship->aistateattack = KILL; //within mining range so start dropping spec->aispheretime=0.0f; //reset time; } break; case KILL: #ifdef DEBUG_ATTACK dbgMessagef("\nShip %x KILL",(udword)ship); #endif aishipGetTrajectory(ship,target,&trajectory); range = RangeToTarget(ship,target,&trajectory); spec->aispheretime += universe.phystimeelapsed; if(gunCanShoot(ship, gun)) { if(gun->numMissiles > 0) { spec->mineaistate = MINE_DROP_ATTACK; MinelayerCorvetteFire(ship,target); } } if(range > minelayercorvettestatics->DropStopRange) { //out of range.... ship->aistateattack = BREAK2; } if(spec->aispheretime > minelayercorvettestatics->Break2SphereizeFreq) { //time to sphereize; spec->aivec.x =0.0f; spec->aivec.y =0.0f; spec->aivec.z =0.0f; spec->aispheretime = -1000000.0f; // Reset, and never do again till next attack pass... vecNormalize(&trajectory); SetAIVecHeading(ship,target,&trajectory); #ifdef DEBUG_ATTACK dbgMessagef("\nShip %x KILL: Adjust for Break2 Sphereizing Godliness Maneuver :)",(udword)ship); #endif } aishipFlyToPointAvoidingObjs(ship,&spec->aivec,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY); break; case BREAK2: #ifdef DEBUG_ATTACK dbgMessagef("\nShip %x BREAK2",(udword)ship); #endif aishipGetTrajectory(ship,target,&trajectory); range = RangeToTarget(ship,target,&trajectory); aishipFlyToPointAvoidingObjs(ship,&spec->aivec,AISHIP_FastAsPossible | AISHIP_PointInDirectionFlying,INTERCEPTORBREAK_MINVELOCITY); if(range > minelayercorvettestatics->FlyAwayDist[target_class] || (MoveReachedDestinationVariable(ship,&spec->aivec,minelayercorvettestatics->FlyAwayTolerance))) { //turn around and start over ship->aistateattack = APPROACH; } break; default: dbgAssert(FALSE); break; } }
void univUpdateMineWallFormations() { Node *node,*minenode,*tempnode; //Missile *mine, *mineend = NULL, *minestart, *mineendtemp; MineFormationInfo *mineformationinfo; Missile *minestart; vector tempvec; node = universe.MineFormationList.head; while(node != NULL) { mineformationinfo = (MineFormationInfo *) listGetStructOfNode(node); if(mineformationinfo->MineList.num == 9) //use another number other than 0 later..maybe 8? Tunable { //no more mines in formation so destroy this here formation //destroy any effects that are still going //here re-task mines (make not Force Dropped...) if(mineformationinfo->FULL) { //no more mines are going to be added... minenode = mineformationinfo->MineList.head; //set formationinfo to NULL while(minenode != NULL) { minestart = (Missile *) listGetStructOfNode(minenode); minestart->formationinfo = NULL; minenode = minenode->next; } listRemoveAll(&mineformationinfo->MineList); //removes all mine links tempnode = node->next; listDeleteNode(node); //destroys mineformation node = tempnode; continue; } } else { //mines exist in formation if(mineformationinfo->FULL) { minenode = mineformationinfo->MineList.head; while(minenode != NULL) { minestart = (Missile *) listGetStructOfNode(minenode); vecSub(tempvec, minestart->posinfo.position, minestart->formation_position); if(vecMagnitudeSquared(tempvec) > MINE_GONE_TOO_FAR_SQR) { tempnode = minenode->next; minestart->formationinfo = NULL; listRemoveNode(&minestart->formationLink); minenode = tempnode; continue; } minenode = minenode->next; } } } ret: node = node->next; } }
/*----------------------------------------------------------------------------- Name : pingListDraw Description : Draw all pings from farthest to nearest. Inputs : camera - the camera we're rendering from modelView, projection - current matrices viewPort - rectangle we're rending in, for the TO legend Outputs : Return : Note : The renderer should be in 2D mode at this point. ----------------------------------------------------------------------------*/ void pingListDraw(Camera *camera, hmatrix *modelView, hmatrix *projection, rectangle *viewPort) { real32 pingAge, pingCycle, pingMod, pingSize; real32 x, y, radius; Node *thisNode, *nextNode; ping *thisPing; vector distSquared; sdword nSegments, index, rowHeight, xScreen, yScreen; oval o; udword TOFlags = 0; fonthandle fhSave; toicon *icon; color col; real32 realMargin; ShipClass shipClass; static real32 lastProximityPing = REALlyBig; static real32 lastAnomolyPing = REALlyBig; static real32 lastBattlePing = REALlyBig; static real32 lastHyperspacePing = REALlyBig; static real32 lastNewshipPing = REALlyBig; bool pingset; //start by sorting the ping list from farthest to nearest thisNode = pingList.head; while (thisNode != NULL) { //scan all pings nextNode = thisNode->next; thisPing = listGetStructOfNode(thisNode); if (thisPing->owner != NULL) { thisPing->centre = thisPing->owner->posinfo.position; } vecSub(distSquared, camera->eyeposition, thisPing->centre); thisPing->cameraDistanceSquared = vecMagnitudeSquared(distSquared); TOFlags |= thisPing->TOMask; thisNode = nextNode; } listMergeSortGeneral(&pingList, pingListSortCallback); //now the list is sorted; proceed to draw all the pings thisNode = pingList.head; pingset = FALSE; while (thisNode != NULL) { //scan all pings nextNode = thisNode->next; thisPing = listGetStructOfNode(thisNode); pingCycle = thisPing->pingDuration + thisPing->interPingPause; pingAge = universe.totaltimeelapsed - thisPing->creationTime; pingMod = (real32)fmod((double)pingAge, (double)pingCycle); if (pingMod <= thisPing->pingDuration) { pingSize = (thisPing->size - thisPing->minSize) * pingMod / thisPing->pingDuration + thisPing->minSize; selCircleComputeGeneral(modelView, projection, &thisPing->centre, max(thisPing->size,thisPing->minSize), &x, &y, &radius); if (radius > 0.0f) { radius = max(radius, thisPing->minScreenSize); radius *= pingSize / max(thisPing->size,thisPing->minSize); o.centreX = primGLToScreenX(x); o.centreY = primGLToScreenY(y); o.radiusX = o.radiusY = primGLToScreenScaleX(radius); nSegments = pieCircleSegmentsCompute(radius); primOvalArcOutline2(&o, 0.0f, 2*PI, 1, nSegments, thisPing->c); /* starting to draw a new ping so play the sound */ if (!smZoomingIn && !smZoomingOut && !pingset) { switch (thisPing->TOMask) { case PTOM_Anomaly: if (pingSize <=lastAnomolyPing) { soundEvent(NULL, UI_SensorsPing); pingset = TRUE; lastAnomolyPing = pingSize; } break; case PTOM_Battle: if (pingSize <= lastBattlePing) { soundEvent(NULL, UI_PingBattle); pingset = TRUE; lastBattlePing = pingSize; } break; case PTOM_Hyperspace: if (pingSize <= lastHyperspacePing) { soundEvent(NULL, UI_PingHyperspace); pingset = TRUE; lastHyperspacePing = pingSize; } break; case PTOM_Proximity: if (pingSize <= lastProximityPing) { soundEvent(NULL, UI_PingProximity); pingset = TRUE; lastProximityPing = pingSize; } break; case PTOM_NewShips: if (pingSize <= lastNewshipPing) { soundEvent(NULL, UI_PingNewShips); pingset = TRUE; lastNewshipPing = pingSize; } break; default: break; } } } } thisNode = nextNode; } //draw the blip TO if (smTacticalOverlay) { realMargin = primScreenToGLScaleX(viewPort->x0); fhSave = fontCurrentGet(); //save the current font fontMakeCurrent(selGroupFont2); // use a common, fairly small font rowHeight = fontHeight("M"); // used to space the legend yScreen = viewPort->y0 + rowHeight; //leave some space at the top to start radius = primScreenToGLScaleX(rowHeight)/2; xScreen = viewPort->x0 + (sdword)(rowHeight * 2.5); for (index = 0; index < PTO_NumberTOs; index++) { if ((TOFlags & pingTOList[index].bitMask)) { // fontPrint(xScreen, yScreen, *pingTOList[index].c, "O"); pingTOList[index].lastTimeDrawn = universe.totaltimeelapsed; } if (universe.totaltimeelapsed - pingTOList[index].lastTimeDrawn <= pingTOLingerTime) { o.centreX = viewPort->x0 + rowHeight * 3 / 2; o.centreY = yScreen + rowHeight / 2; o.radiusX = o.radiusY = rowHeight / 2; primOvalArcOutline2(&o, 0.0f, TWOPI, 1, pingTONSegments, *pingTOList[index].c); fontPrint(xScreen, yScreen, TO_TextColor, strGetString(pingTOList[index].stringEnum)); yScreen += rowHeight + 1; } } for (shipClass = 0; shipClass < NUM_CLASSES; shipClass++) { if (!toClassUsed[shipClass][0]) { continue; } icon = toClassIcon[shipClass]; fontPrint(xScreen, yScreen + (rowHeight>>2), TO_TextColor, ShipClassToNiceStr(shipClass)); #if TO_STANDARD_COLORS col = teFriendlyColor; #else col = teColorSchemes[universe.curPlayerIndex].tacticalColor; #endif col = colRGB(colRed(col)/TO_IconColorFade, colGreen(col)/TO_IconColorFade, colBlue(col)/TO_IconColorFade); primLineLoopStart2(1, col); for (index = icon->nPoints - 1; index >= 0; index--) { primLineLoopPoint3F(realMargin + primScreenToGLX(rowHeight*1.5) + icon->loc[index].x * radius, primScreenToGLY(yScreen + rowHeight/2) + icon->loc[index].y * radius); } primLineLoopEnd2(); yScreen += rowHeight + 1; } fontMakeCurrent(fhSave); } }