bool FighterTacticalAI::IsStrikeComplete(Instruction* instr) { // wingmen can not call a halt to a strike: if (!ship || element_index > 1) return false; // if there's nothing to shoot at, we must be done: if (!instr || !instr->GetTarget() || instr->GetTarget()->Life() == 0 || instr->GetTarget()->Type() != SimObject::SIM_SHIP) return true; // break off strike only when ALL weapons are expended: // (remember to check all relevant wingmen) Element* element = ship->GetElement(); Ship* target = (Ship*) instr->GetTarget(); if (!element) return true; for (int i = 0; i < element->NumShips(); i++) { Ship* s = element->GetShip(i+1); if (!s || s->Integrity() < 25) // || (s->Location() - target->Location()).length() > 250e3) continue; ListIter<WeaponGroup> g_iter = s->Weapons(); while (++g_iter) { WeaponGroup* w = g_iter.value(); if (w->Ammo() && w->CanTarget(target->Class())) { ListIter<Weapon> w_iter = w->GetWeapons(); while (++w_iter) { Weapon* weapon = w_iter.value(); if (weapon->Status() > System::CRITICAL) return false; } } } } // still here? we must be done! return true; }
int FighterTacticalAI::ListSecondariesForTarget(Ship* tgt, List<WeaponGroup>& weps) { weps.clear(); if (tgt) { ListIter<WeaponGroup> iter = ship->Weapons(); while (++iter) { WeaponGroup* w = iter.value(); if (w->Ammo() && w->CanTarget(tgt->Class())) weps.append(w); } } return weps.size(); }
void NetPlayer::SetShip(Ship* s) { if (ship != s) { if (ship) { ship->EnableRepair(true); Ignore(ship); } ship = s; if (ship) { Observe(ship); ship->SetNetworkControl(this); ship->SetObjID(objid); iff = ship->GetIFF(); // Turn off auto-repair. All repair data should // come in over the network from the remote player: ship->EnableRepair(false); // Set all ship weapons back to manual fire control. // All trigger events should come over the network, // not from weapon auto aiming ai: 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(); weapon->SetFiringOrders(Weapon::MANUAL); } } } } }
void GroundAI::ExecFrame(double secs) { const int exec_period = 1000; if ((int) Game::GameTime() - exec_time > exec_period) { exec_time = (int) Game::GameTime(); SelectTarget(); } if (ship) { Shield* shield = ship->GetShield(); if (shield) shield->SetPowerLevel(100); ListIter<WeaponGroup> iter = ship->Weapons(); while (++iter) { WeaponGroup* group = (WeaponGroup*) iter.value(); if (group->NumWeapons() > 1 && group->CanTarget(Ship::DROPSHIPS)) group->SetFiringOrders(Weapon::POINT_DEFENSE); else group->SetFiringOrders(Weapon::AUTO); group->SetTarget((Ship*) target, 0); } if (carrier_ai) carrier_ai->ExecFrame(secs); } }
bool StarshipAI::AssessTargetPointDefense() { if (Game::GameTime() - point_defense_time < 3500) return tgt_point_defense; tgt_point_defense = false; if (!target || target->Type() != SimObject::SIM_SHIP || GetAILevel() < 2) return tgt_point_defense; Ship* tgt_ship = (Ship*) target; if (!tgt_ship->IsStarship()) return tgt_point_defense; Weapon* subtgt = 0; Point svec = ship->Location() - tgt_ship->Location(); point_defense_time = Game::GameTime(); // first pass: turrets ListIter<WeaponGroup> g_iter = tgt_ship->Weapons(); while (++g_iter && !tgt_point_defense) { WeaponGroup* g = g_iter.value(); if (g->CanTarget(1)) { ListIter<Weapon> w_iter = g->GetWeapons(); while (++w_iter && !tgt_point_defense) { Weapon* w = w_iter.value(); if (w->Availability() > 35 && w->GetAimVector() * svec > 0) tgt_point_defense = true; } } } return tgt_point_defense; }
bool Model::Read() { int chunk; FILE *f; ImgString ist; if (filename.Length() == 0) { ErrorMsg("Project has no filename."); return false; } f = fopen(filename.c_str(), "rb"); if (f == NULL) { ErrorMsg("Could not open %s for binary reading.", filename.c_str()); return false; } int nmeshes; Mesh *m; // Header fread(&nmeshes, sizeof nmeshes, 1, f); if (nmeshes != GEO_MAGIC) { ErrorMsg("This is not a Segeltuch Project file"); return false; } fread(&nmeshes, sizeof nmeshes, 1, f); fread(&nlods, sizeof nlods, 1, f); // Info meshes.insert(meshes.end(), nmeshes, Mesh()); for (m=meshes.begin(); m != meshes.end(); m++) { m->Read(f); } // Additional resources int ntexts, i; char str[128]; int nt, ng; Thruster *trstr; Glow *glow; // Process them while (fread(&chunk, 4, 1, f)) { switch (chunk) { case TEXT_ID: fread(&ntexts, 4, 1, f); //InfoMsg("%d Textures found", ntexts); while (ntexts) { fread(&i, 4, 1, f); fread(str, i+1, 1, f); ist.s = str; ist.image = 0; mats.push_back(ist); ntexts--; } break; case SHLD_ID: shields.Read(f); break; case OLD_WEAP_ID: /////// REMOVE AS SOON AS POSSIBLE //////// { fread(&i, 4, 1, f); WeaponGroup wg; int group_gun = 0, group_mis = 0, group; while (i > 0) { wg.Read(f); i--; if (wg.type == WT_GUN) group = group_gun++; else group = group_mis++; size_t wi = weapons.size(); weapons.insert(weapons.end(), wg.weapons.size(), Weapon()); for (size_t w=0; w < wg.weapons.size(); w++, wi++) { weapons[wi].Type = wg.type; weapons[wi].ID = w; weapons[wi].Group = group; weapons[wi].Pos = wg.weapons[w].Pos; weapons[wi].Normal= wg.weapons[w].Normal; } } } /////////////// break; case NEW_WEAP_ID: fread(&i, 4, 1, f); weapons.clear(); weapons.insert(weapons.end(), i, Weapon()); for (int w=0; w < i; w++) { weapons[w].Read(f); } break; case THRUST_ID: fread(&i, 4, 1, f); thrusters.clear(); thrusters.insert(thrusters.begin(), i, Thruster()); for (int t=0; t < i; t++) { thrusters[t].Read(f); } break; case SPCL_ID: fread(&i, 4, 1, f); Specials.clear(); Specials.insert(Specials.begin(), i, Special()); for (int s=0; s < i; s++) { Specials[s].Read(f); } break; default: ErrorMsg("Unrecognized chunk (ID=0x%X) in project file", chunk); fclose(f); return false; } } fclose(f); return true; }
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 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); } } } }
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); } }