void FltDlg::UpdateObjective() { if (!objective_list || mission_type < 0 || !ship) return; Sim* sim = Sim::GetSim(); char txt[32]; for (int item = 0; item < objective_list->NumItems(); item++) { const char* obj_name = objective_list->GetItemText(item); Element* elem = sim->FindElement(obj_name); // if element has expired, remove it from the objective list if (!elem || !elem->IsActive() || elem->IsFinished()) { objective_list->RemoveItem(item); item--; } // otherwise, the element is still active, so update range/region else { Ship* s = elem->GetShip(1); double r = 0; bool con = false; if (s) { Point s_loc = s->Location() + s->GetRegion()->Location(); Point h_loc = ship->Location() + ship->GetRegion()->Location(); r = (s_loc - h_loc).length(); con = ship->FindContact(s) != 0; if (con) { FormatNumber(txt, r); } else { strcpy_s(txt, Game::GetText("FltDlg.Unknown").data()); r = 2e9; } } objective_list->SetItemText(item, 1, s->GetRegion()->Name()); objective_list->SetItemText(item, 2, txt); objective_list->SetItemData(item, 2, (DWORD) r); } } }
bool CameraDirector::Update(SimObject* obj) { if (obj->Type() == SimObject::SIM_SHIP) { Ship* s = (Ship*) obj; if (ship == s) ship = 0; if (external_ship == s) { external_point = s->Location(); external_ship = 0; } if (external_group.contains(s)) external_group.remove(s); } return SimObserver::Update(obj); }
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); }
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; }
bool MissionEvent::CheckTrigger() { Sim* sim = Sim::GetSim(); if (time > 0 && time > sim->MissionClock()) return false; switch (trigger) { case TRIGGER_TIME: { if (time <= sim->MissionClock()) Activate(); } break; case TRIGGER_DAMAGE: { Ship* ship = sim->FindShip(trigger_ship); if (ship) { double damage = 100.0 * (ship->Design()->integrity - ship->Integrity()) / (ship->Design()->integrity); if (damage >= trigger_param[0]) Activate(); } } break; case TRIGGER_DETECT: { Ship* ship = sim->FindShip(trigger_ship); Ship* tgt = sim->FindShip(trigger_target); if (ship && tgt) { if (ship->FindContact(tgt)) Activate(); } else { Skip(); } } break; case TRIGGER_RANGE: { Ship* ship = sim->FindShip(trigger_ship); Ship* tgt = sim->FindShip(trigger_target); if (ship && tgt) { double range = (ship->Location() - tgt->Location()).length(); double min_range = 0; double max_range = 1e12; if (trigger_param[0] > 0) min_range = trigger_param[0]; else max_range = -trigger_param[0]; if (range < min_range || range > max_range) Activate(); } else { Skip(); } } break; case TRIGGER_SHIPS_LEFT: { int alive = 0; int count = 0; int iff = -1; int nparams = NumTriggerParams(); if (nparams > 0) count = TriggerParam(0); if (nparams > 1) iff = TriggerParam(1); ListIter<SimRegion> iter = sim->GetRegions(); while (++iter) { SimRegion* rgn = iter.value(); ListIter<Ship> s_iter = rgn->Ships(); while (++s_iter) { Ship* ship = s_iter.value(); if (ship->Type() >= Ship::STATION) continue; if (ship->Life() == 0 && ship->RespawnCount() < 1) continue; if (iff < 0 || ship->GetIFF() == iff) alive++; } } if (alive <= count) Activate(); } break; case TRIGGER_EVENT_ALL: { bool all = true; int nparams = NumTriggerParams(); for (int i = 0; all && i < nparams; i++) { int trigger_id = TriggerParam(i); ListIter<MissionEvent> iter = sim->GetEvents(); while (++iter) { MissionEvent* e = iter.value(); if (e->EventID() == trigger_id) { if (e->Status() != COMPLETE) all = false; break; } else if (e->EventID() == -trigger_id) { if (e->Status() == COMPLETE) all = false; break; } } } if (all) Activate(); } break; case TRIGGER_EVENT_ANY: { bool any = false; int nparams = NumTriggerParams(); for (int i = 0; !any && i < nparams; i++) { int trigger_id = TriggerParam(i); ListIter<MissionEvent> iter = sim->GetEvents(); while (++iter) { MissionEvent* e = iter.value(); if (e->EventID() == trigger_id) { if (e->Status() == COMPLETE) any = true; break; } } } if (any) Activate(); } break; } return status == ACTIVE; }
void FltDlg::OnMissionType(AWEvent* event) { mission_type = -1; for (int i = 0; i < 6; i++) { if (mission_btn[i]) { if (mission_btn[i] == event->window) { mission_btn[i]->SetButtonState(1); mission_type = i; } else { mission_btn[i]->SetButtonState(0); } } } if (objective_list && mission_type > -1) { objective_list->ClearItems(); char txt[32]; Sim* sim = Sim::GetSim(); ListIter<Element> iter = sim->GetElements(); while (++iter) { Element* elem = iter.value(); if (!elem->IsActive() || elem->IsFinished() || elem->IsSquadron()) continue; CombatGroup* group = elem->GetCombatGroup(); int iff = elem->GetIFF(); Ship* s = elem->GetShip(1); double r = 0; bool con = false; if (iff != ship->GetIFF()) { if (elem->IntelLevel() < Intel::LOCATED) continue; if (group && group->IntelLevel() < Intel::LOCATED) continue; } if (s) { Point s_loc = s->Location() + s->GetRegion()->Location(); Point h_loc = ship->Location() + ship->GetRegion()->Location(); r = (s_loc - h_loc).length(); con = ship->FindContact(s) != 0; if (con) { FormatNumber(txt, r); } else { strcpy_s(txt, Game::GetText("FltDlg.Unknown").data()); r = 2e9; } } switch (mission_type) { case 1: // INTERCEPT if (iff && iff != ship->GetIFF() && s && s->IsDropship()) { int item = objective_list->AddItem(elem->Name()) - 1; objective_list->SetItemText(item, 1, s->GetRegion()->Name()); objective_list->SetItemText(item, 2, txt); objective_list->SetItemData(item, 2, (DWORD) r); } break; case 2: // ASSAULT if (iff && iff != ship->GetIFF() && s && (s->IsStarship() || s->IsStatic())) { int item = objective_list->AddItem(elem->Name()) - 1; objective_list->SetItemText(item, 1, s->GetRegion()->Name()); objective_list->SetItemText(item, 2, txt); objective_list->SetItemData(item, 2, (DWORD) r); } break; case 3: // STRIKE if (iff && iff != ship->GetIFF() && s && s->IsGroundUnit()) { int item = objective_list->AddItem(elem->Name()) - 1; objective_list->SetItemText(item, 1, s->GetRegion()->Name()); objective_list->SetItemText(item, 2, txt); objective_list->SetItemData(item, 2, (DWORD) r); } break; case 4: // ESCORT if ((iff == 0 || iff == ship->GetIFF()) && (!s || !s->IsStatic())) { int item = objective_list->AddItem(elem->Name()) - 1; if (s) { objective_list->SetItemText(item, 1, s->GetRegion()->Name()); objective_list->SetItemText(item, 2, txt); objective_list->SetItemData(item, 2, (DWORD) r); } else { objective_list->SetItemText(item, 1, "0"); objective_list->SetItemData(item, 1, 0); } } break; case 5: // SCOUT? break; default: break; } } } if (loadout_list && mission_type > -1) { loadout_list->ClearItems(); if (design) { ListIter<ShipLoad> sl = (List<ShipLoad>&) design->loadouts; while (++sl) { int item = loadout_list->AddItem(sl->name) - 1; char weight[32]; sprintf_s(weight, "%d kg", (int) ((design->mass + sl->mass) * 1000)); loadout_list->SetItemText(item, 1, weight); loadout_list->SetItemData(item, 1, (DWORD) (sl->mass * 1000)); } } } }