bool TacticalAI::CheckObjectives() { bool processed = false; Ship* ward = 0; Element* elem = ship->GetElement(); if (elem) { Instruction* obj = elem->GetTargetObjective(); if (obj) { ship_ai->ClearPatrol(); if (obj->Action()) { switch (obj->Action()) { case Instruction::INTERCEPT: case Instruction::STRIKE: case Instruction::ASSAULT: { SimObject* tgt = obj->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP) { roe = DIRECTED; SelectTargetDirected((Ship*) tgt); } } break; case Instruction::DEFEND: case Instruction::ESCORT: { SimObject* tgt = obj->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP) { roe = DEFENSIVE; ward = (Ship*) tgt; } } break; default: break; } } orders = obj; processed = true; } } ship_ai->SetWard(ward); return processed; }
void FighterTacticalAI::SelectTarget() { TacticalAI::SelectTarget(); SimObject* target = ship_ai->GetTarget(); if (target && (target->Type() == SimObject::SIM_SHIP) && (Game::GameTime() - secondary_selection_time) > THREAT_REACTION_TIME) { SelectSecondaryForTarget((Ship*) target); secondary_selection_time = Game::GameTime(); } }
void Element::ResumeAssignment() { SetAssignment(0); if (objectives.isEmpty()) return; Instruction* objective = 0; for (int i = 0; i < objectives.size() && !objective; i++) { Instruction* instr = objectives[i]; if (instr->Status() <= Instruction::ACTIVE) { switch (instr->Action()) { case Instruction::INTERCEPT: case Instruction::STRIKE: case Instruction::ASSAULT: objective = instr; break; } } } if (objective) { Sim* sim = Sim::GetSim(); ListIter<Element> iter = sim->GetElements(); while (++iter) { Element* elem = iter.value(); SimObject* tgt = objective->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP && elem->Contains((const Ship*) tgt)) { SetAssignment(elem); return; } } } }
void TacticalAI::CheckTarget() { SimObject* tgt = ship_ai->GetTarget(); if (!tgt) return; if (tgt->GetRegion() != ship->GetRegion()) { ship_ai->DropTarget(); return; } if (tgt->Type() == SimObject::SIM_SHIP) { Ship* target = (Ship*) tgt; // has the target joined our side? if (target->GetIFF() == ship->GetIFF() && !target->IsRogue()) { ship_ai->DropTarget(); return; } // is the target already jumping/breaking/dying? if (target->InTransition()) { ship_ai->DropTarget(); return; } // have we been ordered to pursue the target? if (directed_tgtid) { if (directed_tgtid != target->Identity()) { ship_ai->DropTarget(); } return; } // can we catch the target? if (target->Design()->vlimit <= ship->Design()->vlimit || ship->Velocity().length() <= ship->Design()->vlimit) return; // is the target now out of range? WeaponDesign* wep_dsn = ship->GetPrimaryDesign(); if (!wep_dsn) return; // compute the "give up" range: double drop_range = 3 * wep_dsn->max_range; if (drop_range > 0.75 * ship->Design()->commit_range) drop_range = 0.75 * ship->Design()->commit_range; double range = Point(target->Location() - ship->Location()).length(); if (range < drop_range) return; // is the target closing or separating? Point delta = (target->Location() + target->Velocity()) - (ship->Location() + ship->Velocity()); if (delta.length() < range) return; ship_ai->DropTarget(); } else if (tgt->Type() == SimObject::SIM_DRONE) { Drone* drone = (Drone*) tgt; // is the target still a threat? if (drone->GetEta() < 1 || drone->GetTarget() == 0) ship_ai->DropTarget(); } }
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 TacticalAI::SelectTarget() { if (!ship) { roe = NONE; return; } // unarmed vessels should never engage an enemy: if (ship->Weapons().size() < 1) roe = NONE; SimObject* target = ship_ai->GetTarget(); SimObject* ward = ship_ai->GetWard(); // if not allowed to engage, drop and return: if (roe == NONE) { if (target) ship_ai->DropTarget(); return; } // if we have abandoned our ward, drop and return: if (ward && roe != AGRESSIVE) { double d = (ward->Location() - ship->Location()).length(); double safe_zone = 50e3; if (target) { if (ship->IsStarship()) safe_zone = 100e3; if (d > safe_zone) { ship_ai->DropTarget(); return; } } else { if (d > safe_zone) { return; } } } // already have a target, keep it: if (target) { if (target->Life()) { CheckTarget(); // frigates need to be ready to abandon ship-type targets // in favor of drone-type targets, others should just go // with what they have: if (ship->Class() != Ship::CORVETTE && ship->Class() != Ship::FRIGATE) return; // in case the check decided to drop the target: target = ship_ai->GetTarget(); } // if the old target is dead, forget it: else { ship_ai->DropTarget(); target = 0; } } // if not allowed to acquire, forget it: if (ship_ai->DropTime() > 0) return; if (roe == DIRECTED) { if (target && target->Type() == SimObject::SIM_SHIP) SelectTargetDirected((Ship*) target); else if (navpt && navpt->GetTarget() && navpt->GetTarget()->Type() == SimObject::SIM_SHIP) SelectTargetDirected((Ship*) navpt->GetTarget()); else SelectTargetDirected(); } else { SelectTargetOpportunity(); // don't switch one ship target for another... if (ship->Class() == Ship::CORVETTE || ship->Class() == Ship::FRIGATE) { SimObject* potential_target = ship_ai->GetTarget(); if (target && potential_target && target != potential_target) { if (target->Type() == SimObject::SIM_SHIP && potential_target->Type() == SimObject::SIM_SHIP) { ship_ai->SetTarget(target); } } } } }
bool TacticalAI::CheckFlightPlan() { Ship* ward = 0; // Find next Instruction: navpt = ship->GetNextNavPoint(); roe = FLEXIBLE; if (navpt) { switch (navpt->Action()) { case Instruction::LAUNCH: case Instruction::DOCK: case Instruction::RTB: roe = NONE; break; case Instruction::VECTOR: roe = SELF_DEFENSIVE; break; case Instruction::DEFEND: case Instruction::ESCORT: roe = DEFENSIVE; break; case Instruction::INTERCEPT: roe = DIRECTED; break; case Instruction::RECON: case Instruction::STRIKE: case Instruction::ASSAULT: roe = DIRECTED; break; case Instruction::PATROL: case Instruction::SWEEP: roe = FLEXIBLE; break; default: break; } if (roe == DEFENSIVE) { SimObject* tgt = navpt->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP) ward = (Ship*) tgt; } if (navpt->EMCON() > 0) { int desired_emcon = navpt->EMCON(); if (ship_ai && (ship_ai->GetThreat() || ship_ai->GetThreatMissile())) desired_emcon = 3; if (ship->GetEMCON() != desired_emcon) ship->SetEMCON(desired_emcon); } } if (ship_ai) ship_ai->SetWard(ward); return (navpt != 0); }
bool TacticalAI::ProcessOrders() { if (ship_ai) ship_ai->ClearPatrol(); if (orders && orders->EMCON() > 0) { int desired_emcon = orders->EMCON(); if (ship_ai && (ship_ai->GetThreat() || ship_ai->GetThreatMissile())) desired_emcon = 3; if (ship->GetEMCON() != desired_emcon) ship->SetEMCON(desired_emcon); } if (orders && orders->Action()) { switch (orders->Action()) { case RadioMessage::ATTACK: case RadioMessage::BRACKET: case RadioMessage::IDENTIFY: { bool tgt_ok = false; SimObject* tgt = orders->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP) { Ship* tgt_ship = (Ship*) tgt; if (CanTarget(tgt_ship)) { roe = DIRECTED; SelectTargetDirected((Ship*) tgt); ship_ai->SetBracket(orders->Action() == RadioMessage::BRACKET); ship_ai->SetIdentify(orders->Action() == RadioMessage::IDENTIFY); ship_ai->SetNavPoint(0); tgt_ok = true; } } if (!tgt_ok) ClearRadioOrders(); } break; case RadioMessage::ESCORT: case RadioMessage::COVER_ME: { SimObject* tgt = orders->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP) { roe = DEFENSIVE; ship_ai->SetWard((Ship*) tgt); ship_ai->SetNavPoint(0); } else { ClearRadioOrders(); } } break; case RadioMessage::WEP_FREE: roe = AGRESSIVE; ship_ai->DropTarget(0.1); break; case RadioMessage::WEP_HOLD: case RadioMessage::FORM_UP: roe = NONE; ship_ai->DropTarget(5); break; case RadioMessage::MOVE_PATROL: roe = SELF_DEFENSIVE; ship_ai->SetPatrol(orders->Location()); ship_ai->SetNavPoint(0); ship_ai->DropTarget(Random(5, 10)); break; case RadioMessage::RTB: case RadioMessage::DOCK_WITH: roe = NONE; ship_ai->DropTarget(10); if (!ship->GetInbound()) { RadioMessage* msg = 0; Ship* controller = ship->GetController(); if (orders->Action() == RadioMessage::DOCK_WITH && orders->GetTarget()) { controller = (Ship*) orders->GetTarget(); } if (!controller) { Element* elem = ship->GetElement(); if (elem && elem->GetCommander()) { Element* cmdr = elem->GetCommander(); controller = cmdr->GetShip(1); } } if (controller && controller->GetHangar() && controller->GetHangar()->CanStow(ship)) { SimRegion* self_rgn = ship->GetRegion(); SimRegion* rtb_rgn = controller->GetRegion(); if (self_rgn == rtb_rgn) { double range = Point(controller->Location() - ship->Location()).length(); if (range < 50e3) { msg = new(__FILE__,__LINE__) RadioMessage(controller, ship, RadioMessage::CALL_INBOUND); RadioTraffic::Transmit(msg); } } } else { ship->ClearRadioOrders(); } ship_ai->SetNavPoint(0); } break; case RadioMessage::QUANTUM_TO: case RadioMessage::FARCAST_TO: roe = NONE; ship_ai->DropTarget(10); break; } action = orders->Action(); return true; } // if we had an action before, this must be a "cancel orders" else if (action) { ClearRadioOrders(); } return false; }
void CameraDirector::ExecFrame(double seconds) { if (!ship) return; hud = HUDView::GetInstance(); int flight_phase = ship->GetFlightPhase(); if (flight_phase < Ship::LOCKED) SetMode(MODE_DOCKING); if (ship->IsAirborne()) { if (flight_phase >= Ship::DOCKING) SetMode(MODE_DOCKING); } else { if (flight_phase >= Ship::RECOVERY) SetMode(MODE_DOCKING); } if (flight_phase >= Ship::LOCKED && flight_phase < Ship::ACTIVE) { int m = GetMode(); if (m != MODE_COCKPIT && m != MODE_VIRTUAL) SetMode(MODE_COCKPIT); } if (ship->InTransition()) { SetMode(MODE_DROP); } // automatically restore mode after transition: else if (old_mode != MODE_NONE) { mode = old_mode; requested_mode = old_mode; old_mode = MODE_NONE; } int op_mode = mode; if (requested_mode > mode) op_mode = requested_mode; Starshatter* stars = Starshatter::GetInstance(); // if we are in padlock, and have not locked a ship // try to padlock the current target: if (op_mode == MODE_TARGET && !external_ship) { SimObject* tgt = ship->GetTarget(); if (tgt && tgt->Type() == SimObject::SIM_SHIP) SetViewObject((Ship*) tgt); } // if in an external mode, check the external ship: else if (op_mode >= MODE_TARGET && op_mode <= MODE_ZOOM) { if (external_ship && external_ship != ship && !stars->InCutscene()) { Contact* c = ship->FindContact(external_ship); if (!c || !c->ActLock()) { SetViewObject(ship); } } } if (ship->Rep()) { if (op_mode == MODE_COCKPIT) { ship->HideRep(); ship->HideCockpit(); } else if (op_mode == MODE_VIRTUAL || op_mode == MODE_TARGET) { if (ship->Cockpit()) { ship->HideRep(); ship->ShowCockpit(); } else { ship->ShowRep(); } } else { ship->Rep()->SetForeground(op_mode == MODE_DOCKING); ship->ShowRep(); ship->HideCockpit(); } } if (hud && hud->Ambient() != Color::Black) sim->GetScene()->SetAmbient( hud->Ambient() ); else sim->GetScene()->SetAmbient( sim->GetStarSystem()->Ambient() ); switch (op_mode) { default: case MODE_COCKPIT: Cockpit(seconds); break; case MODE_CHASE: Chase(seconds); break; case MODE_TARGET: Target(seconds); break; case MODE_THREAT: Threat(seconds); break; case MODE_VIRTUAL: Virtual(seconds); break; case MODE_ORBIT: case MODE_TRANSLATE: case MODE_ZOOM: Orbit(seconds); break; case MODE_DOCKING: Docking(seconds); break; case MODE_DROP: Drop(seconds); break; } if (ship->Shake() > 0 && (op_mode < MODE_ORBIT || (op_mode == MODE_VIRTUAL && ship->Cockpit()))) { Point vib = ship->Vibration() * 0.2; camera.MoveBy(vib); camera.Aim(0, vib.y, vib.z); } Transition(seconds); DetailSet::SetReference(region, camera.Pos()); }