void TacticalAI::SelectTargetOpportunity() { // NON-COMBATANTS do not pick targets of opportunity: if (ship->GetIFF() == 0) return; SimObject* potential_target = 0; // pick the closest combatant ship with a different IFF code: double target_dist = ship->Design()->commit_range; SimObject* ward = ship_ai->GetWard(); // FRIGATES are primarily anti-air platforms, but may // also attack smaller starships: if (ship->Class() == Ship::CORVETTE || ship->Class() == Ship::FRIGATE) { Ship* current_ship_target = 0; Shot* current_shot_target = 0; // if we are escorting a larger warship, it is good to attack // the same target as our ward: if (ward) { Ship* s = (Ship*) ward; if (s->Class() > ship->Class()) { SimObject* obj = s->GetTarget(); if (obj && obj->Type() == SimObject::SIM_SHIP) { current_ship_target = (Ship*) obj; target_dist = (ship->Location() - obj->Location()).length(); } } } ListIter<Contact> contact = ship->ContactList(); while (++contact) { Ship* c_ship = contact->GetShip(); Shot* c_shot = contact->GetShot(); if (!c_ship && !c_shot) continue; int c_iff = contact->GetIFF(ship); bool rogue = c_ship && c_ship->IsRogue(); bool tgt_ok = c_iff > 0 && c_iff != ship->GetIFF() && c_iff < 1000; if (rogue || tgt_ok) { if (c_ship && c_ship != ship && !c_ship->InTransition()) { if (c_ship->Class() < Ship::DESTROYER || (c_ship->Class() >= Ship::MINE && c_ship->Class() <= Ship::DEFSAT)) { // found an enemy, check distance: double dist = (ship->Location() - c_ship->Location()).length(); if (dist < 0.75 * target_dist && (!current_ship_target || c_ship->Class() <= current_ship_target->Class())) { current_ship_target = c_ship; target_dist = dist; } } } else if (c_shot) { // found an enemy shot, is there enough time to engage? if (c_shot->GetEta() < 3) continue; // found an enemy shot, check distance: double dist = (ship->Location() - c_shot->Location()).length(); if (!current_shot_target) { current_shot_target = c_shot; target_dist = dist; } // is this shot a better target than the one we've found? else { Ship* ward = ship_ai->GetWard(); if ((c_shot->IsTracking(ward) || c_shot->IsTracking(ship)) && (!current_shot_target->IsTracking(ward) || !current_shot_target->IsTracking(ship))) { current_shot_target = c_shot; target_dist = dist; } else if (dist < target_dist) { current_shot_target = c_shot; target_dist = dist; } } } } } if (current_shot_target) potential_target = current_shot_target; else potential_target = current_ship_target; } // ALL OTHER SHIP CLASSES ignore fighters and only engage // other starships: else { List<Ship> ward_threats; ListIter<Contact> contact = ship->ContactList(); while (++contact) { Ship* c_ship = contact->GetShip(); if (!c_ship) continue; int c_iff = contact->GetIFF(ship); bool rogue = c_ship->IsRogue(); bool tgt_ok = c_ship != ship && c_iff > 0 && c_iff != ship->GetIFF() && !c_ship->InTransition(); if (rogue || tgt_ok) { if (c_ship->IsStarship() || c_ship->IsStatic()) { // found an enemy, check distance: double dist = (ship->Location() - c_ship->Location()).length(); if (dist < 0.75 * target_dist) { potential_target = c_ship; target_dist = dist; } if (ward && c_ship->IsTracking(ward)) { ward_threats.append(c_ship); } } } } // if this ship is protecting a ward, // prefer targets that are threatening that ward: if (potential_target && ward_threats.size() && !ward_threats.contains((Ship*)potential_target)) { target_dist *= 2; ListIter<Ship> iter = ward_threats; while (++iter) { Ship* threat = iter.value(); double dist = (ward->Location() - threat->Location()).length(); if (dist < target_dist) { potential_target = threat; target_dist = dist; } } } } if (ship->Class() != Ship::CARRIER && ship->Class() != Ship::SWACS) ship_ai->SetTarget(potential_target); }
void Weapon::SelectTarget() { bool select_locked = false; SimObject* targ = 0; double dist = 1e9; double az = 0; double el = 0; if (ammo && enabled && (availability > crit_level)) { ZeroAim(); ListIter<Contact> contact = ship->ContactList(); // lock onto any threatening shots first (if we can): if (design->target_type & Ship::DRONE) { while (++contact) { Shot* c_shot = contact->GetShot(); if (c_shot && contact->Threat(ship)) { // distance from self to target: double distance = Point(c_shot->Location() - muzzle_pts[0]).length(); if (distance > design->min_range && distance < design->max_range && distance < dist) { // check aim basket: select_locked = CanLockPoint(c_shot->Location(), az, el); if (select_locked) { targ = c_shot; dist = distance; } } } } } // lock onto a threatening ship only if it is (much) closer: dist *= 0.2; contact.reset(); while (++contact) { Ship* c_ship = contact->GetShip(); if (!c_ship) continue; // can we lock onto this target? if ((c_ship->IsRogue() || c_ship->GetIFF() > 0 && c_ship->GetIFF() != ship->GetIFF()) && (c_ship->Class() & design->target_type) && c_ship->Weapons().size() > 0) { // distance from self to target: double distance = Point(c_ship->Location() - muzzle_pts[0]).length(); if (distance < design->max_range && distance < dist) { // check aim basket: select_locked = CanLockPoint(c_ship->Location(), az, el); if (select_locked) { targ = c_ship; dist = distance; } } } } } if (!ammo || !enabled) { SetTarget(0,0); locked = false; } else { SetTarget(targ, 0); } }