void StarshipAI::FireControl() { // identify unknown contacts: if (identify) { if (fabs(ship->GetHelmHeading() - ship->CompassHeading()) < 10*DEGREES) { Contact* contact = ship->FindContact(target); if (contact && !contact->ActLock()) { if (!ship->GetProbe()) { ship->LaunchProbe(); } } } return; } // investigate last known location of enemy ship: if (rumor && !target && ship->GetProbeLauncher() && !ship->GetProbe()) { // is rumor in basket? Point rmr = Transform(rumor->Location()); rmr.Normalize(); double dx = fabs(rmr.x); double dy = fabs(rmr.y); if (dx < 10*DEGREES && dy < 10*DEGREES && rmr.z > 0) { ship->LaunchProbe(); } } // Corvettes and Frigates are anti-air platforms. They need to // target missile threats even when the threat is aimed at another // friendly ship. Forward facing weapons must be on auto fire, // while lateral and aft facing weapons are set to point defense. if (ship->Class() == Ship::CORVETTE || ship->Class() == Ship::FRIGATE) { ListIter<WeaponGroup> iter = ship->Weapons(); while (++iter) { WeaponGroup* group = iter.value(); ListIter<Weapon> w_iter = group->GetWeapons(); while (++w_iter) { Weapon* weapon = w_iter.value(); double az = weapon->GetAzimuth(); if (fabs(az) < 45*DEGREES) { weapon->SetFiringOrders(Weapon::AUTO); weapon->SetTarget(target, 0); } else { weapon->SetFiringOrders(Weapon::POINT_DEFENSE); } } } } // All other starships are free to engage ship targets. Weapon // fire control is managed by the type of weapon. else { System* subtgt = SelectSubtarget(); ListIter<WeaponGroup> iter = ship->Weapons(); while (++iter) { WeaponGroup* weapon = iter.value(); if (weapon->GetDesign()->target_type & Ship::DROPSHIPS) { // anti-air weapon? weapon->SetFiringOrders(Weapon::POINT_DEFENSE); } else if (weapon->IsDrone()) { // torpedoes weapon->SetFiringOrders(Weapon::MANUAL); weapon->SetTarget(target, 0); if (target && target->GetRegion() == ship->GetRegion()) { Point delta = target->Location() - ship->Location(); double range = delta.length(); if (range < weapon->GetDesign()->max_range * 0.9 && !AssessTargetPointDefense()) weapon->SetFiringOrders(Weapon::AUTO); else if (range < weapon->GetDesign()->max_range * 0.5) weapon->SetFiringOrders(Weapon::AUTO); } } else { // anti-ship weapon weapon->SetFiringOrders(Weapon::AUTO); weapon->SetTarget(target, subtgt); weapon->SetSweep(subtgt ? Weapon::SWEEP_NONE : Weapon::SWEEP_TIGHT); } } } }
System* StarshipAI::SelectSubtarget() { if (Game::GameTime() - sub_select_time < 2345) return subtarget; subtarget = 0; if (!target || target->Type() != SimObject::SIM_SHIP || GetAILevel() < 1) return subtarget; Ship* tgt_ship = (Ship*) target; if (!tgt_ship->IsStarship()) return subtarget; Weapon* subtgt = 0; double dist = 50e3; Point svec = ship->Location() - tgt_ship->Location(); sub_select_time = Game::GameTime(); // first pass: turrets ListIter<WeaponGroup> g_iter = tgt_ship->Weapons(); while (++g_iter) { WeaponGroup* g = g_iter.value(); if (g->GetDesign() && g->GetDesign()->turret_model) { ListIter<Weapon> w_iter = g->GetWeapons(); while (++w_iter) { Weapon* w = w_iter.value(); if (w->Availability() < 35) continue; if (w->GetAimVector() * svec < 0) continue; if (w->GetTurret()) { Point tloc = w->GetTurret()->Location(); Point delta = tloc - ship->Location(); double dlen = delta.length(); if (dlen < dist) { subtgt = w; dist = dlen; } } } } } // second pass: major weapons if (!subtgt) { g_iter.reset(); while (++g_iter) { WeaponGroup* g = g_iter.value(); if (g->GetDesign() && !g->GetDesign()->turret_model) { ListIter<Weapon> w_iter = g->GetWeapons(); while (++w_iter) { Weapon* w = w_iter.value(); if (w->Availability() < 35) continue; if (w->GetAimVector() * svec < 0) continue; Point tloc = w->MountLocation(); Point delta = tloc - ship->Location(); double dlen = delta.length(); if (dlen < dist) { subtgt = w; dist = dlen; } } } } } subtarget = subtgt; return subtarget; }
void FighterTacticalAI::SelectSecondaryForTarget(Ship* tgt) { if (tgt) { int wix = WINCHESTER_FIGHTER; if (tgt->IsGroundUnit()) wix = WINCHESTER_STRIKE; else if (tgt->IsStatic()) wix = WINCHESTER_STATIC; else if (tgt->IsStarship()) wix = WINCHESTER_ASSAULT; WeaponGroup* best = 0; List<WeaponGroup> weps; if (ListSecondariesForTarget(tgt, weps)) { winchester[wix] = false; // select best weapon for the job: double range = (ship->Location() - tgt->Location()).length(); double best_range = 0; double best_damage = 0; ListIter<WeaponGroup> iter = weps; while (++iter) { WeaponGroup* w = iter.value(); if (!best) { best = w; WeaponDesign* d = best->GetDesign(); best_range = d->max_range; best_damage = d->damage * d->ripple_count; if (best_range < range) best = 0; } else { WeaponDesign* d = w->GetDesign(); double w_range = d->max_range; double w_damage = d->damage * d->ripple_count; if (w_range > range) { if (w_range < best_range || w_damage > best_damage) best = w; } } } // now cycle weapons until you pick the best one: WeaponGroup* current_missile = ship->GetSecondaryGroup(); if (current_missile && best && current_missile != best) { ship->CycleSecondary(); WeaponGroup* m = ship->GetSecondaryGroup(); while (m != current_missile && m != best) { ship->CycleSecondary(); m = ship->GetSecondaryGroup(); } } } else { winchester[wix] = true; // if we have NO weapons that can hit this target, // just drop it: Weapon* primary = ship->GetPrimary(); if (!primary || !primary->CanTarget(tgt->Class())) { ship_ai->DropTarget(3); ship->DropTarget(); } } if (tgt->IsGroundUnit()) ship->SetSensorMode(Sensor::GM); else if (ship->GetSensorMode() == Sensor::GM) ship->SetSensorMode(Sensor::STD); } }