diff options
author | milo24x7@gmail.com <milo24x7@gmail.com@076cb2c4-205e-83fd-5cf3-1be9aa105544> | 2013-07-07 22:08:49 +0000 |
---|---|---|
committer | milo24x7@gmail.com <milo24x7@gmail.com@076cb2c4-205e-83fd-5cf3-1be9aa105544> | 2013-07-07 22:08:49 +0000 |
commit | d17521c8b9085a91d08fecfd0b51bbbf7b1dccac (patch) | |
tree | 4673104b47dc68a079cac9f94deefd48dfcb66fa /Stars45/CampaignMissionFighter.cpp | |
parent | 1de4b2bdbb019be6f1b7262c3eba5568d7682edd (diff) | |
download | starshatter-d17521c8b9085a91d08fecfd0b51bbbf7b1dccac.zip starshatter-d17521c8b9085a91d08fecfd0b51bbbf7b1dccac.tar.gz starshatter-d17521c8b9085a91d08fecfd0b51bbbf7b1dccac.tar.bz2 |
Updated open source license declaration and fixed some formatting issues.
Diffstat (limited to 'Stars45/CampaignMissionFighter.cpp')
-rw-r--r-- | Stars45/CampaignMissionFighter.cpp | 4334 |
1 files changed, 2179 insertions, 2155 deletions
diff --git a/Stars45/CampaignMissionFighter.cpp b/Stars45/CampaignMissionFighter.cpp index 002dae7..06db25e 100644 --- a/Stars45/CampaignMissionFighter.cpp +++ b/Stars45/CampaignMissionFighter.cpp @@ -1,2155 +1,2179 @@ -/* Project Starshatter 4.5
- Destroyer Studios LLC
- Copyright (C) 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: Stars.exe
- FILE: CampaignMissionFighter.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- CampaignMissionFighter generates missions and mission
- info for the player's FIGHTER SQUADRON as part of a
- dynamic campaign.
-*/
-
-#include "MemDebug.h"
-#include "CampaignMissionFighter.h"
-#include "CampaignMissionRequest.h"
-#include "Campaign.h"
-#include "Combatant.h"
-#include "CombatAssignment.h"
-#include "CombatGroup.h"
-#include "CombatUnit.h"
-#include "CombatZone.h"
-#include "Callsign.h"
-#include "Galaxy.h"
-#include "Mission.h"
-#include "MissionTemplate.h"
-#include "Instruction.h"
-#include "Ship.h"
-#include "ShipDesign.h"
-#include "Starshatter.h"
-#include "StarSystem.h"
-#include "Player.h"
-
-#include "Random.h"
-
-static int pkg_id = 1000;
-extern int dump_missions;
-
-// +--------------------------------------------------------------------+
-
-CampaignMissionFighter::CampaignMissionFighter(Campaign* c)
-: campaign(c), squadron(0), mission(0), player_elem(0),
-strike_group(0), strike_target(0), prime_target(0),
-carrier_elem(0), ward(0), escort(0), airborne(false), airbase(false),
-ownside(0), enemy(-1), mission_type(0), mission_info(0)
-{
- if (!campaign || !campaign->GetPlayerGroup()) {
- ::Print("ERROR - CMF campaign=0x%08x player_group=0x%08x\n",
- campaign, (DWORD) campaign?campaign->GetPlayerGroup():0);
- return;
- }
-
- CombatGroup* player_group = campaign->GetPlayerGroup();
-
- switch (player_group->Type()) {
- case CombatGroup::WING: {
- CombatGroup* wing = player_group;
- ListIter<CombatGroup> iter = wing->GetComponents();
-
- while (++iter) {
- if (iter->Type() == CombatGroup::FIGHTER_SQUADRON) {
- squadron = iter.value();
- }
- }
- }
- break;
-
- case CombatGroup::FIGHTER_SQUADRON:
- case CombatGroup::INTERCEPT_SQUADRON:
- case CombatGroup::ATTACK_SQUADRON:
- squadron = player_group;
- break;
-
- default:
- ::Print("ERROR - CMF invalid player group: %s IFF %d\n",
- player_group->GetDescription(),
- player_group->GetIFF());
- break;
- }
-
- if (squadron) {
- CombatGroup* carrier = squadron->FindCarrier();
-
- if (carrier && carrier->Type() == CombatGroup::STARBASE) {
- airbase = true;
- }
- }
-}
-
-CampaignMissionFighter::~CampaignMissionFighter() {}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateMission(CampaignMissionRequest* req)
-{
- if (!campaign || !squadron || !req)
- return;
-
- ::Print("\n-----------------------------------------------\n");
- if (req->Script().length())
- ::Print("CMF CreateMission() request: %s '%s'\n",
- Mission::RoleName(req->Type()),
- (const char*) req->Script());
-
- else
- ::Print("CMF CreateMission() request: %s %s\n",
- Mission::RoleName(req->Type()),
- req->GetObjective() ? req->GetObjective()->Name().data() : "(no target)");
-
- request = req;
- mission_info = 0;
-
- if (request->GetPrimaryGroup()) {
- switch (request->GetPrimaryGroup()->Type()) {
- case CombatGroup::FIGHTER_SQUADRON:
- case CombatGroup::INTERCEPT_SQUADRON:
- case CombatGroup::ATTACK_SQUADRON:
- squadron = request->GetPrimaryGroup();
- break;
- }
- }
-
- ownside = squadron->GetIFF();
-
- for (int i = 0; i < campaign->GetCombatants().size(); i++) {
- int iff = campaign->GetCombatants().at(i)->GetIFF();
- if (iff > 0 && iff != ownside) {
- enemy = iff;
- break;
- }
- }
-
- static int id_key = 1;
- GenerateMission(id_key++);
- DefineMissionObjectives();
-
- MissionInfo* info = DescribeMission();
-
- if (info) {
- campaign->GetMissionList().append(info);
-
- ::Print("CMF Created %03d '%s' %s\n\n",
- info->id,
- (const char*) info->name,
- Mission::RoleName(mission->Type()));
-
- if (dump_missions) {
- Text script = mission->Serialize();
- char fname[32];
-
- sprintf_s(fname, "msn%03d.def", info->id);
- FILE* f;
- fopen_s(&f, fname, "w");
- if (f) {
- fprintf(f, "%s\n", script.data());
- fclose(f);
- }
- }
- }
- else {
- ::Print("CMF failed to create mission.\n");
- }
-}
-
-// +--------------------------------------------------------------------+
-
-Mission*
-CampaignMissionFighter::GenerateMission(int id)
-{
- bool found = false;
-
- SelectType();
-
- if (request && request->Script().length()) {
- MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, request->Script(), campaign->Path());
- if (mt)
- mt->SetPlayerSquadron(squadron);
- mission = mt;
- found = true;
- }
-
- else {
- mission_info = campaign->FindMissionTemplate(mission_type, squadron);
- found = mission_info != 0;
-
- if (found) {
- MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, mission_info->script, campaign->Path());
- if (mt)
- mt->SetPlayerSquadron(squadron);
- mission = mt;
- }
- else {
- mission = new(__FILE__,__LINE__) Mission(id);
- if (mission)
- mission->SetType(mission_type);
- }
- }
-
- if (!mission) {
- Exit();
- return 0;
- }
-
- char name[64];
- sprintf_s(name, "Fighter Mission %d", id);
-
- mission->SetName(name);
- mission->SetTeam(squadron->GetIFF());
- mission->SetStart(request->StartTime());
-
- SelectRegion();
- GenerateStandardElements();
- CreatePatrols();
-
- if (!found) {
- GenerateMissionElements();
- mission->SetOK(true);
- mission->Validate();
- }
-
- else {
- mission->Load();
-
- if (mission->IsOK()) {
- player_elem = mission->GetPlayer();
- prime_target = mission->GetTarget();
- ward = mission->GetWard();
-
- Player* p = Player::GetCurrentPlayer();
-
- if (player_elem && p)
- player_elem->SetAlert(!p->FlyingStart());
- }
-
- // if there was a problem, scrap the mission
- // and start over:
- else {
- delete mission;
-
- mission = new(__FILE__,__LINE__) Mission(id);
- mission->SetType(mission_type);
- mission->SetName(name);
- mission->SetTeam(squadron->GetIFF());
- mission->SetStart(request->StartTime());
-
- SelectRegion();
- GenerateStandardElements();
- GenerateMissionElements();
-
- mission->SetOK(true);
- mission->Validate();
- }
- }
-
- return mission;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-CampaignMissionFighter::IsGroundObjective(CombatGroup* obj)
-{
- bool ground = false;
-
- if (obj) {
- CombatGroup* pgroup = campaign->GetPlayerGroup();
-
- if (pgroup) {
- CombatZone* zone = pgroup->GetAssignedZone();
-
- if (zone) {
- StarSystem* system = campaign->GetSystem(zone->System());
-
- if (system) {
- OrbitalRegion* region = system->FindRegion(obj->GetRegion());
-
- if (region && region->Type() == Orbital::TERRAIN) {
- ground = true;
- }
- }
- }
- }
- }
-
- return ground;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::SelectType()
-{
- int type = Mission::PATROL;
-
- if (request) {
- type = request->Type();
- if (type == Mission::STRIKE) {
- strike_group = request->GetPrimaryGroup();
-
- // verify that objective is a ground target:
- if (!IsGroundObjective(request->GetObjective())) {
- type = Mission::ASSAULT;
- }
- }
-
- else if (type == Mission::ESCORT_STRIKE) {
- strike_group = request->GetSecondaryGroup();
- if (!strike_group || strike_group->CalcValue() < 1) {
- type = Mission::SWEEP;
- strike_group = 0;
- }
- }
- }
-
- mission_type = type;
-}
-
-void
-CampaignMissionFighter::SelectRegion()
-{
- CombatZone* zone = squadron->GetAssignedZone();
-
- if (!zone)
- zone = squadron->GetCurrentZone();
-
- if (zone) {
- mission->SetStarSystem(campaign->GetSystem(zone->System()));
- mission->SetRegion(*zone->GetRegions().at(0));
-
- orb_region = mission->GetRegion();
-
- if (zone->GetRegions().size() > 1) {
- air_region = *zone->GetRegions().at(1);
-
- StarSystem* system = mission->GetStarSystem();
- OrbitalRegion* rgn = 0;
-
- if (system)
- rgn = system->FindRegion(air_region);
-
- if (!rgn || rgn->Type() != Orbital::TERRAIN)
- air_region = "";
- }
-
- if (air_region.length() > 0) {
- if (request && IsGroundObjective(request->GetObjective())) {
- airborne = true;
- }
-
- else if (mission->Type() >= Mission::AIR_PATROL &&
- mission->Type() <= Mission::AIR_INTERCEPT) {
- airborne = true;
- }
-
- else if (mission->Type() == Mission::STRIKE ||
- mission->Type() == Mission::ESCORT_STRIKE) {
- if (strike_group) {
- strike_target = campaign->FindStrikeTarget(ownside, strike_group);
-
- if (strike_target && strike_target->GetRegion() == air_region)
- airborne = true;
- }
- }
-
- if (airbase) {
- mission->SetRegion(air_region);
- }
- }
- }
-
- else {
- ::Print("WARNING: CMF - No zone for '%s'\n", squadron->Name().data());
-
- StarSystem* s = campaign->GetSystemList()[0];
-
- mission->SetStarSystem(s);
- mission->SetRegion(s->Regions()[0]->Name());
- }
-
- if (!airborne) {
- switch (mission->Type()) {
- case Mission::AIR_PATROL: mission->SetType(Mission::PATROL); break;
- case Mission::AIR_SWEEP: mission->SetType(Mission::SWEEP); break;
- case Mission::AIR_INTERCEPT: mission->SetType(Mission::INTERCEPT); break;
- default: break;
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::GenerateStandardElements()
-{
- ListIter<CombatZone> z_iter = campaign->GetZones();
- while (++z_iter) {
- CombatZone* z = z_iter.value();
-
- ListIter<ZoneForce> iter = z->GetForces();
- while (++iter) {
- ZoneForce* force = iter.value();
- ListIter<CombatGroup> group = force->GetGroups();
-
- while (++group) {
- CombatGroup* g = group.value();
-
- switch (g->Type()) {
- case CombatGroup::INTERCEPT_SQUADRON:
- case CombatGroup::FIGHTER_SQUADRON:
- case CombatGroup::ATTACK_SQUADRON:
- case CombatGroup::LCA_SQUADRON:
- CreateSquadron(g);
- break;
-
- case CombatGroup::DESTROYER_SQUADRON:
- case CombatGroup::BATTLE_GROUP:
- case CombatGroup::CARRIER_GROUP:
- CreateElements(g);
- break;
-
- case CombatGroup::MINEFIELD:
- case CombatGroup::BATTERY:
- case CombatGroup::MISSILE:
- case CombatGroup::STATION:
- case CombatGroup::STARBASE:
- case CombatGroup::SUPPORT:
- case CombatGroup::COURIER:
- case CombatGroup::MEDICAL:
- case CombatGroup::SUPPLY:
- case CombatGroup::REPAIR:
- CreateElements(g);
- break;
-
- case CombatGroup::CIVILIAN:
- case CombatGroup::WAR_PRODUCTION:
- case CombatGroup::FACTORY:
- case CombatGroup::REFINERY:
- case CombatGroup::RESOURCE:
- case CombatGroup::INFRASTRUCTURE:
- case CombatGroup::TRANSPORT:
- case CombatGroup::NETWORK:
- case CombatGroup::HABITAT:
- case CombatGroup::STORAGE:
- case CombatGroup::NON_COM:
- CreateElements(g);
- break;
- }
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::GenerateMissionElements()
-{
- CreateWards();
- CreatePlayer(squadron);
- CreateTargets();
- CreateEscorts();
-
- if (player_elem) {
- Instruction* obj = new(__FILE__,__LINE__) Instruction(mission->GetRegion(),
- Point(0,0,0),
- Instruction::RTB);
-
- if (obj)
- player_elem->AddObjective(obj);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateElements(CombatGroup* g)
-{
- MissionElement* elem = 0;
- List<CombatUnit>& units = g->GetUnits();
-
- CombatUnit* cmdr = 0;
-
- for (int i = 0; i < units.size(); i++) {
- elem = CreateSingleElement(g, units[i]);
-
- if (elem) {
- if (!cmdr) {
- cmdr = units[i];
- }
- else {
- elem->SetCommander(cmdr->Name());
-
- if (g->Type() == CombatGroup::CARRIER_GROUP &&
- elem->MissionRole() == Mission::ESCORT) {
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, cmdr->Name());
- if (obj)
- elem->AddObjective(obj);
- }
- }
-
- mission->AddElement(elem);
- }
- }
-}
-
-MissionElement*
-CampaignMissionFighter::CreateSingleElement(CombatGroup* g, CombatUnit* u)
-{
- if (!g || g->IsReserve()) return 0;
- if (!u || u->LiveCount() < 1) return 0;
-
- // make sure this unit is actually in the right star system:
- Galaxy* galaxy = Galaxy::GetInstance();
- if (galaxy) {
- if (galaxy->FindSystemByRegion(u->GetRegion()) !=
- galaxy->FindSystemByRegion(squadron->GetRegion())) {
- return 0;
- }
- }
-
- // make sure this unit isn't already in the mission:
- ListIter<MissionElement> e_iter = mission->GetElements();
- while (++e_iter) {
- MissionElement* elem = e_iter.value();
-
- if (elem->GetCombatUnit() == u)
- return 0;
- }
-
- MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
- if (!elem) {
- Exit();
- return 0;
- }
-
- if (u->Name().length())
- elem->SetName(u->Name());
- else
- elem->SetName(u->DesignName());
-
- elem->SetElementID(pkg_id++);
-
- elem->SetDesign(u->GetDesign());
- elem->SetCount(u->LiveCount());
- elem->SetIFF(u->GetIFF());
- elem->SetIntelLevel(g->IntelLevel());
- elem->SetRegion(u->GetRegion());
- elem->SetHeading(u->GetHeading());
-
- int unit_index = g->GetUnits().index(u);
- Point base_loc = u->Location();
- bool exact = u->IsStatic(); // exact unit-level placement
-
- if (base_loc.length() < 1) {
- base_loc = g->Location();
- exact = false;
- }
-
- if (unit_index < 0 || unit_index > 0 && !exact) {
- Point loc = RandomDirection();
-
- if (!u->IsStatic()) {
- while (fabs(loc.y) > fabs(loc.x))
- loc = RandomDirection();
-
- loc *= 10e3 + 9e3 * unit_index;
- }
- else {
- loc *= 2e3 + 2e3 * unit_index;
- }
-
- elem->SetLocation(base_loc + loc);
- }
- else {
- elem->SetLocation(base_loc);
- }
-
- if (g->Type() == CombatGroup::CARRIER_GROUP) {
- if (u->Type() == Ship::CARRIER) {
- elem->SetMissionRole(Mission::FLIGHT_OPS);
-
- if (squadron && elem->GetCombatGroup() == squadron->FindCarrier())
- carrier_elem = elem;
-
- else if (!carrier_elem && u->GetIFF() == squadron->GetIFF())
- carrier_elem = elem;
- }
- else {
- elem->SetMissionRole(Mission::ESCORT);
- }
- }
- else if (u->Type() == Ship::STATION ||
- u->Type() == Ship::STARBASE) {
- elem->SetMissionRole(Mission::FLIGHT_OPS);
-
- if (squadron && elem->GetCombatGroup() == squadron->FindCarrier()) {
- carrier_elem = elem;
-
- if (u->Type() == Ship::STARBASE)
- airbase = true;
- }
- }
- else if (u->Type() == Ship::FARCASTER) {
- elem->SetMissionRole(Mission::OTHER);
-
- // link farcaster to other terminus:
- Text name = u->Name();
- int dash = -1;
-
- for (int i = 0; i < (int) name.length(); i++)
- if (name[i] == '-')
- dash = i;
-
- Text src = name.substring(0, dash);
- Text dst = name.substring(dash+1, name.length() - (dash+1));
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::VECTOR, dst + "-" + src);
- elem->AddObjective(obj);
- }
- else if ((u->Type() & Ship::STARSHIPS) != 0) {
- elem->SetMissionRole(Mission::FLEET);
- }
-
- elem->SetCombatGroup(g);
- elem->SetCombatUnit(u);
-
- return elem;
-}
-
-CombatUnit*
-CampaignMissionFighter::FindCarrier(CombatGroup* g)
-{
- CombatGroup* carrier = g->FindCarrier();
-
- if (carrier && carrier->GetUnits().size()) {
- MissionElement* carrier_elem = mission->FindElement(carrier->Name());
-
- if (carrier_elem)
- return carrier->GetUnits().at(0);
- }
-
- return 0;
-}
-
-void
-CampaignMissionFighter::CreateSquadron(CombatGroup* g)
-{
- if (!g || g->IsReserve()) return;
-
- CombatUnit* fighter = g->GetUnits().at(0);
- CombatUnit* carrier = FindCarrier(g);
-
- if (!fighter || !carrier) return;
-
- int live_count = fighter->LiveCount();
- int maint_count = (live_count > 4) ? live_count / 2 : 0;
-
- MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
-
- if (!elem) {
- Exit();
- return;
- }
-
- elem->SetName(g->Name());
- elem->SetElementID(pkg_id++);
-
- elem->SetDesign(fighter->GetDesign());
- elem->SetCount(fighter->Count());
- elem->SetDeadCount(fighter->DeadCount());
- elem->SetMaintCount(maint_count);
- elem->SetIFF(fighter->GetIFF());
- elem->SetIntelLevel(g->IntelLevel());
- elem->SetRegion(fighter->GetRegion());
-
- elem->SetCarrier(carrier->Name());
- elem->SetCommander(carrier->Name());
- elem->SetLocation(carrier->Location() + RandomPoint());
-
- elem->SetCombatGroup(g);
- elem->SetCombatUnit(fighter);
-
- mission->AddElement(elem);
-}
-
-void
-CampaignMissionFighter::CreatePlayer(CombatGroup* g)
-{
- int pkg_size = 2;
-
- if (mission->Type() == Mission::STRIKE || mission->Type() == Mission::ASSAULT) {
- if (request && request->GetObjective()) {
- int tgt_type = request->GetObjective()->Type();
-
- if (tgt_type >= CombatGroup::FLEET && tgt_type <= CombatGroup::CARRIER_GROUP)
- pkg_size = 4;
-
- if (tgt_type == CombatGroup::STATION || tgt_type == CombatGroup::STARBASE)
- pkg_size = 4;
- }
- }
-
- MissionElement* elem = CreateFighterPackage(g, pkg_size, mission->Type());
-
- if (elem) {
- Player* p = Player::GetCurrentPlayer();
- elem->SetAlert(p ? !p->FlyingStart() : true);
- elem->SetPlayer(1);
-
- if (ward) {
- Point approach = elem->Location() - ward->Location();
- approach.Normalize();
-
- Point pickup = ward->Location() + approach * 50e3;
- double delta = (pickup - elem->Location()).length();
-
- if (delta > 30e3) {
- Instruction* n = new(__FILE__,__LINE__) Instruction(elem->Region(), pickup, Instruction::ESCORT);
- n->SetTarget(ward->Name());
- n->SetSpeed(750);
- elem->AddNavPoint(n);
- }
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, ward->Name());
-
- switch (mission->Type()) {
- case Mission::ESCORT_FREIGHT:
- obj->SetTargetDesc(Text("the star freighter ") + ward->Name());
- break;
-
- case Mission::ESCORT_SHUTTLE:
- obj->SetTargetDesc(Text("the shuttle ") + ward->Name());
- break;
-
- case Mission::ESCORT_STRIKE:
- obj->SetTargetDesc(Text("the ") + ward->Name() + Text(" strike package"));
- break;
-
- case Mission::DEFEND:
- obj->SetTargetDesc(Text("the ") + ward->Name());
- break;
-
- default:
- if (ward->GetCombatGroup()) {
- obj->SetTargetDesc(Text("the ") + ward->GetCombatGroup()->GetDescription());
- }
- else {
- obj->SetTargetDesc(Text("the ") + ward->Name());
- }
- break;
- }
-
- elem->AddObjective(obj);
- }
-
- mission->AddElement(elem);
-
- player_elem = elem;
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreatePatrols()
-{
- List<MissionElement> patrols;
-
- ListIter<MissionElement> iter = mission->GetElements();
- while (++iter) {
- MissionElement* squad_elem = iter.value();
- CombatGroup* squadron = squad_elem->GetCombatGroup();
- CombatUnit* unit = squad_elem->GetCombatUnit();
-
- if (!squad_elem->IsSquadron() || !squadron || !unit || unit->LiveCount() < 4)
- continue;
-
- if (squadron->Type() == CombatGroup::INTERCEPT_SQUADRON ||
- squadron->Type() == CombatGroup::FIGHTER_SQUADRON) {
-
- StarSystem* system = mission->GetStarSystem();
- CombatGroup* base = squadron->FindCarrier();
-
- if (!base)
- continue;
-
- OrbitalRegion* region = system->FindRegion(base->GetRegion());
-
- if (!region)
- continue;
-
- int patrol_type = Mission::PATROL;
- Point base_loc;
-
- if (region->Type() == Orbital::TERRAIN) {
- patrol_type = Mission::AIR_PATROL;
-
- if (RandomChance(2,3))
- continue;
- }
-
- base_loc = base->Location() + RandomPoint() * 1.5;
-
- if (region->Type() == Orbital::TERRAIN)
- base_loc += Point(0, 0, 14.0e3);
-
- MissionElement* elem = CreateFighterPackage(squadron, 2, patrol_type);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(base->GetRegion());
- elem->SetLocation(base_loc);
- patrols.append(elem);
- }
- }
- }
-
- iter.attach(patrols);
- while (++iter)
- mission->AddElement(iter.value());
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateWards()
-{
- switch (mission->Type()) {
- case Mission::ESCORT_FREIGHT: CreateWardFreight(); break;
- case Mission::ESCORT_SHUTTLE: CreateWardShuttle(); break;
- case Mission::ESCORT_STRIKE: CreateWardStrike(); break;
- default: break;
- }
-}
-
-void
-CampaignMissionFighter::CreateWardFreight()
-{
- if (!mission || !mission->GetStarSystem()) return;
-
- CombatUnit* carrier = FindCarrier(squadron);
- CombatGroup* freight = 0;
-
- if (request)
- freight = request->GetObjective();
-
- if (!freight)
- freight = campaign->FindGroup(ownside, CombatGroup::FREIGHT);
-
- if (!freight || freight->CalcValue() < 1) return;
-
- CombatUnit* unit = freight->GetNextUnit();
- if (!unit) return;
-
- MissionElement* elem = CreateSingleElement(freight, unit);
- if (!elem) return;
-
- elem->SetMissionRole(Mission::CARGO);
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(squadron->GetRegion());
-
- if (carrier)
- elem->SetLocation(carrier->Location() + RandomPoint() * 2);
-
- ward = elem;
- mission->AddElement(elem);
-
-
- StarSystem* system = mission->GetStarSystem();
- OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
- Point delta = rgn1->Location() - rgn1->Primary()->Location();
- Point npt_loc = elem->Location();
- Instruction* n = 0;
-
- delta.Normalize();
- delta *= 200.0e3;
-
- npt_loc += delta;
-
- n = new(__FILE__,__LINE__) Instruction(elem->Region(),
- npt_loc,
- Instruction::VECTOR);
-
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
-
- Text rgn2 = elem->Region();
- List<CombatZone>& zones = campaign->GetZones();
- if (zones[zones.size()-1]->HasRegion(rgn2))
- rgn2 = *zones[0]->GetRegions()[0];
- else
- rgn2 = *zones[zones.size()-1]->GetRegions()[0];
-
- n = new(__FILE__,__LINE__) Instruction(rgn2,
- Point(0, 0, 0),
- Instruction::VECTOR);
-
- if (n) {
- n->SetSpeed(750);
- elem->AddNavPoint(n);
- }
-}
-
-void
-CampaignMissionFighter::CreateWardShuttle()
-{
- if (!mission || !mission->GetStarSystem()) return;
-
- CombatUnit* carrier = FindCarrier(squadron);
- CombatGroup* shuttle = campaign->FindGroup(ownside, CombatGroup::LCA_SQUADRON);
-
- if (!shuttle || shuttle->CalcValue() < 1) return;
-
- List<CombatUnit>& units = shuttle->GetUnits();
-
- MissionElement* elem = CreateFighterPackage(shuttle, 1, Mission::CARGO);
- if (!elem) return;
-
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(orb_region);
- elem->Loadouts().destroy();
-
- if (carrier)
- elem->SetLocation(carrier->Location() + RandomPoint() * 2);
-
- ward = elem;
- mission->AddElement(elem);
-
- // if there is terrain nearby, then have the shuttle fly down to it:
- if (air_region.length() > 0) {
- StarSystem* system = mission->GetStarSystem();
- OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
- Point delta = rgn1->Location() - rgn1->Primary()->Location();
- Point npt_loc = elem->Location();
- Instruction* n = 0;
-
- delta.Normalize();
- delta *= -200.0e3;
-
- npt_loc += delta;
-
- n = new(__FILE__,__LINE__) Instruction(elem->Region(),
- npt_loc,
- Instruction::VECTOR);
-
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
-
- n = new(__FILE__,__LINE__) Instruction(air_region,
- Point(0, 0, 10.0e3),
- Instruction::VECTOR);
-
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
- }
-
- // otherwise, escort the shuttle in for a landing on the carrier:
- else if (carrier) {
- Point src = carrier->Location() + RandomDirection() * 150e3;
- Point dst = carrier->Location() + RandomDirection() * 25e3;
- Instruction* n = 0;
-
- elem->SetLocation(src);
-
- n = new(__FILE__,__LINE__) Instruction(elem->Region(), dst, Instruction::DOCK);
- if (n) {
- n->SetTarget(carrier->Name());
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
- }
-}
-
-void
-CampaignMissionFighter::CreateWardStrike()
-{
- if (!mission || !mission->GetStarSystem()) return;
-
- CombatUnit* carrier = FindCarrier(squadron);
- CombatGroup* strike = strike_group;
-
- if (!strike || strike->CalcValue() < 1) return;
-
- List<CombatUnit>& units = strike->GetUnits();
-
- int type = Mission::ASSAULT;
-
- if (airborne)
- type = Mission::STRIKE;
-
- MissionElement* elem = CreateFighterPackage(strike, 2, type);
- if (!elem) return;
-
- if (strike->GetParent() == squadron->GetParent()) {
- Player* p = Player::GetCurrentPlayer();
- elem->SetAlert(p ? !p->FlyingStart() : true);
- }
-
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(squadron->GetRegion());
-
- if (strike_target) {
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, strike_target->Name());
-
- if (obj) {
- if (airborne)
- obj->SetAction(Instruction::STRIKE);
-
- elem->AddObjective(obj);
- }
- }
-
- ward = elem;
- mission->AddElement(elem);
-
-
- StarSystem* system = mission->GetStarSystem();
- OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
- Point delta = rgn1->Location() - rgn1->Primary()->Location();
- Point npt_loc = elem->Location();
- Instruction* n = 0;
-
- if (airborne) {
- delta.Normalize();
- delta *= -30.0e3;
- npt_loc += delta;
-
- n = new(__FILE__,__LINE__) Instruction(elem->Region(),
- npt_loc,
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
-
- npt_loc = Point(0, 0, 10.0e3);
-
- n = new(__FILE__,__LINE__) Instruction(air_region,
- npt_loc,
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
- }
-
- // IP:
- if (strike_target) {
- delta = strike_target->Location() - npt_loc;
- delta.Normalize();
- delta *= 15.0e3;
-
- npt_loc = strike_target->Location() + delta + Point(0, 0, 8.0e3);
-
- n = new(__FILE__,__LINE__) Instruction(strike_target->GetRegion(),
- npt_loc,
- Instruction::STRIKE);
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
- }
-
- if (airborne) {
- n = new(__FILE__,__LINE__) Instruction(air_region,
- Point(0, 0, 30.0e3),
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
- }
-
- if (carrier) {
- n = new(__FILE__,__LINE__) Instruction(elem->Region(),
- carrier->Location() - Point(0, -20.0e3, 0),
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(500);
- elem->AddNavPoint(n);
- }
- }
-
- // find the strike target element:
- if (strike_target) {
- prime_target = mission->FindElement(strike_target->Name());
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateEscorts()
-{
- bool escort_needed = false;
-
- if (mission->Type() == Mission::STRIKE || mission->Type() == Mission::ASSAULT) {
- if (request && request->GetObjective()) {
- int tgt_type = request->GetObjective()->Type();
-
- if (tgt_type == CombatGroup::CARRIER_GROUP ||
- tgt_type == CombatGroup::STATION ||
- tgt_type == CombatGroup::STARBASE)
-
- escort_needed = true;
- }
- }
-
- if (player_elem && escort_needed) {
- CombatGroup* s = FindSquadron(ownside, CombatGroup::INTERCEPT_SQUADRON);
-
- if (s && s->IsAssignable()) {
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::ESCORT_STRIKE);
-
- if (elem) {
- Point offset = Point(2.0e3, 2.0e3, 1.0e3);
-
- ListIter<Instruction> npt_iter = player_elem->NavList();
- while (++npt_iter) {
- Instruction* npt = npt_iter.value();
- Instruction* n = new(__FILE__,__LINE__) Instruction(npt->RegionName(),
- npt->Location() + offset,
- Instruction::ESCORT);
- if (n) {
- n->SetSpeed(npt->Speed());
- elem->AddNavPoint(n);
- }
- }
-
- mission->AddElement(elem);
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateTargets()
-{
- switch (mission->Type()) {
- default:
- case Mission::DEFEND:
- case Mission::PATROL: CreateTargetsPatrol(); break;
- case Mission::SWEEP: CreateTargetsSweep(); break;
- case Mission::INTERCEPT: CreateTargetsIntercept(); break;
- case Mission::ESCORT_FREIGHT: CreateTargetsFreightEscort(); break;
-
- case Mission::ESCORT:
- case Mission::ESCORT_SHUTTLE: CreateTargetsShuttleEscort(); break;
- case Mission::ESCORT_STRIKE: CreateTargetsStrikeEscort(); break;
- case Mission::STRIKE: CreateTargetsStrike(); break;
- case Mission::ASSAULT: CreateTargetsAssault(); break;
- }
-}
-
-void
-CampaignMissionFighter::CreateTargetsPatrol()
-{
- if (!squadron || !player_elem) return;
-
- Text region = squadron->GetRegion();
- Point base_loc = player_elem->Location();
- Point patrol_loc;
-
- if (airborne)
- base_loc = RandomPoint() * 2 + Point(0, 0, 12.0e3);
-
- else if (carrier_elem)
- base_loc = carrier_elem->Location();
-
- if (airborne) {
- if (!airbase)
- PlanetaryInsertion(player_elem);
- region = air_region;
- patrol_loc = base_loc +
- RandomDirection() * Random( 60e3, 100e3);
- }
- else {
- patrol_loc = base_loc +
- RandomDirection() * Random(110e3, 160e3);
- }
-
- Instruction* n = new(__FILE__,__LINE__) Instruction(region,
- patrol_loc,
- Instruction::PATROL);
- if (n)
- player_elem->AddNavPoint(n);
-
- int ntargets = (int) Random(2.0,5.1);
-
- while (ntargets > 0) {
- int t = CreateRandomTarget(region, patrol_loc);
- ntargets -= t;
- if (t < 1) break;
- }
-
- if (airborne && !airbase) {
- OrbitalInsertion(player_elem);
- }
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(*n);
- obj->SetTargetDesc("inbound enemy units");
- player_elem->AddObjective(obj);
-
- if (carrier_elem && !airborne) {
- obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier_elem->Name());
- if (obj) {
- obj->SetTargetDesc(Text("the ") + carrier_elem->Name() + " battle group");
- player_elem->AddObjective(obj);
- }
- }
-}
-
-void
-CampaignMissionFighter::CreateTargetsSweep()
-{
- if (!squadron || !player_elem) return;
-
- double traverse = PI;
- double a = Random(-PI/2, PI/2);
- Point base_loc = player_elem->Location();
- Point sweep_loc = base_loc;
- Text region = player_elem->Region();
- Instruction* n = 0;
-
- if (carrier_elem)
- base_loc = carrier_elem->Location();
-
- if (airborne) {
- PlanetaryInsertion(player_elem);
- region = air_region;
- sweep_loc = RandomPoint() + Point(0, 0, 10.0e3); // keep it airborne!
- }
-
- sweep_loc += Point(sin(a), -cos(a), 0) * 100.0e3;
-
- n = new(__FILE__,__LINE__) Instruction(region,
- sweep_loc,
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- player_elem->AddNavPoint(n);
- }
-
- int index = 0;
- int ntargets = 6;
-
- while (traverse > 0) {
- double a1 = Random(PI/4, PI/2);
- traverse -= a1;
- a += a1;
-
- sweep_loc += Point(sin(a), -cos(a), 0) * 80.0e3;
-
- n = new(__FILE__,__LINE__) Instruction(region,
- sweep_loc,
- Instruction::SWEEP);
- if (n) {
- n->SetSpeed(750);
- n->SetFormation(Instruction::SPREAD);
- player_elem->AddNavPoint(n);
- }
-
- if (ntargets && RandomChance()) {
- ntargets -= CreateRandomTarget(region, sweep_loc);
- }
-
- index++;
- }
-
- if (ntargets > 0)
- CreateRandomTarget(region, sweep_loc);
-
- if (airborne && !airbase) {
- OrbitalInsertion(player_elem);
- region = player_elem->Region();
- }
-
- sweep_loc = base_loc;
- sweep_loc.y += 30.0e3;
-
- n = new(__FILE__,__LINE__) Instruction(region,
- sweep_loc,
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- player_elem->AddNavPoint(n);
- }
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(region,
- sweep_loc,
- Instruction::SWEEP);
- if (obj) {
- obj->SetTargetDesc("enemy patrols");
- player_elem->AddObjective(obj);
- }
-
- if (carrier_elem && !airborne) {
- obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier_elem->Name());
- if (obj) {
- obj->SetTargetDesc(Text("the ") + carrier_elem->Name() + " battle group");
- player_elem->AddObjective(obj);
- }
- }
-}
-
-void
-CampaignMissionFighter::CreateTargetsIntercept()
-{
- if (!squadron || !player_elem) return;
-
- CombatUnit* carrier = FindCarrier(squadron);
- CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON);
- CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON);
-
- if (!s || !s2) return;
-
- int ninbound = 2 + (int) (RandomIndex() < 5);
- bool second = ninbound > 2;
- Text attacker;
-
- while (ninbound--) {
- MissionElement* elem = CreateFighterPackage(s, 4, Mission::ASSAULT);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->Loadouts().destroy();
- elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Hvy Ship Strike"));
-
- if (carrier) {
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, carrier->Name());
- if (obj) {
- elem->AddObjective(obj);
- elem->SetLocation(carrier->Location() + RandomPoint() * 6);
- }
- }
- else {
- elem->SetLocation(squadron->Location() + RandomPoint() * 5);
- }
-
- mission->AddElement(elem);
-
- attacker = elem->Name();
-
- if (!prime_target) {
- prime_target = elem;
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::INTERCEPT, attacker);
- if (obj) {
- obj->SetTargetDesc(Text("inbound strike package '") + elem->Name() + "'");
- player_elem->AddObjective(obj);
- }
- }
-
- MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT);
- if (e2) {
- e2->SetIntelLevel(Intel::KNOWN);
- e2->SetLocation(elem->Location() + RandomPoint() * 0.25);
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
- if (obj)
- e2->AddObjective(obj);
- mission->AddElement(e2);
- }
- }
- }
-
- if (second) {
- // second friendly fighter package
- CombatGroup* s = FindSquadron(ownside, CombatGroup::FIGHTER_SQUADRON);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::INTERCEPT);
- if (elem) {
- Player* p = Player::GetCurrentPlayer();
- elem->SetAlert(p ? !p->FlyingStart() : true);
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::INTERCEPT, attacker);
- if (obj)
- elem->AddObjective(obj);
- mission->AddElement(elem);
- }
- }
- }
-
- if (carrier && !airborne) {
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier->Name());
- if (obj) {
- obj->SetTargetDesc(Text("the ") + carrier->Name() + " battle group");
- player_elem->AddObjective(obj);
- }
- }
-}
-
-void
-CampaignMissionFighter::CreateTargetsFreightEscort()
-{
- if (!squadron || !player_elem) return;
-
- if (!ward) {
- CreateTargetsPatrol();
- return;
- }
-
- CombatUnit* carrier = FindCarrier(squadron);
- CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON);
- CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON);
-
- if (!s) s = s2;
-
- if (!s || !s2) return;
-
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::ASSAULT);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
-
- elem->SetLocation(ward->Location() + RandomPoint() * 5);
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, ward->Name());
- if (obj)
- elem->AddObjective(obj);
- mission->AddElement(elem);
-
- MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT);
- if (e2) {
- e2->SetIntelLevel(Intel::KNOWN);
- e2->SetLocation(elem->Location() + RandomPoint() * 0.25);
-
- Instruction* obj2 = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
- if (obj2)
- e2->AddObjective(obj2);
- mission->AddElement(e2);
- }
- }
-
- Instruction* obj3 = new(__FILE__,__LINE__) Instruction(mission->GetRegion(),
- Point(0,0,0),
- Instruction::PATROL);
-
- if (obj3) {
- obj3->SetTargetDesc("enemy patrols");
- player_elem->AddObjective(obj3);
- }
-}
-
-void
-CampaignMissionFighter::CreateTargetsShuttleEscort()
-{
- CreateTargetsFreightEscort();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateTargetsStrikeEscort()
-{
- if (!squadron || !player_elem) return;
-
- if (ward) {
- Point offset = Point(2.0e3, 2.0e3, 1.0e3);
-
- ListIter<Instruction> npt_iter = ward->NavList();
- while (++npt_iter) {
- Instruction* npt = npt_iter.value();
- Instruction* n = new(__FILE__,__LINE__) Instruction(npt->RegionName(),
- npt->Location() + offset,
- Instruction::ESCORT);
- if (n) {
- n->SetSpeed(npt->Speed());
- player_elem->AddNavPoint(n);
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateTargetsStrike()
-{
- if (!squadron || !player_elem) return;
-
- if (request && request->GetObjective())
- strike_target = request->GetObjective();
-
- if (strike_target && strike_group) {
- CreateElements(strike_target);
-
- ListIter<MissionElement> e_iter = mission->GetElements();
- while (++e_iter) {
- MissionElement* elem = e_iter.value();
-
- if (elem->GetCombatGroup() == strike_target) {
- prime_target = elem;
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::STRIKE, elem->Name());
- if (obj) {
- obj->SetTargetDesc(Text("preplanned target '") + elem->Name() + "'");
- player_elem->AddObjective(obj);
- }
-
- // create flight plan:
- RLoc rloc;
- Point loc = Point(0, 0, 15e3);
- Instruction* n = 0;
-
- PlanetaryInsertion(player_elem);
-
- // target approach and strike:
- Point delta = prime_target->Location() - loc;
-
- if (delta.length() >= 100e3) {
- Point mid = loc + delta * 0.5;
- mid.z = 10.0e3;
-
- rloc.SetReferenceLoc(0);
- rloc.SetBaseLocation(mid);
- rloc.SetDistance(20e3);
- rloc.SetDistanceVar(5e3);
- rloc.SetAzimuth(90*DEGREES);
- rloc.SetAzimuthVar(25*DEGREES);
-
- n = new(__FILE__,__LINE__) Instruction(prime_target->Region(),
- Point(),
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- n->GetRLoc() = rloc;
- player_elem->AddNavPoint(n);
- }
-
- loc = mid;
- }
-
- delta = loc - prime_target->Location();
- delta.Normalize();
- delta *= 25.0e3;
-
- loc = prime_target->Location() + delta;
- loc.z = 8.0e3;
-
- n = new(__FILE__,__LINE__) Instruction(prime_target->Region(),
- loc,
- Instruction::STRIKE);
- if (n) {
- n->SetSpeed(500);
- player_elem->AddNavPoint(n);
- }
-
- // exeunt:
- rloc.SetReferenceLoc(0);
- rloc.SetBaseLocation(Point(0, 0, 30.0e3));
- rloc.SetDistance(50e3);
- rloc.SetDistanceVar(5e3);
- rloc.SetAzimuth(-90*DEGREES);
- rloc.SetAzimuthVar(25*DEGREES);
-
- n = new(__FILE__,__LINE__) Instruction(prime_target->Region(),
- Point(),
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- n->GetRLoc() = rloc;
- player_elem->AddNavPoint(n);
- }
-
- if (carrier_elem) {
- rloc.SetReferenceLoc(0);
- rloc.SetBaseLocation(carrier_elem->Location());
- rloc.SetDistance(60e3);
- rloc.SetDistanceVar(10e3);
- rloc.SetAzimuth(180*DEGREES);
- rloc.SetAzimuthVar(30*DEGREES);
-
- n = new(__FILE__,__LINE__) Instruction(carrier_elem->Region(),
- Point(),
- Instruction::RTB);
- if (n) {
- n->SetSpeed(750);
- n->GetRLoc() = rloc;
- player_elem->AddNavPoint(n);
- }
- }
-
- break;
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::CreateTargetsAssault()
-{
- if (!squadron || !player_elem) return;
-
- CombatGroup* assigned = 0;
-
- if (request)
- assigned = request->GetObjective();
-
- if (assigned) {
- if (assigned->Type() > CombatGroup::WING && assigned->Type() < CombatGroup::FLEET) {
- mission->AddElement(CreateFighterPackage(assigned, 2, Mission::CARGO));
- }
- else {
- CreateElements(assigned);
- }
-
- // select the prime target element - choose the lowest ranking
- // unit of a DESRON, CBG, or CVBG:
-
- ListIter<MissionElement> e_iter = mission->GetElements();
- while (++e_iter) {
- MissionElement* elem = e_iter.value();
-
- if (elem->GetCombatGroup() == assigned) {
- if (!prime_target || assigned->Type() <= CombatGroup::CARRIER_GROUP) {
- prime_target = elem;
- }
- }
- }
-
- if (prime_target) {
- MissionElement* elem = prime_target;
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, elem->Name());
- if (obj) {
- obj->SetTargetDesc(Text("preplanned target '") + elem->Name() + "'");
- player_elem->AddObjective(obj);
- }
-
- // create flight plan:
- RLoc rloc;
- Vec3 dummy(0,0,0);
- Instruction* instr = 0;
- Point loc = player_elem->Location();
- Point tgt = elem->Location();
- Point mid;
-
- CombatGroup* tgt_group = elem->GetCombatGroup();
- if (tgt_group && tgt_group->GetFirstUnit() && tgt_group->IsMovable()) {
- tgt = tgt_group->GetFirstUnit()->Location();
- }
-
- if (carrier_elem)
- loc = carrier_elem->Location();
-
- mid = loc + (elem->Location() - loc) * 0.5;
-
- rloc.SetReferenceLoc(0);
- rloc.SetBaseLocation(mid);
- rloc.SetDistance(40e3);
- rloc.SetDistanceVar(5e3);
- rloc.SetAzimuth(90*DEGREES);
- rloc.SetAzimuthVar(45*DEGREES);
-
- instr = new(__FILE__,__LINE__) Instruction(elem->Region(), dummy, Instruction::VECTOR);
- if (instr) {
- instr->SetSpeed(750);
- instr->GetRLoc() = rloc;
-
- player_elem->AddNavPoint(instr);
-
- if (RandomChance()) {
- CreateRandomTarget(elem->Region(), rloc.Location());
- }
- }
-
- rloc.SetReferenceLoc(0);
- rloc.SetBaseLocation(tgt);
- rloc.SetDistance(60e3);
- rloc.SetDistanceVar(5e3);
- rloc.SetAzimuth(120*DEGREES);
- rloc.SetAzimuthVar(15*DEGREES);
-
- instr = new(__FILE__,__LINE__) Instruction(elem->Region(), dummy, Instruction::ASSAULT);
- if (instr) {
- instr->SetSpeed(750);
- instr->GetRLoc() = rloc;
- instr->SetTarget(elem->Name());
-
- player_elem->AddNavPoint(instr);
- }
-
- if (carrier_elem) {
- rloc.SetReferenceLoc(0);
- rloc.SetBaseLocation(loc);
- rloc.SetDistance(30e3);
- rloc.SetDistanceVar(0);
- rloc.SetAzimuth(180*DEGREES);
- rloc.SetAzimuthVar(60*DEGREES);
-
- instr = new(__FILE__,__LINE__) Instruction(carrier_elem->Region(), dummy, Instruction::RTB);
- if (instr) {
- instr->SetSpeed(500);
- instr->GetRLoc() = rloc;
-
- player_elem->AddNavPoint(instr);
- }
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-int
-CampaignMissionFighter::CreateRandomTarget(const char* rgn, Point base_loc)
-{
- if (!mission) return 0;
-
- int ntargets = 0;
- int ttype = RandomIndex();
- bool oca = (mission->Type() == Mission::SWEEP);
-
- if (ttype < 8) {
- CombatGroup* s = 0;
-
- if (ttype < 4)
- s = FindSquadron(enemy, CombatGroup::INTERCEPT_SQUADRON);
- else
- s = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::SWEEP);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(rgn);
- elem->SetLocation(base_loc + RandomPoint() * 1.5);
- mission->AddElement(elem);
- ntargets++;
- }
- }
- }
- else if (ttype < 12) {
- if (oca) {
- CombatGroup* s = FindSquadron(enemy, CombatGroup::LCA_SQUADRON);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 1, Mission::CARGO);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(rgn);
- elem->SetLocation(base_loc + RandomPoint() * 2);
- mission->AddElement(elem);
- ntargets++;
-
- CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON);
-
- if (s2) {
- MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT);
- if (e2) {
- e2->SetIntelLevel(Intel::KNOWN);
- e2->SetRegion(rgn);
- e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
- if (obj)
- e2->AddObjective(obj);
- mission->AddElement(e2);
- ntargets++;
- }
- }
- }
- }
- }
- else {
- CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::ASSAULT);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(rgn);
- elem->SetLocation(base_loc + RandomPoint() * 1.3);
- mission->AddElement(elem);
- ntargets++;
- }
- }
- }
- }
- else if (ttype < 15) {
- if (oca) {
- CombatGroup* s = 0;
-
- if (airborne)
- s = FindSquadron(enemy, CombatGroup::LCA_SQUADRON);
- else
- s = FindSquadron(enemy, CombatGroup::FREIGHT);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 1, Mission::CARGO);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(rgn);
- elem->SetLocation(base_loc + RandomPoint() * 2);
- mission->AddElement(elem);
- ntargets++;
-
- CombatGroup* s2 = FindSquadron(enemy, CombatGroup::INTERCEPT_SQUADRON);
-
- if (s2) {
- MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT);
- if (e2) {
- e2->SetIntelLevel(Intel::KNOWN);
- e2->SetRegion(rgn);
- e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
- if (obj)
- e2->AddObjective(obj);
- mission->AddElement(e2);
- ntargets++;
- }
- }
- }
- }
- }
- else {
- CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::ASSAULT);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(rgn);
- elem->SetLocation(base_loc + RandomPoint() * 1.1);
- mission->AddElement(elem);
- ntargets++;
-
- CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON);
-
- if (s2) {
- MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT);
- if (e2) {
- e2->SetIntelLevel(Intel::KNOWN);
- e2->SetRegion(rgn);
- e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
-
- Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
- if (obj)
- e2->AddObjective(obj);
- mission->AddElement(e2);
- ntargets++;
- }
- }
- }
- }
- }
- }
- else {
- CombatGroup* s = FindSquadron(enemy, CombatGroup::LCA_SQUADRON);
-
- if (s) {
- MissionElement* elem = CreateFighterPackage(s, 2, Mission::CARGO);
- if (elem) {
- elem->SetIntelLevel(Intel::KNOWN);
- elem->SetRegion(rgn);
- elem->SetLocation(base_loc + RandomPoint() * 2);
- mission->AddElement(elem);
- ntargets++;
- }
- }
- }
-
- return ntargets;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::PlanetaryInsertion(MissionElement* elem)
-{
- if (!mission || !elem) return;
- if (!mission->GetStarSystem()) return;
-
- MissionElement* carrier = mission->FindElement(elem->Commander());
- StarSystem* system = mission->GetStarSystem();
- OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
- OrbitalRegion* rgn2 = system->FindRegion(air_region);
- Point npt_loc = elem->Location();
- Instruction* n = 0;
- Player* p = Player::GetCurrentPlayer();
-
- int flying_start = p ? p->FlyingStart() : 0;
-
- if (carrier && !flying_start) {
- npt_loc = carrier->Location() + Point(1e3, -5e3, 0);
- }
-
- if (rgn1 && rgn2) {
- double delta_t = mission->Start() - campaign->GetTime();
- Point r1 = rgn1->PredictLocation(delta_t);
- Point r2 = rgn2->PredictLocation(delta_t);
-
- Point delta = r2 - r1;
-
- delta.y *= -1;
- delta.Normalize();
- delta *= 10e3;
-
- npt_loc += delta;
-
- n = new(__FILE__,__LINE__) Instruction(elem->Region(),
- npt_loc,
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- elem->AddNavPoint(n);
- }
- }
-
- n = new(__FILE__,__LINE__) Instruction(air_region,
- Point(0, 0, 15e3),
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- elem->AddNavPoint(n);
- }
-}
-
-void
-CampaignMissionFighter::OrbitalInsertion(MissionElement* elem)
-{
- Instruction* n = new(__FILE__,__LINE__) Instruction(air_region,
- Point(0, 0, 30.0e3),
- Instruction::VECTOR);
- if (n) {
- n->SetSpeed(750);
- elem->AddNavPoint(n);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-MissionElement*
-CampaignMissionFighter::CreateFighterPackage(CombatGroup* squadron, int count, int role)
-{
- if (!squadron) return 0;
-
- CombatUnit* fighter = squadron->GetUnits().at(0);
- CombatUnit* carrier = FindCarrier(squadron);
-
- if (!fighter)
- return 0;
-
- int avail = fighter->LiveCount();
- int actual = count;
-
- if (avail < actual)
- actual = avail;
-
- if (avail < 1) {
- ::Print("CMF - Insufficient fighters in squadron '%s' - %d required, %d available\n",
- squadron->Name().data(), count, avail);
- return 0;
- }
-
- MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
- if (!elem) {
- Exit();
- return 0;
- }
-
- elem->SetName(Callsign::GetCallsign(fighter->GetIFF()));
- elem->SetElementID(pkg_id++);
-
- if (carrier) {
- elem->SetCommander(carrier->Name());
- elem->SetHeading(carrier->GetHeading());
- }
- else {
- elem->SetHeading(fighter->GetHeading());
- }
-
- elem->SetDesign(fighter->GetDesign());
- elem->SetCount(actual);
- elem->SetIFF(fighter->GetIFF());
- elem->SetIntelLevel(squadron->IntelLevel());
- elem->SetRegion(fighter->GetRegion());
- elem->SetSquadron(squadron->Name());
- elem->SetMissionRole(role);
-
- switch (role) {
- case Mission::ASSAULT:
- if (request->GetObjective() &&
- request->GetObjective()->Type() == CombatGroup::MINEFIELD)
- elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Rockets"));
- else
- elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ship Strike"));
- break;
-
- case Mission::STRIKE:
- elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ground Strike"));
- break;
-
- default:
- elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "ACM Medium Range"));
- break;
- }
-
- if (carrier) {
- Point offset = RandomPoint() * 0.3;
- offset.y = fabs(offset.y);
- offset.z += 2e3;
- elem->SetLocation(carrier->Location() + offset);
- }
- else {
- elem->SetLocation(fighter->Location() + RandomPoint());
- }
-
- elem->SetCombatGroup(squadron);
- elem->SetCombatUnit(fighter);
-
- return elem;
-}
-
-// +--------------------------------------------------------------------+
-
-static CombatGroup* FindCombatGroup(CombatGroup* g, int type)
-{
- if (g->IntelLevel() <= Intel::RESERVE)
- return 0;
-
- if (g->GetUnits().size() > 0) {
- for (int i = 0; i < g->GetUnits().size(); i++) {
- CombatUnit* u = g->GetUnits().at(i);
- if (g->Type() == type && u->LiveCount() > 0)
- return g;
- }
- }
-
- CombatGroup* result = 0;
-
- ListIter<CombatGroup> subgroup = g->GetComponents();
- while (++subgroup && !result)
- result = FindCombatGroup(subgroup.value(), type);
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-CombatGroup*
-CampaignMissionFighter::FindSquadron(int iff, int type)
-{
- if (!squadron) return 0;
-
- CombatGroup* result = 0;
- Campaign* campaign = Campaign::GetCampaign();
-
- if (campaign) {
- ListIter<Combatant> combatant = campaign->GetCombatants();
- while (++combatant && !result) {
- if (combatant->GetIFF() == iff) {
- result = ::FindCombatGroup(combatant->GetForce(), type);
-
- if (result && result->CountUnits() < 1) {
- result = 0;
- }
- }
- }
- }
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::DefineMissionObjectives()
-{
- if (!mission || !player_elem) return;
-
- if (prime_target) mission->SetTarget(prime_target);
- if (ward) mission->SetWard(ward);
-
- Text objectives;
-
- for (int i = 0; i < player_elem->Objectives().size(); i++) {
- Instruction* obj = player_elem->Objectives().at(i);
- objectives += "* ";
- objectives += obj->GetDescription();
- objectives += ".\n";
- }
-
- mission->SetObjective(objectives);
-}
-
-// +--------------------------------------------------------------------+
-
-MissionInfo*
-CampaignMissionFighter::DescribeMission()
-{
- if (!mission || !player_elem) return 0;
-
- char name[256];
- char player_info[256];
-
- if (mission_info && mission_info->name.length())
- sprintf_s(name, "MSN-%03d %s", mission->Identity(), mission_info->name.data());
- else if (ward)
- sprintf_s(name, "MSN-%03d %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(), ward->Name().data());
- else if (prime_target)
- sprintf_s(name, "MSN-%03d %s %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(),
- Ship::ClassName(prime_target->GetDesign()->type),
- prime_target->Name().data());
- else
- sprintf_s(name, "MSN-%03d %s", mission->Identity(), Game::GetText(mission->TypeName()).data());
-
- if (player_elem) {
- sprintf_s(player_info, "%d x %s %s '%s'",
- player_elem->Count(),
- (const char*) player_elem->GetDesign()->abrv,
- (const char*) player_elem->GetDesign()->name,
- (const char*) player_elem->Name());
- }
-
- MissionInfo* info = new(__FILE__,__LINE__) MissionInfo;
-
- info->id = mission->Identity();
- info->mission = mission;
- info->name = name;
- info->type = mission->Type();
- info->player_info = player_info;
- info->description = mission->Objective();
- info->start = mission->Start();
-
- if (mission->GetStarSystem())
- info->system = mission->GetStarSystem()->Name();
- info->region = mission->GetRegion();
-
- mission->SetName(name);
-
- return info;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-CampaignMissionFighter::Exit()
-{
- Starshatter* stars = Starshatter::GetInstance();
- if (stars)
- stars->SetGameMode(Starshatter::MENU_MODE);
-}
+/* Starshatter OpenSource Distribution + Copyright (c) 1997-2004, Destroyer Studios LLC. + All Rights Reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name "Destroyer Studios" nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + + SUBSYSTEM: Stars.exe + FILE: CampaignMissionFighter.cpp + AUTHOR: John DiCamillo + + + OVERVIEW + ======== + CampaignMissionFighter generates missions and mission + info for the player's FIGHTER SQUADRON as part of a + dynamic campaign. +*/ + +#include "MemDebug.h" +#include "CampaignMissionFighter.h" +#include "CampaignMissionRequest.h" +#include "Campaign.h" +#include "Combatant.h" +#include "CombatAssignment.h" +#include "CombatGroup.h" +#include "CombatUnit.h" +#include "CombatZone.h" +#include "Callsign.h" +#include "Galaxy.h" +#include "Mission.h" +#include "MissionTemplate.h" +#include "Instruction.h" +#include "Ship.h" +#include "ShipDesign.h" +#include "Starshatter.h" +#include "StarSystem.h" +#include "Player.h" + +#include "Random.h" + +static int pkg_id = 1000; +extern int dump_missions; + +// +--------------------------------------------------------------------+ + +CampaignMissionFighter::CampaignMissionFighter(Campaign* c) + : campaign(c), squadron(0), mission(0), player_elem(0), + strike_group(0), strike_target(0), prime_target(0), + carrier_elem(0), ward(0), escort(0), airborne(false), airbase(false), + ownside(0), enemy(-1), mission_type(0), mission_info(0) +{ + if (!campaign || !campaign->GetPlayerGroup()) { + ::Print("ERROR - CMF campaign=0x%08x player_group=0x%08x\n", + campaign, (DWORD) campaign?campaign->GetPlayerGroup():0); + return; + } + + CombatGroup* player_group = campaign->GetPlayerGroup(); + + switch (player_group->Type()) { + case CombatGroup::WING: { + CombatGroup* wing = player_group; + ListIter<CombatGroup> iter = wing->GetComponents(); + + while (++iter) { + if (iter->Type() == CombatGroup::FIGHTER_SQUADRON) { + squadron = iter.value(); + } + } + } + break; + + case CombatGroup::FIGHTER_SQUADRON: + case CombatGroup::INTERCEPT_SQUADRON: + case CombatGroup::ATTACK_SQUADRON: + squadron = player_group; + break; + + default: + ::Print("ERROR - CMF invalid player group: %s IFF %d\n", + player_group->GetDescription(), + player_group->GetIFF()); + break; + } + + if (squadron) { + CombatGroup* carrier = squadron->FindCarrier(); + + if (carrier && carrier->Type() == CombatGroup::STARBASE) { + airbase = true; + } + } +} + +CampaignMissionFighter::~CampaignMissionFighter() {} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateMission(CampaignMissionRequest* req) +{ + if (!campaign || !squadron || !req) + return; + + ::Print("\n-----------------------------------------------\n"); + if (req->Script().length()) + ::Print("CMF CreateMission() request: %s '%s'\n", + Mission::RoleName(req->Type()), + (const char*) req->Script()); + + else + ::Print("CMF CreateMission() request: %s %s\n", + Mission::RoleName(req->Type()), + req->GetObjective() ? req->GetObjective()->Name().data() : "(no target)"); + + request = req; + mission_info = 0; + + if (request->GetPrimaryGroup()) { + switch (request->GetPrimaryGroup()->Type()) { + case CombatGroup::FIGHTER_SQUADRON: + case CombatGroup::INTERCEPT_SQUADRON: + case CombatGroup::ATTACK_SQUADRON: + squadron = request->GetPrimaryGroup(); + break; + } + } + + ownside = squadron->GetIFF(); + + for (int i = 0; i < campaign->GetCombatants().size(); i++) { + int iff = campaign->GetCombatants().at(i)->GetIFF(); + if (iff > 0 && iff != ownside) { + enemy = iff; + break; + } + } + + static int id_key = 1; + GenerateMission(id_key++); + DefineMissionObjectives(); + + MissionInfo* info = DescribeMission(); + + if (info) { + campaign->GetMissionList().append(info); + + ::Print("CMF Created %03d '%s' %s\n\n", + info->id, + (const char*) info->name, + Mission::RoleName(mission->Type())); + + if (dump_missions) { + Text script = mission->Serialize(); + char fname[32]; + + sprintf_s(fname, "msn%03d.def", info->id); + FILE* f; + fopen_s(&f, fname, "w"); + if (f) { + fprintf(f, "%s\n", script.data()); + fclose(f); + } + } + } + else { + ::Print("CMF failed to create mission.\n"); + } +} + +// +--------------------------------------------------------------------+ + +Mission* +CampaignMissionFighter::GenerateMission(int id) +{ + bool found = false; + + SelectType(); + + if (request && request->Script().length()) { + MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, request->Script(), campaign->Path()); + if (mt) + mt->SetPlayerSquadron(squadron); + mission = mt; + found = true; + } + + else { + mission_info = campaign->FindMissionTemplate(mission_type, squadron); + found = mission_info != 0; + + if (found) { + MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, mission_info->script, campaign->Path()); + if (mt) + mt->SetPlayerSquadron(squadron); + mission = mt; + } + else { + mission = new(__FILE__,__LINE__) Mission(id); + if (mission) + mission->SetType(mission_type); + } + } + + if (!mission) { + Exit(); + return 0; + } + + char name[64]; + sprintf_s(name, "Fighter Mission %d", id); + + mission->SetName(name); + mission->SetTeam(squadron->GetIFF()); + mission->SetStart(request->StartTime()); + + SelectRegion(); + GenerateStandardElements(); + CreatePatrols(); + + if (!found) { + GenerateMissionElements(); + mission->SetOK(true); + mission->Validate(); + } + + else { + mission->Load(); + + if (mission->IsOK()) { + player_elem = mission->GetPlayer(); + prime_target = mission->GetTarget(); + ward = mission->GetWard(); + + Player* p = Player::GetCurrentPlayer(); + + if (player_elem && p) + player_elem->SetAlert(!p->FlyingStart()); + } + + // if there was a problem, scrap the mission + // and start over: + else { + delete mission; + + mission = new(__FILE__,__LINE__) Mission(id); + mission->SetType(mission_type); + mission->SetName(name); + mission->SetTeam(squadron->GetIFF()); + mission->SetStart(request->StartTime()); + + SelectRegion(); + GenerateStandardElements(); + GenerateMissionElements(); + + mission->SetOK(true); + mission->Validate(); + } + } + + return mission; +} + +// +--------------------------------------------------------------------+ + +bool +CampaignMissionFighter::IsGroundObjective(CombatGroup* obj) +{ + bool ground = false; + + if (obj) { + CombatGroup* pgroup = campaign->GetPlayerGroup(); + + if (pgroup) { + CombatZone* zone = pgroup->GetAssignedZone(); + + if (zone) { + StarSystem* system = campaign->GetSystem(zone->System()); + + if (system) { + OrbitalRegion* region = system->FindRegion(obj->GetRegion()); + + if (region && region->Type() == Orbital::TERRAIN) { + ground = true; + } + } + } + } + } + + return ground; +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::SelectType() +{ + int type = Mission::PATROL; + + if (request) { + type = request->Type(); + if (type == Mission::STRIKE) { + strike_group = request->GetPrimaryGroup(); + + // verify that objective is a ground target: + if (!IsGroundObjective(request->GetObjective())) { + type = Mission::ASSAULT; + } + } + + else if (type == Mission::ESCORT_STRIKE) { + strike_group = request->GetSecondaryGroup(); + if (!strike_group || strike_group->CalcValue() < 1) { + type = Mission::SWEEP; + strike_group = 0; + } + } + } + + mission_type = type; +} + +void +CampaignMissionFighter::SelectRegion() +{ + CombatZone* zone = squadron->GetAssignedZone(); + + if (!zone) + zone = squadron->GetCurrentZone(); + + if (zone) { + mission->SetStarSystem(campaign->GetSystem(zone->System())); + mission->SetRegion(*zone->GetRegions().at(0)); + + orb_region = mission->GetRegion(); + + if (zone->GetRegions().size() > 1) { + air_region = *zone->GetRegions().at(1); + + StarSystem* system = mission->GetStarSystem(); + OrbitalRegion* rgn = 0; + + if (system) + rgn = system->FindRegion(air_region); + + if (!rgn || rgn->Type() != Orbital::TERRAIN) + air_region = ""; + } + + if (air_region.length() > 0) { + if (request && IsGroundObjective(request->GetObjective())) { + airborne = true; + } + + else if (mission->Type() >= Mission::AIR_PATROL && + mission->Type() <= Mission::AIR_INTERCEPT) { + airborne = true; + } + + else if (mission->Type() == Mission::STRIKE || + mission->Type() == Mission::ESCORT_STRIKE) { + if (strike_group) { + strike_target = campaign->FindStrikeTarget(ownside, strike_group); + + if (strike_target && strike_target->GetRegion() == air_region) + airborne = true; + } + } + + if (airbase) { + mission->SetRegion(air_region); + } + } + } + + else { + ::Print("WARNING: CMF - No zone for '%s'\n", squadron->Name().data()); + + StarSystem* s = campaign->GetSystemList()[0]; + + mission->SetStarSystem(s); + mission->SetRegion(s->Regions()[0]->Name()); + } + + if (!airborne) { + switch (mission->Type()) { + case Mission::AIR_PATROL: mission->SetType(Mission::PATROL); break; + case Mission::AIR_SWEEP: mission->SetType(Mission::SWEEP); break; + case Mission::AIR_INTERCEPT: mission->SetType(Mission::INTERCEPT); break; + default: break; + } + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::GenerateStandardElements() +{ + ListIter<CombatZone> z_iter = campaign->GetZones(); + while (++z_iter) { + CombatZone* z = z_iter.value(); + + ListIter<ZoneForce> iter = z->GetForces(); + while (++iter) { + ZoneForce* force = iter.value(); + ListIter<CombatGroup> group = force->GetGroups(); + + while (++group) { + CombatGroup* g = group.value(); + + switch (g->Type()) { + case CombatGroup::INTERCEPT_SQUADRON: + case CombatGroup::FIGHTER_SQUADRON: + case CombatGroup::ATTACK_SQUADRON: + case CombatGroup::LCA_SQUADRON: + CreateSquadron(g); + break; + + case CombatGroup::DESTROYER_SQUADRON: + case CombatGroup::BATTLE_GROUP: + case CombatGroup::CARRIER_GROUP: + CreateElements(g); + break; + + case CombatGroup::MINEFIELD: + case CombatGroup::BATTERY: + case CombatGroup::MISSILE: + case CombatGroup::STATION: + case CombatGroup::STARBASE: + case CombatGroup::SUPPORT: + case CombatGroup::COURIER: + case CombatGroup::MEDICAL: + case CombatGroup::SUPPLY: + case CombatGroup::REPAIR: + CreateElements(g); + break; + + case CombatGroup::CIVILIAN: + case CombatGroup::WAR_PRODUCTION: + case CombatGroup::FACTORY: + case CombatGroup::REFINERY: + case CombatGroup::RESOURCE: + case CombatGroup::INFRASTRUCTURE: + case CombatGroup::TRANSPORT: + case CombatGroup::NETWORK: + case CombatGroup::HABITAT: + case CombatGroup::STORAGE: + case CombatGroup::NON_COM: + CreateElements(g); + break; + } + } + } + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::GenerateMissionElements() +{ + CreateWards(); + CreatePlayer(squadron); + CreateTargets(); + CreateEscorts(); + + if (player_elem) { + Instruction* obj = new(__FILE__,__LINE__) Instruction(mission->GetRegion(), + Point(0,0,0), + Instruction::RTB); + + if (obj) + player_elem->AddObjective(obj); + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateElements(CombatGroup* g) +{ + MissionElement* elem = 0; + List<CombatUnit>& units = g->GetUnits(); + + CombatUnit* cmdr = 0; + + for (int i = 0; i < units.size(); i++) { + elem = CreateSingleElement(g, units[i]); + + if (elem) { + if (!cmdr) { + cmdr = units[i]; + } + else { + elem->SetCommander(cmdr->Name()); + + if (g->Type() == CombatGroup::CARRIER_GROUP && + elem->MissionRole() == Mission::ESCORT) { + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, cmdr->Name()); + if (obj) + elem->AddObjective(obj); + } + } + + mission->AddElement(elem); + } + } +} + +MissionElement* +CampaignMissionFighter::CreateSingleElement(CombatGroup* g, CombatUnit* u) +{ + if (!g || g->IsReserve()) return 0; + if (!u || u->LiveCount() < 1) return 0; + + // make sure this unit is actually in the right star system: + Galaxy* galaxy = Galaxy::GetInstance(); + if (galaxy) { + if (galaxy->FindSystemByRegion(u->GetRegion()) != + galaxy->FindSystemByRegion(squadron->GetRegion())) { + return 0; + } + } + + // make sure this unit isn't already in the mission: + ListIter<MissionElement> e_iter = mission->GetElements(); + while (++e_iter) { + MissionElement* elem = e_iter.value(); + + if (elem->GetCombatUnit() == u) + return 0; + } + + MissionElement* elem = new(__FILE__,__LINE__) MissionElement; + if (!elem) { + Exit(); + return 0; + } + + if (u->Name().length()) + elem->SetName(u->Name()); + else + elem->SetName(u->DesignName()); + + elem->SetElementID(pkg_id++); + + elem->SetDesign(u->GetDesign()); + elem->SetCount(u->LiveCount()); + elem->SetIFF(u->GetIFF()); + elem->SetIntelLevel(g->IntelLevel()); + elem->SetRegion(u->GetRegion()); + elem->SetHeading(u->GetHeading()); + + int unit_index = g->GetUnits().index(u); + Point base_loc = u->Location(); + bool exact = u->IsStatic(); // exact unit-level placement + + if (base_loc.length() < 1) { + base_loc = g->Location(); + exact = false; + } + + if (unit_index < 0 || unit_index > 0 && !exact) { + Point loc = RandomDirection(); + + if (!u->IsStatic()) { + while (fabs(loc.y) > fabs(loc.x)) + loc = RandomDirection(); + + loc *= 10e3 + 9e3 * unit_index; + } + else { + loc *= 2e3 + 2e3 * unit_index; + } + + elem->SetLocation(base_loc + loc); + } + else { + elem->SetLocation(base_loc); + } + + if (g->Type() == CombatGroup::CARRIER_GROUP) { + if (u->Type() == Ship::CARRIER) { + elem->SetMissionRole(Mission::FLIGHT_OPS); + + if (squadron && elem->GetCombatGroup() == squadron->FindCarrier()) + carrier_elem = elem; + + else if (!carrier_elem && u->GetIFF() == squadron->GetIFF()) + carrier_elem = elem; + } + else { + elem->SetMissionRole(Mission::ESCORT); + } + } + else if (u->Type() == Ship::STATION || + u->Type() == Ship::STARBASE) { + elem->SetMissionRole(Mission::FLIGHT_OPS); + + if (squadron && elem->GetCombatGroup() == squadron->FindCarrier()) { + carrier_elem = elem; + + if (u->Type() == Ship::STARBASE) + airbase = true; + } + } + else if (u->Type() == Ship::FARCASTER) { + elem->SetMissionRole(Mission::OTHER); + + // link farcaster to other terminus: + Text name = u->Name(); + int dash = -1; + + for (int i = 0; i < (int) name.length(); i++) + if (name[i] == '-') + dash = i; + + Text src = name.substring(0, dash); + Text dst = name.substring(dash+1, name.length() - (dash+1)); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::VECTOR, dst + "-" + src); + elem->AddObjective(obj); + } + else if ((u->Type() & Ship::STARSHIPS) != 0) { + elem->SetMissionRole(Mission::FLEET); + } + + elem->SetCombatGroup(g); + elem->SetCombatUnit(u); + + return elem; +} + +CombatUnit* +CampaignMissionFighter::FindCarrier(CombatGroup* g) +{ + CombatGroup* carrier = g->FindCarrier(); + + if (carrier && carrier->GetUnits().size()) { + MissionElement* carrier_elem = mission->FindElement(carrier->Name()); + + if (carrier_elem) + return carrier->GetUnits().at(0); + } + + return 0; +} + +void +CampaignMissionFighter::CreateSquadron(CombatGroup* g) +{ + if (!g || g->IsReserve()) return; + + CombatUnit* fighter = g->GetUnits().at(0); + CombatUnit* carrier = FindCarrier(g); + + if (!fighter || !carrier) return; + + int live_count = fighter->LiveCount(); + int maint_count = (live_count > 4) ? live_count / 2 : 0; + + MissionElement* elem = new(__FILE__,__LINE__) MissionElement; + + if (!elem) { + Exit(); + return; + } + + elem->SetName(g->Name()); + elem->SetElementID(pkg_id++); + + elem->SetDesign(fighter->GetDesign()); + elem->SetCount(fighter->Count()); + elem->SetDeadCount(fighter->DeadCount()); + elem->SetMaintCount(maint_count); + elem->SetIFF(fighter->GetIFF()); + elem->SetIntelLevel(g->IntelLevel()); + elem->SetRegion(fighter->GetRegion()); + + elem->SetCarrier(carrier->Name()); + elem->SetCommander(carrier->Name()); + elem->SetLocation(carrier->Location() + RandomPoint()); + + elem->SetCombatGroup(g); + elem->SetCombatUnit(fighter); + + mission->AddElement(elem); +} + +void +CampaignMissionFighter::CreatePlayer(CombatGroup* g) +{ + int pkg_size = 2; + + if (mission->Type() == Mission::STRIKE || mission->Type() == Mission::ASSAULT) { + if (request && request->GetObjective()) { + int tgt_type = request->GetObjective()->Type(); + + if (tgt_type >= CombatGroup::FLEET && tgt_type <= CombatGroup::CARRIER_GROUP) + pkg_size = 4; + + if (tgt_type == CombatGroup::STATION || tgt_type == CombatGroup::STARBASE) + pkg_size = 4; + } + } + + MissionElement* elem = CreateFighterPackage(g, pkg_size, mission->Type()); + + if (elem) { + Player* p = Player::GetCurrentPlayer(); + elem->SetAlert(p ? !p->FlyingStart() : true); + elem->SetPlayer(1); + + if (ward) { + Point approach = elem->Location() - ward->Location(); + approach.Normalize(); + + Point pickup = ward->Location() + approach * 50e3; + double delta = (pickup - elem->Location()).length(); + + if (delta > 30e3) { + Instruction* n = new(__FILE__,__LINE__) Instruction(elem->Region(), pickup, Instruction::ESCORT); + n->SetTarget(ward->Name()); + n->SetSpeed(750); + elem->AddNavPoint(n); + } + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, ward->Name()); + + switch (mission->Type()) { + case Mission::ESCORT_FREIGHT: + obj->SetTargetDesc(Text("the star freighter ") + ward->Name()); + break; + + case Mission::ESCORT_SHUTTLE: + obj->SetTargetDesc(Text("the shuttle ") + ward->Name()); + break; + + case Mission::ESCORT_STRIKE: + obj->SetTargetDesc(Text("the ") + ward->Name() + Text(" strike package")); + break; + + case Mission::DEFEND: + obj->SetTargetDesc(Text("the ") + ward->Name()); + break; + + default: + if (ward->GetCombatGroup()) { + obj->SetTargetDesc(Text("the ") + ward->GetCombatGroup()->GetDescription()); + } + else { + obj->SetTargetDesc(Text("the ") + ward->Name()); + } + break; + } + + elem->AddObjective(obj); + } + + mission->AddElement(elem); + + player_elem = elem; + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreatePatrols() +{ + List<MissionElement> patrols; + + ListIter<MissionElement> iter = mission->GetElements(); + while (++iter) { + MissionElement* squad_elem = iter.value(); + CombatGroup* squadron = squad_elem->GetCombatGroup(); + CombatUnit* unit = squad_elem->GetCombatUnit(); + + if (!squad_elem->IsSquadron() || !squadron || !unit || unit->LiveCount() < 4) + continue; + + if (squadron->Type() == CombatGroup::INTERCEPT_SQUADRON || + squadron->Type() == CombatGroup::FIGHTER_SQUADRON) { + + StarSystem* system = mission->GetStarSystem(); + CombatGroup* base = squadron->FindCarrier(); + + if (!base) + continue; + + OrbitalRegion* region = system->FindRegion(base->GetRegion()); + + if (!region) + continue; + + int patrol_type = Mission::PATROL; + Point base_loc; + + if (region->Type() == Orbital::TERRAIN) { + patrol_type = Mission::AIR_PATROL; + + if (RandomChance(2,3)) + continue; + } + + base_loc = base->Location() + RandomPoint() * 1.5; + + if (region->Type() == Orbital::TERRAIN) + base_loc += Point(0, 0, 14.0e3); + + MissionElement* elem = CreateFighterPackage(squadron, 2, patrol_type); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(base->GetRegion()); + elem->SetLocation(base_loc); + patrols.append(elem); + } + } + } + + iter.attach(patrols); + while (++iter) + mission->AddElement(iter.value()); +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateWards() +{ + switch (mission->Type()) { + case Mission::ESCORT_FREIGHT: CreateWardFreight(); break; + case Mission::ESCORT_SHUTTLE: CreateWardShuttle(); break; + case Mission::ESCORT_STRIKE: CreateWardStrike(); break; + default: break; + } +} + +void +CampaignMissionFighter::CreateWardFreight() +{ + if (!mission || !mission->GetStarSystem()) return; + + CombatUnit* carrier = FindCarrier(squadron); + CombatGroup* freight = 0; + + if (request) + freight = request->GetObjective(); + + if (!freight) + freight = campaign->FindGroup(ownside, CombatGroup::FREIGHT); + + if (!freight || freight->CalcValue() < 1) return; + + CombatUnit* unit = freight->GetNextUnit(); + if (!unit) return; + + MissionElement* elem = CreateSingleElement(freight, unit); + if (!elem) return; + + elem->SetMissionRole(Mission::CARGO); + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(squadron->GetRegion()); + + if (carrier) + elem->SetLocation(carrier->Location() + RandomPoint() * 2); + + ward = elem; + mission->AddElement(elem); + + + StarSystem* system = mission->GetStarSystem(); + OrbitalRegion* rgn1 = system->FindRegion(elem->Region()); + Point delta = rgn1->Location() - rgn1->Primary()->Location(); + Point npt_loc = elem->Location(); + Instruction* n = 0; + + delta.Normalize(); + delta *= 200.0e3; + + npt_loc += delta; + + n = new(__FILE__,__LINE__) Instruction(elem->Region(), + npt_loc, + Instruction::VECTOR); + + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + + Text rgn2 = elem->Region(); + List<CombatZone>& zones = campaign->GetZones(); + if (zones[zones.size()-1]->HasRegion(rgn2)) + rgn2 = *zones[0]->GetRegions()[0]; + else + rgn2 = *zones[zones.size()-1]->GetRegions()[0]; + + n = new(__FILE__,__LINE__) Instruction(rgn2, + Point(0, 0, 0), + Instruction::VECTOR); + + if (n) { + n->SetSpeed(750); + elem->AddNavPoint(n); + } +} + +void +CampaignMissionFighter::CreateWardShuttle() +{ + if (!mission || !mission->GetStarSystem()) return; + + CombatUnit* carrier = FindCarrier(squadron); + CombatGroup* shuttle = campaign->FindGroup(ownside, CombatGroup::LCA_SQUADRON); + + if (!shuttle || shuttle->CalcValue() < 1) return; + + List<CombatUnit>& units = shuttle->GetUnits(); + + MissionElement* elem = CreateFighterPackage(shuttle, 1, Mission::CARGO); + if (!elem) return; + + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(orb_region); + elem->Loadouts().destroy(); + + if (carrier) + elem->SetLocation(carrier->Location() + RandomPoint() * 2); + + ward = elem; + mission->AddElement(elem); + + // if there is terrain nearby, then have the shuttle fly down to it: + if (air_region.length() > 0) { + StarSystem* system = mission->GetStarSystem(); + OrbitalRegion* rgn1 = system->FindRegion(elem->Region()); + Point delta = rgn1->Location() - rgn1->Primary()->Location(); + Point npt_loc = elem->Location(); + Instruction* n = 0; + + delta.Normalize(); + delta *= -200.0e3; + + npt_loc += delta; + + n = new(__FILE__,__LINE__) Instruction(elem->Region(), + npt_loc, + Instruction::VECTOR); + + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + + n = new(__FILE__,__LINE__) Instruction(air_region, + Point(0, 0, 10.0e3), + Instruction::VECTOR); + + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + } + + // otherwise, escort the shuttle in for a landing on the carrier: + else if (carrier) { + Point src = carrier->Location() + RandomDirection() * 150e3; + Point dst = carrier->Location() + RandomDirection() * 25e3; + Instruction* n = 0; + + elem->SetLocation(src); + + n = new(__FILE__,__LINE__) Instruction(elem->Region(), dst, Instruction::DOCK); + if (n) { + n->SetTarget(carrier->Name()); + n->SetSpeed(500); + elem->AddNavPoint(n); + } + } +} + +void +CampaignMissionFighter::CreateWardStrike() +{ + if (!mission || !mission->GetStarSystem()) return; + + CombatUnit* carrier = FindCarrier(squadron); + CombatGroup* strike = strike_group; + + if (!strike || strike->CalcValue() < 1) return; + + List<CombatUnit>& units = strike->GetUnits(); + + int type = Mission::ASSAULT; + + if (airborne) + type = Mission::STRIKE; + + MissionElement* elem = CreateFighterPackage(strike, 2, type); + if (!elem) return; + + if (strike->GetParent() == squadron->GetParent()) { + Player* p = Player::GetCurrentPlayer(); + elem->SetAlert(p ? !p->FlyingStart() : true); + } + + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(squadron->GetRegion()); + + if (strike_target) { + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, strike_target->Name()); + + if (obj) { + if (airborne) + obj->SetAction(Instruction::STRIKE); + + elem->AddObjective(obj); + } + } + + ward = elem; + mission->AddElement(elem); + + + StarSystem* system = mission->GetStarSystem(); + OrbitalRegion* rgn1 = system->FindRegion(elem->Region()); + Point delta = rgn1->Location() - rgn1->Primary()->Location(); + Point npt_loc = elem->Location(); + Instruction* n = 0; + + if (airborne) { + delta.Normalize(); + delta *= -30.0e3; + npt_loc += delta; + + n = new(__FILE__,__LINE__) Instruction(elem->Region(), + npt_loc, + Instruction::VECTOR); + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + + npt_loc = Point(0, 0, 10.0e3); + + n = new(__FILE__,__LINE__) Instruction(air_region, + npt_loc, + Instruction::VECTOR); + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + } + + // IP: + if (strike_target) { + delta = strike_target->Location() - npt_loc; + delta.Normalize(); + delta *= 15.0e3; + + npt_loc = strike_target->Location() + delta + Point(0, 0, 8.0e3); + + n = new(__FILE__,__LINE__) Instruction(strike_target->GetRegion(), + npt_loc, + Instruction::STRIKE); + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + } + + if (airborne) { + n = new(__FILE__,__LINE__) Instruction(air_region, + Point(0, 0, 30.0e3), + Instruction::VECTOR); + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + } + + if (carrier) { + n = new(__FILE__,__LINE__) Instruction(elem->Region(), + carrier->Location() - Point(0, -20.0e3, 0), + Instruction::VECTOR); + if (n) { + n->SetSpeed(500); + elem->AddNavPoint(n); + } + } + + // find the strike target element: + if (strike_target) { + prime_target = mission->FindElement(strike_target->Name()); + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateEscorts() +{ + bool escort_needed = false; + + if (mission->Type() == Mission::STRIKE || mission->Type() == Mission::ASSAULT) { + if (request && request->GetObjective()) { + int tgt_type = request->GetObjective()->Type(); + + if (tgt_type == CombatGroup::CARRIER_GROUP || + tgt_type == CombatGroup::STATION || + tgt_type == CombatGroup::STARBASE) + + escort_needed = true; + } + } + + if (player_elem && escort_needed) { + CombatGroup* s = FindSquadron(ownside, CombatGroup::INTERCEPT_SQUADRON); + + if (s && s->IsAssignable()) { + MissionElement* elem = CreateFighterPackage(s, 2, Mission::ESCORT_STRIKE); + + if (elem) { + Point offset = Point(2.0e3, 2.0e3, 1.0e3); + + ListIter<Instruction> npt_iter = player_elem->NavList(); + while (++npt_iter) { + Instruction* npt = npt_iter.value(); + Instruction* n = new(__FILE__,__LINE__) Instruction(npt->RegionName(), + npt->Location() + offset, + Instruction::ESCORT); + if (n) { + n->SetSpeed(npt->Speed()); + elem->AddNavPoint(n); + } + } + + mission->AddElement(elem); + } + } + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateTargets() +{ + switch (mission->Type()) { + default: + case Mission::DEFEND: + case Mission::PATROL: CreateTargetsPatrol(); break; + case Mission::SWEEP: CreateTargetsSweep(); break; + case Mission::INTERCEPT: CreateTargetsIntercept(); break; + case Mission::ESCORT_FREIGHT: CreateTargetsFreightEscort(); break; + + case Mission::ESCORT: + case Mission::ESCORT_SHUTTLE: CreateTargetsShuttleEscort(); break; + case Mission::ESCORT_STRIKE: CreateTargetsStrikeEscort(); break; + case Mission::STRIKE: CreateTargetsStrike(); break; + case Mission::ASSAULT: CreateTargetsAssault(); break; + } +} + +void +CampaignMissionFighter::CreateTargetsPatrol() +{ + if (!squadron || !player_elem) return; + + Text region = squadron->GetRegion(); + Point base_loc = player_elem->Location(); + Point patrol_loc; + + if (airborne) + base_loc = RandomPoint() * 2 + Point(0, 0, 12.0e3); + + else if (carrier_elem) + base_loc = carrier_elem->Location(); + + if (airborne) { + if (!airbase) + PlanetaryInsertion(player_elem); + region = air_region; + patrol_loc = base_loc + + RandomDirection() * Random( 60e3, 100e3); + } + else { + patrol_loc = base_loc + + RandomDirection() * Random(110e3, 160e3); + } + + Instruction* n = new(__FILE__,__LINE__) Instruction(region, + patrol_loc, + Instruction::PATROL); + if (n) + player_elem->AddNavPoint(n); + + int ntargets = (int) Random(2.0,5.1); + + while (ntargets > 0) { + int t = CreateRandomTarget(region, patrol_loc); + ntargets -= t; + if (t < 1) break; + } + + if (airborne && !airbase) { + OrbitalInsertion(player_elem); + } + + Instruction* obj = new(__FILE__,__LINE__) Instruction(*n); + obj->SetTargetDesc("inbound enemy units"); + player_elem->AddObjective(obj); + + if (carrier_elem && !airborne) { + obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier_elem->Name()); + if (obj) { + obj->SetTargetDesc(Text("the ") + carrier_elem->Name() + " battle group"); + player_elem->AddObjective(obj); + } + } +} + +void +CampaignMissionFighter::CreateTargetsSweep() +{ + if (!squadron || !player_elem) return; + + double traverse = PI; + double a = Random(-PI/2, PI/2); + Point base_loc = player_elem->Location(); + Point sweep_loc = base_loc; + Text region = player_elem->Region(); + Instruction* n = 0; + + if (carrier_elem) + base_loc = carrier_elem->Location(); + + if (airborne) { + PlanetaryInsertion(player_elem); + region = air_region; + sweep_loc = RandomPoint() + Point(0, 0, 10.0e3); // keep it airborne! + } + + sweep_loc += Point(sin(a), -cos(a), 0) * 100.0e3; + + n = new(__FILE__,__LINE__) Instruction(region, + sweep_loc, + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + player_elem->AddNavPoint(n); + } + + int index = 0; + int ntargets = 6; + + while (traverse > 0) { + double a1 = Random(PI/4, PI/2); + traverse -= a1; + a += a1; + + sweep_loc += Point(sin(a), -cos(a), 0) * 80.0e3; + + n = new(__FILE__,__LINE__) Instruction(region, + sweep_loc, + Instruction::SWEEP); + if (n) { + n->SetSpeed(750); + n->SetFormation(Instruction::SPREAD); + player_elem->AddNavPoint(n); + } + + if (ntargets && RandomChance()) { + ntargets -= CreateRandomTarget(region, sweep_loc); + } + + index++; + } + + if (ntargets > 0) + CreateRandomTarget(region, sweep_loc); + + if (airborne && !airbase) { + OrbitalInsertion(player_elem); + region = player_elem->Region(); + } + + sweep_loc = base_loc; + sweep_loc.y += 30.0e3; + + n = new(__FILE__,__LINE__) Instruction(region, + sweep_loc, + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + player_elem->AddNavPoint(n); + } + + Instruction* obj = new(__FILE__,__LINE__) Instruction(region, + sweep_loc, + Instruction::SWEEP); + if (obj) { + obj->SetTargetDesc("enemy patrols"); + player_elem->AddObjective(obj); + } + + if (carrier_elem && !airborne) { + obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier_elem->Name()); + if (obj) { + obj->SetTargetDesc(Text("the ") + carrier_elem->Name() + " battle group"); + player_elem->AddObjective(obj); + } + } +} + +void +CampaignMissionFighter::CreateTargetsIntercept() +{ + if (!squadron || !player_elem) return; + + CombatUnit* carrier = FindCarrier(squadron); + CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON); + CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON); + + if (!s || !s2) return; + + int ninbound = 2 + (int) (RandomIndex() < 5); + bool second = ninbound > 2; + Text attacker; + + while (ninbound--) { + MissionElement* elem = CreateFighterPackage(s, 4, Mission::ASSAULT); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->Loadouts().destroy(); + elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Hvy Ship Strike")); + + if (carrier) { + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, carrier->Name()); + if (obj) { + elem->AddObjective(obj); + elem->SetLocation(carrier->Location() + RandomPoint() * 6); + } + } + else { + elem->SetLocation(squadron->Location() + RandomPoint() * 5); + } + + mission->AddElement(elem); + + attacker = elem->Name(); + + if (!prime_target) { + prime_target = elem; + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::INTERCEPT, attacker); + if (obj) { + obj->SetTargetDesc(Text("inbound strike package '") + elem->Name() + "'"); + player_elem->AddObjective(obj); + } + } + + MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT); + if (e2) { + e2->SetIntelLevel(Intel::KNOWN); + e2->SetLocation(elem->Location() + RandomPoint() * 0.25); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name()); + if (obj) + e2->AddObjective(obj); + mission->AddElement(e2); + } + } + } + + if (second) { + // second friendly fighter package + CombatGroup* s = FindSquadron(ownside, CombatGroup::FIGHTER_SQUADRON); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 2, Mission::INTERCEPT); + if (elem) { + Player* p = Player::GetCurrentPlayer(); + elem->SetAlert(p ? !p->FlyingStart() : true); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::INTERCEPT, attacker); + if (obj) + elem->AddObjective(obj); + mission->AddElement(elem); + } + } + } + + if (carrier && !airborne) { + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier->Name()); + if (obj) { + obj->SetTargetDesc(Text("the ") + carrier->Name() + " battle group"); + player_elem->AddObjective(obj); + } + } +} + +void +CampaignMissionFighter::CreateTargetsFreightEscort() +{ + if (!squadron || !player_elem) return; + + if (!ward) { + CreateTargetsPatrol(); + return; + } + + CombatUnit* carrier = FindCarrier(squadron); + CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON); + CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON); + + if (!s) s = s2; + + if (!s || !s2) return; + + MissionElement* elem = CreateFighterPackage(s, 2, Mission::ASSAULT); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + + elem->SetLocation(ward->Location() + RandomPoint() * 5); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, ward->Name()); + if (obj) + elem->AddObjective(obj); + mission->AddElement(elem); + + MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT); + if (e2) { + e2->SetIntelLevel(Intel::KNOWN); + e2->SetLocation(elem->Location() + RandomPoint() * 0.25); + + Instruction* obj2 = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name()); + if (obj2) + e2->AddObjective(obj2); + mission->AddElement(e2); + } + } + + Instruction* obj3 = new(__FILE__,__LINE__) Instruction(mission->GetRegion(), + Point(0,0,0), + Instruction::PATROL); + + if (obj3) { + obj3->SetTargetDesc("enemy patrols"); + player_elem->AddObjective(obj3); + } +} + +void +CampaignMissionFighter::CreateTargetsShuttleEscort() +{ + CreateTargetsFreightEscort(); +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateTargetsStrikeEscort() +{ + if (!squadron || !player_elem) return; + + if (ward) { + Point offset = Point(2.0e3, 2.0e3, 1.0e3); + + ListIter<Instruction> npt_iter = ward->NavList(); + while (++npt_iter) { + Instruction* npt = npt_iter.value(); + Instruction* n = new(__FILE__,__LINE__) Instruction(npt->RegionName(), + npt->Location() + offset, + Instruction::ESCORT); + if (n) { + n->SetSpeed(npt->Speed()); + player_elem->AddNavPoint(n); + } + } + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateTargetsStrike() +{ + if (!squadron || !player_elem) return; + + if (request && request->GetObjective()) + strike_target = request->GetObjective(); + + if (strike_target && strike_group) { + CreateElements(strike_target); + + ListIter<MissionElement> e_iter = mission->GetElements(); + while (++e_iter) { + MissionElement* elem = e_iter.value(); + + if (elem->GetCombatGroup() == strike_target) { + prime_target = elem; + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::STRIKE, elem->Name()); + if (obj) { + obj->SetTargetDesc(Text("preplanned target '") + elem->Name() + "'"); + player_elem->AddObjective(obj); + } + + // create flight plan: + RLoc rloc; + Point loc = Point(0, 0, 15e3); + Instruction* n = 0; + + PlanetaryInsertion(player_elem); + + // target approach and strike: + Point delta = prime_target->Location() - loc; + + if (delta.length() >= 100e3) { + Point mid = loc + delta * 0.5; + mid.z = 10.0e3; + + rloc.SetReferenceLoc(0); + rloc.SetBaseLocation(mid); + rloc.SetDistance(20e3); + rloc.SetDistanceVar(5e3); + rloc.SetAzimuth(90*DEGREES); + rloc.SetAzimuthVar(25*DEGREES); + + n = new(__FILE__,__LINE__) Instruction(prime_target->Region(), + Point(), + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + n->GetRLoc() = rloc; + player_elem->AddNavPoint(n); + } + + loc = mid; + } + + delta = loc - prime_target->Location(); + delta.Normalize(); + delta *= 25.0e3; + + loc = prime_target->Location() + delta; + loc.z = 8.0e3; + + n = new(__FILE__,__LINE__) Instruction(prime_target->Region(), + loc, + Instruction::STRIKE); + if (n) { + n->SetSpeed(500); + player_elem->AddNavPoint(n); + } + + // exeunt: + rloc.SetReferenceLoc(0); + rloc.SetBaseLocation(Point(0, 0, 30.0e3)); + rloc.SetDistance(50e3); + rloc.SetDistanceVar(5e3); + rloc.SetAzimuth(-90*DEGREES); + rloc.SetAzimuthVar(25*DEGREES); + + n = new(__FILE__,__LINE__) Instruction(prime_target->Region(), + Point(), + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + n->GetRLoc() = rloc; + player_elem->AddNavPoint(n); + } + + if (carrier_elem) { + rloc.SetReferenceLoc(0); + rloc.SetBaseLocation(carrier_elem->Location()); + rloc.SetDistance(60e3); + rloc.SetDistanceVar(10e3); + rloc.SetAzimuth(180*DEGREES); + rloc.SetAzimuthVar(30*DEGREES); + + n = new(__FILE__,__LINE__) Instruction(carrier_elem->Region(), + Point(), + Instruction::RTB); + if (n) { + n->SetSpeed(750); + n->GetRLoc() = rloc; + player_elem->AddNavPoint(n); + } + } + + break; + } + } + } +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::CreateTargetsAssault() +{ + if (!squadron || !player_elem) return; + + CombatGroup* assigned = 0; + + if (request) + assigned = request->GetObjective(); + + if (assigned) { + if (assigned->Type() > CombatGroup::WING && assigned->Type() < CombatGroup::FLEET) { + mission->AddElement(CreateFighterPackage(assigned, 2, Mission::CARGO)); + } + else { + CreateElements(assigned); + } + + // select the prime target element - choose the lowest ranking + // unit of a DESRON, CBG, or CVBG: + + ListIter<MissionElement> e_iter = mission->GetElements(); + while (++e_iter) { + MissionElement* elem = e_iter.value(); + + if (elem->GetCombatGroup() == assigned) { + if (!prime_target || assigned->Type() <= CombatGroup::CARRIER_GROUP) { + prime_target = elem; + } + } + } + + if (prime_target) { + MissionElement* elem = prime_target; + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, elem->Name()); + if (obj) { + obj->SetTargetDesc(Text("preplanned target '") + elem->Name() + "'"); + player_elem->AddObjective(obj); + } + + // create flight plan: + RLoc rloc; + Vec3 dummy(0,0,0); + Instruction* instr = 0; + Point loc = player_elem->Location(); + Point tgt = elem->Location(); + Point mid; + + CombatGroup* tgt_group = elem->GetCombatGroup(); + if (tgt_group && tgt_group->GetFirstUnit() && tgt_group->IsMovable()) { + tgt = tgt_group->GetFirstUnit()->Location(); + } + + if (carrier_elem) + loc = carrier_elem->Location(); + + mid = loc + (elem->Location() - loc) * 0.5; + + rloc.SetReferenceLoc(0); + rloc.SetBaseLocation(mid); + rloc.SetDistance(40e3); + rloc.SetDistanceVar(5e3); + rloc.SetAzimuth(90*DEGREES); + rloc.SetAzimuthVar(45*DEGREES); + + instr = new(__FILE__,__LINE__) Instruction(elem->Region(), dummy, Instruction::VECTOR); + if (instr) { + instr->SetSpeed(750); + instr->GetRLoc() = rloc; + + player_elem->AddNavPoint(instr); + + if (RandomChance()) { + CreateRandomTarget(elem->Region(), rloc.Location()); + } + } + + rloc.SetReferenceLoc(0); + rloc.SetBaseLocation(tgt); + rloc.SetDistance(60e3); + rloc.SetDistanceVar(5e3); + rloc.SetAzimuth(120*DEGREES); + rloc.SetAzimuthVar(15*DEGREES); + + instr = new(__FILE__,__LINE__) Instruction(elem->Region(), dummy, Instruction::ASSAULT); + if (instr) { + instr->SetSpeed(750); + instr->GetRLoc() = rloc; + instr->SetTarget(elem->Name()); + + player_elem->AddNavPoint(instr); + } + + if (carrier_elem) { + rloc.SetReferenceLoc(0); + rloc.SetBaseLocation(loc); + rloc.SetDistance(30e3); + rloc.SetDistanceVar(0); + rloc.SetAzimuth(180*DEGREES); + rloc.SetAzimuthVar(60*DEGREES); + + instr = new(__FILE__,__LINE__) Instruction(carrier_elem->Region(), dummy, Instruction::RTB); + if (instr) { + instr->SetSpeed(500); + instr->GetRLoc() = rloc; + + player_elem->AddNavPoint(instr); + } + } + } + } +} + +// +--------------------------------------------------------------------+ + +int +CampaignMissionFighter::CreateRandomTarget(const char* rgn, Point base_loc) +{ + if (!mission) return 0; + + int ntargets = 0; + int ttype = RandomIndex(); + bool oca = (mission->Type() == Mission::SWEEP); + + if (ttype < 8) { + CombatGroup* s = 0; + + if (ttype < 4) + s = FindSquadron(enemy, CombatGroup::INTERCEPT_SQUADRON); + else + s = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 2, Mission::SWEEP); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(rgn); + elem->SetLocation(base_loc + RandomPoint() * 1.5); + mission->AddElement(elem); + ntargets++; + } + } + } + else if (ttype < 12) { + if (oca) { + CombatGroup* s = FindSquadron(enemy, CombatGroup::LCA_SQUADRON); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 1, Mission::CARGO); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(rgn); + elem->SetLocation(base_loc + RandomPoint() * 2); + mission->AddElement(elem); + ntargets++; + + CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON); + + if (s2) { + MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT); + if (e2) { + e2->SetIntelLevel(Intel::KNOWN); + e2->SetRegion(rgn); + e2->SetLocation(elem->Location() + RandomPoint() * 0.5); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name()); + if (obj) + e2->AddObjective(obj); + mission->AddElement(e2); + ntargets++; + } + } + } + } + } + else { + CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 2, Mission::ASSAULT); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(rgn); + elem->SetLocation(base_loc + RandomPoint() * 1.3); + mission->AddElement(elem); + ntargets++; + } + } + } + } + else if (ttype < 15) { + if (oca) { + CombatGroup* s = 0; + + if (airborne) + s = FindSquadron(enemy, CombatGroup::LCA_SQUADRON); + else + s = FindSquadron(enemy, CombatGroup::FREIGHT); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 1, Mission::CARGO); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(rgn); + elem->SetLocation(base_loc + RandomPoint() * 2); + mission->AddElement(elem); + ntargets++; + + CombatGroup* s2 = FindSquadron(enemy, CombatGroup::INTERCEPT_SQUADRON); + + if (s2) { + MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT); + if (e2) { + e2->SetIntelLevel(Intel::KNOWN); + e2->SetRegion(rgn); + e2->SetLocation(elem->Location() + RandomPoint() * 0.5); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name()); + if (obj) + e2->AddObjective(obj); + mission->AddElement(e2); + ntargets++; + } + } + } + } + } + else { + CombatGroup* s = FindSquadron(enemy, CombatGroup::ATTACK_SQUADRON); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 2, Mission::ASSAULT); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(rgn); + elem->SetLocation(base_loc + RandomPoint() * 1.1); + mission->AddElement(elem); + ntargets++; + + CombatGroup* s2 = FindSquadron(enemy, CombatGroup::FIGHTER_SQUADRON); + + if (s2) { + MissionElement* e2 = CreateFighterPackage(s2, 2, Mission::ESCORT); + if (e2) { + e2->SetIntelLevel(Intel::KNOWN); + e2->SetRegion(rgn); + e2->SetLocation(elem->Location() + RandomPoint() * 0.5); + + Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name()); + if (obj) + e2->AddObjective(obj); + mission->AddElement(e2); + ntargets++; + } + } + } + } + } + } + else { + CombatGroup* s = FindSquadron(enemy, CombatGroup::LCA_SQUADRON); + + if (s) { + MissionElement* elem = CreateFighterPackage(s, 2, Mission::CARGO); + if (elem) { + elem->SetIntelLevel(Intel::KNOWN); + elem->SetRegion(rgn); + elem->SetLocation(base_loc + RandomPoint() * 2); + mission->AddElement(elem); + ntargets++; + } + } + } + + return ntargets; +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::PlanetaryInsertion(MissionElement* elem) +{ + if (!mission || !elem) return; + if (!mission->GetStarSystem()) return; + + MissionElement* carrier = mission->FindElement(elem->Commander()); + StarSystem* system = mission->GetStarSystem(); + OrbitalRegion* rgn1 = system->FindRegion(elem->Region()); + OrbitalRegion* rgn2 = system->FindRegion(air_region); + Point npt_loc = elem->Location(); + Instruction* n = 0; + Player* p = Player::GetCurrentPlayer(); + + int flying_start = p ? p->FlyingStart() : 0; + + if (carrier && !flying_start) { + npt_loc = carrier->Location() + Point(1e3, -5e3, 0); + } + + if (rgn1 && rgn2) { + double delta_t = mission->Start() - campaign->GetTime(); + Point r1 = rgn1->PredictLocation(delta_t); + Point r2 = rgn2->PredictLocation(delta_t); + + Point delta = r2 - r1; + + delta.y *= -1; + delta.Normalize(); + delta *= 10e3; + + npt_loc += delta; + + n = new(__FILE__,__LINE__) Instruction(elem->Region(), + npt_loc, + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + elem->AddNavPoint(n); + } + } + + n = new(__FILE__,__LINE__) Instruction(air_region, + Point(0, 0, 15e3), + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + elem->AddNavPoint(n); + } +} + +void +CampaignMissionFighter::OrbitalInsertion(MissionElement* elem) +{ + Instruction* n = new(__FILE__,__LINE__) Instruction(air_region, + Point(0, 0, 30.0e3), + Instruction::VECTOR); + if (n) { + n->SetSpeed(750); + elem->AddNavPoint(n); + } +} + +// +--------------------------------------------------------------------+ + +MissionElement* +CampaignMissionFighter::CreateFighterPackage(CombatGroup* squadron, int count, int role) +{ + if (!squadron) return 0; + + CombatUnit* fighter = squadron->GetUnits().at(0); + CombatUnit* carrier = FindCarrier(squadron); + + if (!fighter) + return 0; + + int avail = fighter->LiveCount(); + int actual = count; + + if (avail < actual) + actual = avail; + + if (avail < 1) { + ::Print("CMF - Insufficient fighters in squadron '%s' - %d required, %d available\n", + squadron->Name().data(), count, avail); + return 0; + } + + MissionElement* elem = new(__FILE__,__LINE__) MissionElement; + if (!elem) { + Exit(); + return 0; + } + + elem->SetName(Callsign::GetCallsign(fighter->GetIFF())); + elem->SetElementID(pkg_id++); + + if (carrier) { + elem->SetCommander(carrier->Name()); + elem->SetHeading(carrier->GetHeading()); + } + else { + elem->SetHeading(fighter->GetHeading()); + } + + elem->SetDesign(fighter->GetDesign()); + elem->SetCount(actual); + elem->SetIFF(fighter->GetIFF()); + elem->SetIntelLevel(squadron->IntelLevel()); + elem->SetRegion(fighter->GetRegion()); + elem->SetSquadron(squadron->Name()); + elem->SetMissionRole(role); + + switch (role) { + case Mission::ASSAULT: + if (request->GetObjective() && + request->GetObjective()->Type() == CombatGroup::MINEFIELD) + elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Rockets")); + else + elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ship Strike")); + break; + + case Mission::STRIKE: + elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ground Strike")); + break; + + default: + elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "ACM Medium Range")); + break; + } + + if (carrier) { + Point offset = RandomPoint() * 0.3; + offset.y = fabs(offset.y); + offset.z += 2e3; + elem->SetLocation(carrier->Location() + offset); + } + else { + elem->SetLocation(fighter->Location() + RandomPoint()); + } + + elem->SetCombatGroup(squadron); + elem->SetCombatUnit(fighter); + + return elem; +} + +// +--------------------------------------------------------------------+ + +static CombatGroup* FindCombatGroup(CombatGroup* g, int type) +{ + if (g->IntelLevel() <= Intel::RESERVE) + return 0; + + if (g->GetUnits().size() > 0) { + for (int i = 0; i < g->GetUnits().size(); i++) { + CombatUnit* u = g->GetUnits().at(i); + if (g->Type() == type && u->LiveCount() > 0) + return g; + } + } + + CombatGroup* result = 0; + + ListIter<CombatGroup> subgroup = g->GetComponents(); + while (++subgroup && !result) + result = FindCombatGroup(subgroup.value(), type); + + return result; +} + +// +--------------------------------------------------------------------+ + +CombatGroup* +CampaignMissionFighter::FindSquadron(int iff, int type) +{ + if (!squadron) return 0; + + CombatGroup* result = 0; + Campaign* campaign = Campaign::GetCampaign(); + + if (campaign) { + ListIter<Combatant> combatant = campaign->GetCombatants(); + while (++combatant && !result) { + if (combatant->GetIFF() == iff) { + result = ::FindCombatGroup(combatant->GetForce(), type); + + if (result && result->CountUnits() < 1) { + result = 0; + } + } + } + } + + return result; +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::DefineMissionObjectives() +{ + if (!mission || !player_elem) return; + + if (prime_target) mission->SetTarget(prime_target); + if (ward) mission->SetWard(ward); + + Text objectives; + + for (int i = 0; i < player_elem->Objectives().size(); i++) { + Instruction* obj = player_elem->Objectives().at(i); + objectives += "* "; + objectives += obj->GetDescription(); + objectives += ".\n"; + } + + mission->SetObjective(objectives); +} + +// +--------------------------------------------------------------------+ + +MissionInfo* +CampaignMissionFighter::DescribeMission() +{ + if (!mission || !player_elem) return 0; + + char name[256]; + char player_info[256]; + + if (mission_info && mission_info->name.length()) + sprintf_s(name, "MSN-%03d %s", mission->Identity(), mission_info->name.data()); + else if (ward) + sprintf_s(name, "MSN-%03d %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(), ward->Name().data()); + else if (prime_target) + sprintf_s(name, "MSN-%03d %s %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(), + Ship::ClassName(prime_target->GetDesign()->type), + prime_target->Name().data()); + else + sprintf_s(name, "MSN-%03d %s", mission->Identity(), Game::GetText(mission->TypeName()).data()); + + if (player_elem) { + sprintf_s(player_info, "%d x %s %s '%s'", + player_elem->Count(), + (const char*) player_elem->GetDesign()->abrv, + (const char*) player_elem->GetDesign()->name, + (const char*) player_elem->Name()); + } + + MissionInfo* info = new(__FILE__,__LINE__) MissionInfo; + + info->id = mission->Identity(); + info->mission = mission; + info->name = name; + info->type = mission->Type(); + info->player_info = player_info; + info->description = mission->Objective(); + info->start = mission->Start(); + + if (mission->GetStarSystem()) + info->system = mission->GetStarSystem()->Name(); + info->region = mission->GetRegion(); + + mission->SetName(name); + + return info; +} + +// +--------------------------------------------------------------------+ + +void +CampaignMissionFighter::Exit() +{ + Starshatter* stars = Starshatter::GetInstance(); + if (stars) + stars->SetGameMode(Starshatter::MENU_MODE); +} |