Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CampaignMissionFighter.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright (C) 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: CampaignMissionFighter.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  CampaignMissionFighter generates missions and mission
13  info for the player's FIGHTER SQUADRON as part of a
14  dynamic campaign.
15 */
16 
17 #include "MemDebug.h"
18 #include "CampaignMissionFighter.h"
19 #include "CampaignMissionRequest.h"
20 #include "Campaign.h"
21 #include "Combatant.h"
22 #include "CombatAssignment.h"
23 #include "CombatGroup.h"
24 #include "CombatUnit.h"
25 #include "CombatZone.h"
26 #include "Callsign.h"
27 #include "Galaxy.h"
28 #include "Mission.h"
29 #include "MissionTemplate.h"
30 #include "Instruction.h"
31 #include "Ship.h"
32 #include "ShipDesign.h"
33 #include "Starshatter.h"
34 #include "StarSystem.h"
35 #include "Player.h"
36 
37 #include "Random.h"
38 
39 static int pkg_id = 1000;
40 extern int dump_missions;
41 
42 // +--------------------------------------------------------------------+
43 
45 : campaign(c), squadron(0), mission(0), player_elem(0),
46 strike_group(0), strike_target(0), prime_target(0),
47 carrier_elem(0), ward(0), escort(0), airborne(false), airbase(false),
48 ownside(0), enemy(-1), mission_type(0), mission_info(0)
49 {
50  if (!campaign || !campaign->GetPlayerGroup()) {
51  ::Print("ERROR - CMF campaign=0x%08x player_group=0x%08x\n",
53  return;
54  }
55 
56  CombatGroup* player_group = campaign->GetPlayerGroup();
57 
58  switch (player_group->Type()) {
59  case CombatGroup::WING: {
60  CombatGroup* wing = player_group;
61  ListIter<CombatGroup> iter = wing->GetComponents();
62 
63  while (++iter) {
64  if (iter->Type() == CombatGroup::FIGHTER_SQUADRON) {
65  squadron = iter.value();
66  }
67  }
68  }
69  break;
70 
74  squadron = player_group;
75  break;
76 
77  default:
78  ::Print("ERROR - CMF invalid player group: %s IFF %d\n",
79  player_group->GetDescription(),
80  player_group->GetIFF());
81  break;
82  }
83 
84  if (squadron) {
85  CombatGroup* carrier = squadron->FindCarrier();
86 
87  if (carrier && carrier->Type() == CombatGroup::STARBASE) {
88  airbase = true;
89  }
90  }
91 }
92 
94 
95 // +--------------------------------------------------------------------+
96 
97 void
99 {
100  if (!campaign || !squadron || !req)
101  return;
102 
103  ::Print("\n-----------------------------------------------\n");
104  if (req->Script().length())
105  ::Print("CMF CreateMission() request: %s '%s'\n",
106  Mission::RoleName(req->Type()),
107  (const char*) req->Script());
108 
109  else
110  ::Print("CMF CreateMission() request: %s %s\n",
111  Mission::RoleName(req->Type()),
112  req->GetObjective() ? req->GetObjective()->Name().data() : "(no target)");
113 
114  request = req;
115  mission_info = 0;
116 
117  if (request->GetPrimaryGroup()) {
118  switch (request->GetPrimaryGroup()->Type()) {
122  squadron = request->GetPrimaryGroup();
123  break;
124  }
125  }
126 
127  ownside = squadron->GetIFF();
128 
129  for (int i = 0; i < campaign->GetCombatants().size(); i++) {
130  int iff = campaign->GetCombatants().at(i)->GetIFF();
131  if (iff > 0 && iff != ownside) {
132  enemy = iff;
133  break;
134  }
135  }
136 
137  static int id_key = 1;
138  GenerateMission(id_key++);
140 
141  MissionInfo* info = DescribeMission();
142 
143  if (info) {
144  campaign->GetMissionList().append(info);
145 
146  ::Print("CMF Created %03d '%s' %s\n\n",
147  info->id,
148  (const char*) info->name,
150 
151  if (dump_missions) {
152  Text script = mission->Serialize();
153  char fname[32];
154 
155  sprintf_s(fname, "msn%03d.def", info->id);
156  FILE* f;
157  fopen_s(&f, fname, "w");
158  if (f) {
159  fprintf(f, "%s\n", script.data());
160  fclose(f);
161  }
162  }
163  }
164  else {
165  ::Print("CMF failed to create mission.\n");
166  }
167 }
168 
169 // +--------------------------------------------------------------------+
170 
171 Mission*
173 {
174  bool found = false;
175 
176  SelectType();
177 
178  if (request && request->Script().length()) {
179  MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, request->Script(), campaign->Path());
180  if (mt)
182  mission = mt;
183  found = true;
184  }
185 
186  else {
188  found = mission_info != 0;
189 
190  if (found) {
191  MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, mission_info->script, campaign->Path());
192  if (mt)
194  mission = mt;
195  }
196  else {
197  mission = new(__FILE__,__LINE__) Mission(id);
198  if (mission)
200  }
201  }
202 
203  if (!mission) {
204  Exit();
205  return 0;
206  }
207 
208  char name[64];
209  sprintf_s(name, "Fighter Mission %d", id);
210 
211  mission->SetName(name);
214 
215  SelectRegion();
217  CreatePatrols();
218 
219  if (!found) {
221  mission->SetOK(true);
222  mission->Validate();
223  }
224 
225  else {
226  mission->Load();
227 
228  if (mission->IsOK()) {
231  ward = mission->GetWard();
232 
234 
235  if (player_elem && p)
237  }
238 
239  // if there was a problem, scrap the mission
240  // and start over:
241  else {
242  delete mission;
243 
244  mission = new(__FILE__,__LINE__) Mission(id);
246  mission->SetName(name);
249 
250  SelectRegion();
253 
254  mission->SetOK(true);
255  mission->Validate();
256  }
257  }
258 
259  return mission;
260 }
261 
262 // +--------------------------------------------------------------------+
263 
264 bool
266 {
267  bool ground = false;
268 
269  if (obj) {
270  CombatGroup* pgroup = campaign->GetPlayerGroup();
271 
272  if (pgroup) {
273  CombatZone* zone = pgroup->GetAssignedZone();
274 
275  if (zone) {
276  StarSystem* system = campaign->GetSystem(zone->System());
277 
278  if (system) {
279  OrbitalRegion* region = system->FindRegion(obj->GetRegion());
280 
281  if (region && region->Type() == Orbital::TERRAIN) {
282  ground = true;
283  }
284  }
285  }
286  }
287  }
288 
289  return ground;
290 }
291 
292 // +--------------------------------------------------------------------+
293 
294 void
296 {
297  int type = Mission::PATROL;
298 
299  if (request) {
300  type = request->Type();
301  if (type == Mission::STRIKE) {
303 
304  // verify that objective is a ground target:
306  type = Mission::ASSAULT;
307  }
308  }
309 
310  else if (type == Mission::ESCORT_STRIKE) {
312  if (!strike_group || strike_group->CalcValue() < 1) {
313  type = Mission::SWEEP;
314  strike_group = 0;
315  }
316  }
317  }
318 
319  mission_type = type;
320 }
321 
322 void
324 {
326 
327  if (!zone)
328  zone = squadron->GetCurrentZone();
329 
330  if (zone) {
332  mission->SetRegion(*zone->GetRegions().at(0));
333 
335 
336  if (zone->GetRegions().size() > 1) {
337  air_region = *zone->GetRegions().at(1);
338 
339  StarSystem* system = mission->GetStarSystem();
340  OrbitalRegion* rgn = 0;
341 
342  if (system)
343  rgn = system->FindRegion(air_region);
344 
345  if (!rgn || rgn->Type() != Orbital::TERRAIN)
346  air_region = "";
347  }
348 
349  if (air_region.length() > 0) {
351  airborne = true;
352  }
353 
354  else if (mission->Type() >= Mission::AIR_PATROL &&
356  airborne = true;
357  }
358 
359  else if (mission->Type() == Mission::STRIKE ||
361  if (strike_group) {
363 
365  airborne = true;
366  }
367  }
368 
369  if (airbase) {
371  }
372  }
373  }
374 
375  else {
376  ::Print("WARNING: CMF - No zone for '%s'\n", squadron->Name().data());
377 
378  StarSystem* s = campaign->GetSystemList()[0];
379 
381  mission->SetRegion(s->Regions()[0]->Name());
382  }
383 
384  if (!airborne) {
385  switch (mission->Type()) {
389  default: break;
390  }
391  }
392 }
393 
394 // +--------------------------------------------------------------------+
395 
396 void
398 {
400  while (++z_iter) {
401  CombatZone* z = z_iter.value();
402 
403  ListIter<ZoneForce> iter = z->GetForces();
404  while (++iter) {
405  ZoneForce* force = iter.value();
406  ListIter<CombatGroup> group = force->GetGroups();
407 
408  while (++group) {
409  CombatGroup* g = group.value();
410 
411  switch (g->Type()) {
416  CreateSquadron(g);
417  break;
418 
422  CreateElements(g);
423  break;
424 
433  case CombatGroup::SUPPLY:
434  case CombatGroup::REPAIR:
435  CreateElements(g);
436  break;
437 
449  CreateElements(g);
450  break;
451  }
452  }
453  }
454  }
455 }
456 
457 // +--------------------------------------------------------------------+
458 
459 void
461 {
462  CreateWards();
464  CreateTargets();
465  CreateEscorts();
466 
467  if (player_elem) {
468  Instruction* obj = new(__FILE__,__LINE__) Instruction(mission->GetRegion(),
469  Point(0,0,0),
471 
472  if (obj)
474  }
475 }
476 
477 // +--------------------------------------------------------------------+
478 
479 void
481 {
482  MissionElement* elem = 0;
483  List<CombatUnit>& units = g->GetUnits();
484 
485  CombatUnit* cmdr = 0;
486 
487  for (int i = 0; i < units.size(); i++) {
488  elem = CreateSingleElement(g, units[i]);
489 
490  if (elem) {
491  if (!cmdr) {
492  cmdr = units[i];
493  }
494  else {
495  elem->SetCommander(cmdr->Name());
496 
497  if (g->Type() == CombatGroup::CARRIER_GROUP &&
498  elem->MissionRole() == Mission::ESCORT) {
499  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, cmdr->Name());
500  if (obj)
501  elem->AddObjective(obj);
502  }
503  }
504 
505  mission->AddElement(elem);
506  }
507  }
508 }
509 
512 {
513  if (!g || g->IsReserve()) return 0;
514  if (!u || u->LiveCount() < 1) return 0;
515 
516  // make sure this unit is actually in the right star system:
517  Galaxy* galaxy = Galaxy::GetInstance();
518  if (galaxy) {
519  if (galaxy->FindSystemByRegion(u->GetRegion()) !=
520  galaxy->FindSystemByRegion(squadron->GetRegion())) {
521  return 0;
522  }
523  }
524 
525  // make sure this unit isn't already in the mission:
527  while (++e_iter) {
528  MissionElement* elem = e_iter.value();
529 
530  if (elem->GetCombatUnit() == u)
531  return 0;
532  }
533 
534  MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
535  if (!elem) {
536  Exit();
537  return 0;
538  }
539 
540  if (u->Name().length())
541  elem->SetName(u->Name());
542  else
543  elem->SetName(u->DesignName());
544 
545  elem->SetElementID(pkg_id++);
546 
547  elem->SetDesign(u->GetDesign());
548  elem->SetCount(u->LiveCount());
549  elem->SetIFF(u->GetIFF());
550  elem->SetIntelLevel(g->IntelLevel());
551  elem->SetRegion(u->GetRegion());
552  elem->SetHeading(u->GetHeading());
553 
554  int unit_index = g->GetUnits().index(u);
555  Point base_loc = u->Location();
556  bool exact = u->IsStatic(); // exact unit-level placement
557 
558  if (base_loc.length() < 1) {
559  base_loc = g->Location();
560  exact = false;
561  }
562 
563  if (unit_index < 0 || unit_index > 0 && !exact) {
564  Point loc = RandomDirection();
565 
566  if (!u->IsStatic()) {
567  while (fabs(loc.y) > fabs(loc.x))
568  loc = RandomDirection();
569 
570  loc *= 10e3 + 9e3 * unit_index;
571  }
572  else {
573  loc *= 2e3 + 2e3 * unit_index;
574  }
575 
576  elem->SetLocation(base_loc + loc);
577  }
578  else {
579  elem->SetLocation(base_loc);
580  }
581 
582  if (g->Type() == CombatGroup::CARRIER_GROUP) {
583  if (u->Type() == Ship::CARRIER) {
585 
586  if (squadron && elem->GetCombatGroup() == squadron->FindCarrier())
587  carrier_elem = elem;
588 
589  else if (!carrier_elem && u->GetIFF() == squadron->GetIFF())
590  carrier_elem = elem;
591  }
592  else {
594  }
595  }
596  else if (u->Type() == Ship::STATION ||
597  u->Type() == Ship::STARBASE) {
599 
600  if (squadron && elem->GetCombatGroup() == squadron->FindCarrier()) {
601  carrier_elem = elem;
602 
603  if (u->Type() == Ship::STARBASE)
604  airbase = true;
605  }
606  }
607  else if (u->Type() == Ship::FARCASTER) {
609 
610  // link farcaster to other terminus:
611  Text name = u->Name();
612  int dash = -1;
613 
614  for (int i = 0; i < (int) name.length(); i++)
615  if (name[i] == '-')
616  dash = i;
617 
618  Text src = name.substring(0, dash);
619  Text dst = name.substring(dash+1, name.length() - (dash+1));
620 
621  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::VECTOR, dst + "-" + src);
622  elem->AddObjective(obj);
623  }
624  else if ((u->Type() & Ship::STARSHIPS) != 0) {
626  }
627 
628  elem->SetCombatGroup(g);
629  elem->SetCombatUnit(u);
630 
631  return elem;
632 }
633 
634 CombatUnit*
636 {
637  CombatGroup* carrier = g->FindCarrier();
638 
639  if (carrier && carrier->GetUnits().size()) {
641 
642  if (carrier_elem)
643  return carrier->GetUnits().at(0);
644  }
645 
646  return 0;
647 }
648 
649 void
651 {
652  if (!g || g->IsReserve()) return;
653 
654  CombatUnit* fighter = g->GetUnits().at(0);
655  CombatUnit* carrier = FindCarrier(g);
656 
657  if (!fighter || !carrier) return;
658 
659  int live_count = fighter->LiveCount();
660  int maint_count = (live_count > 4) ? live_count / 2 : 0;
661 
662  MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
663 
664  if (!elem) {
665  Exit();
666  return;
667  }
668 
669  elem->SetName(g->Name());
670  elem->SetElementID(pkg_id++);
671 
672  elem->SetDesign(fighter->GetDesign());
673  elem->SetCount(fighter->Count());
674  elem->SetDeadCount(fighter->DeadCount());
675  elem->SetMaintCount(maint_count);
676  elem->SetIFF(fighter->GetIFF());
677  elem->SetIntelLevel(g->IntelLevel());
678  elem->SetRegion(fighter->GetRegion());
679 
680  elem->SetCarrier(carrier->Name());
681  elem->SetCommander(carrier->Name());
682  elem->SetLocation(carrier->Location() + RandomPoint());
683 
684  elem->SetCombatGroup(g);
685  elem->SetCombatUnit(fighter);
686 
687  mission->AddElement(elem);
688 }
689 
690 void
692 {
693  int pkg_size = 2;
694 
696  if (request && request->GetObjective()) {
697  int tgt_type = request->GetObjective()->Type();
698 
699  if (tgt_type >= CombatGroup::FLEET && tgt_type <= CombatGroup::CARRIER_GROUP)
700  pkg_size = 4;
701 
702  if (tgt_type == CombatGroup::STATION || tgt_type == CombatGroup::STARBASE)
703  pkg_size = 4;
704  }
705  }
706 
707  MissionElement* elem = CreateFighterPackage(g, pkg_size, mission->Type());
708 
709  if (elem) {
711  elem->SetAlert(p ? !p->FlyingStart() : true);
712  elem->SetPlayer(1);
713 
714  if (ward) {
715  Point approach = elem->Location() - ward->Location();
716  approach.Normalize();
717 
718  Point pickup = ward->Location() + approach * 50e3;
719  double delta = (pickup - elem->Location()).length();
720 
721  if (delta > 30e3) {
722  Instruction* n = new(__FILE__,__LINE__) Instruction(elem->Region(), pickup, Instruction::ESCORT);
723  n->SetTarget(ward->Name());
724  n->SetSpeed(750);
725  elem->AddNavPoint(n);
726  }
727 
728  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, ward->Name());
729 
730  switch (mission->Type()) {
732  obj->SetTargetDesc(Text("the star freighter ") + ward->Name());
733  break;
734 
736  obj->SetTargetDesc(Text("the shuttle ") + ward->Name());
737  break;
738 
740  obj->SetTargetDesc(Text("the ") + ward->Name() + Text(" strike package"));
741  break;
742 
743  case Mission::DEFEND:
744  obj->SetTargetDesc(Text("the ") + ward->Name());
745  break;
746 
747  default:
748  if (ward->GetCombatGroup()) {
749  obj->SetTargetDesc(Text("the ") + ward->GetCombatGroup()->GetDescription());
750  }
751  else {
752  obj->SetTargetDesc(Text("the ") + ward->Name());
753  }
754  break;
755  }
756 
757  elem->AddObjective(obj);
758  }
759 
760  mission->AddElement(elem);
761 
762  player_elem = elem;
763  }
764 }
765 
766 // +--------------------------------------------------------------------+
767 
768 void
770 {
771  List<MissionElement> patrols;
772 
774  while (++iter) {
775  MissionElement* squad_elem = iter.value();
776  CombatGroup* squadron = squad_elem->GetCombatGroup();
777  CombatUnit* unit = squad_elem->GetCombatUnit();
778 
779  if (!squad_elem->IsSquadron() || !squadron || !unit || unit->LiveCount() < 4)
780  continue;
781 
782  if (squadron->Type() == CombatGroup::INTERCEPT_SQUADRON ||
783  squadron->Type() == CombatGroup::FIGHTER_SQUADRON) {
784 
785  StarSystem* system = mission->GetStarSystem();
786  CombatGroup* base = squadron->FindCarrier();
787 
788  if (!base)
789  continue;
790 
791  OrbitalRegion* region = system->FindRegion(base->GetRegion());
792 
793  if (!region)
794  continue;
795 
796  int patrol_type = Mission::PATROL;
797  Point base_loc;
798 
799  if (region->Type() == Orbital::TERRAIN) {
800  patrol_type = Mission::AIR_PATROL;
801 
802  if (RandomChance(2,3))
803  continue;
804  }
805 
806  base_loc = base->Location() + RandomPoint() * 1.5;
807 
808  if (region->Type() == Orbital::TERRAIN)
809  base_loc += Point(0, 0, 14.0e3);
810 
811  MissionElement* elem = CreateFighterPackage(squadron, 2, patrol_type);
812  if (elem) {
814  elem->SetRegion(base->GetRegion());
815  elem->SetLocation(base_loc);
816  patrols.append(elem);
817  }
818  }
819  }
820 
821  iter.attach(patrols);
822  while (++iter)
823  mission->AddElement(iter.value());
824 }
825 
826 // +--------------------------------------------------------------------+
827 
828 void
830 {
831  switch (mission->Type()) {
835  default: break;
836  }
837 }
838 
839 void
841 {
842  if (!mission || !mission->GetStarSystem()) return;
843 
844  CombatUnit* carrier = FindCarrier(squadron);
845  CombatGroup* freight = 0;
846 
847  if (request)
848  freight = request->GetObjective();
849 
850  if (!freight)
852 
853  if (!freight || freight->CalcValue() < 1) return;
854 
855  CombatUnit* unit = freight->GetNextUnit();
856  if (!unit) return;
857 
858  MissionElement* elem = CreateSingleElement(freight, unit);
859  if (!elem) return;
860 
863  elem->SetRegion(squadron->GetRegion());
864 
865  if (carrier)
866  elem->SetLocation(carrier->Location() + RandomPoint() * 2);
867 
868  ward = elem;
869  mission->AddElement(elem);
870 
871 
872  StarSystem* system = mission->GetStarSystem();
873  OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
874  Point delta = rgn1->Location() - rgn1->Primary()->Location();
875  Point npt_loc = elem->Location();
876  Instruction* n = 0;
877 
878  delta.Normalize();
879  delta *= 200.0e3;
880 
881  npt_loc += delta;
882 
883  n = new(__FILE__,__LINE__) Instruction(elem->Region(),
884  npt_loc,
886 
887  if (n) {
888  n->SetSpeed(500);
889  elem->AddNavPoint(n);
890  }
891 
892  Text rgn2 = elem->Region();
893  List<CombatZone>& zones = campaign->GetZones();
894  if (zones[zones.size()-1]->HasRegion(rgn2))
895  rgn2 = *zones[0]->GetRegions()[0];
896  else
897  rgn2 = *zones[zones.size()-1]->GetRegions()[0];
898 
899  n = new(__FILE__,__LINE__) Instruction(rgn2,
900  Point(0, 0, 0),
902 
903  if (n) {
904  n->SetSpeed(750);
905  elem->AddNavPoint(n);
906  }
907 }
908 
909 void
911 {
912  if (!mission || !mission->GetStarSystem()) return;
913 
914  CombatUnit* carrier = FindCarrier(squadron);
916 
917  if (!shuttle || shuttle->CalcValue() < 1) return;
918 
919  List<CombatUnit>& units = shuttle->GetUnits();
920 
922  if (!elem) return;
923 
925  elem->SetRegion(orb_region);
926  elem->Loadouts().destroy();
927 
928  if (carrier)
929  elem->SetLocation(carrier->Location() + RandomPoint() * 2);
930 
931  ward = elem;
932  mission->AddElement(elem);
933 
934  // if there is terrain nearby, then have the shuttle fly down to it:
935  if (air_region.length() > 0) {
936  StarSystem* system = mission->GetStarSystem();
937  OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
938  Point delta = rgn1->Location() - rgn1->Primary()->Location();
939  Point npt_loc = elem->Location();
940  Instruction* n = 0;
941 
942  delta.Normalize();
943  delta *= -200.0e3;
944 
945  npt_loc += delta;
946 
947  n = new(__FILE__,__LINE__) Instruction(elem->Region(),
948  npt_loc,
950 
951  if (n) {
952  n->SetSpeed(500);
953  elem->AddNavPoint(n);
954  }
955 
956  n = new(__FILE__,__LINE__) Instruction(air_region,
957  Point(0, 0, 10.0e3),
959 
960  if (n) {
961  n->SetSpeed(500);
962  elem->AddNavPoint(n);
963  }
964  }
965 
966  // otherwise, escort the shuttle in for a landing on the carrier:
967  else if (carrier) {
968  Point src = carrier->Location() + RandomDirection() * 150e3;
969  Point dst = carrier->Location() + RandomDirection() * 25e3;
970  Instruction* n = 0;
971 
972  elem->SetLocation(src);
973 
974  n = new(__FILE__,__LINE__) Instruction(elem->Region(), dst, Instruction::DOCK);
975  if (n) {
976  n->SetTarget(carrier->Name());
977  n->SetSpeed(500);
978  elem->AddNavPoint(n);
979  }
980  }
981 }
982 
983 void
985 {
986  if (!mission || !mission->GetStarSystem()) return;
987 
988  CombatUnit* carrier = FindCarrier(squadron);
989  CombatGroup* strike = strike_group;
990 
991  if (!strike || strike->CalcValue() < 1) return;
992 
993  List<CombatUnit>& units = strike->GetUnits();
994 
995  int type = Mission::ASSAULT;
996 
997  if (airborne)
998  type = Mission::STRIKE;
999 
1000  MissionElement* elem = CreateFighterPackage(strike, 2, type);
1001  if (!elem) return;
1002 
1003  if (strike->GetParent() == squadron->GetParent()) {
1005  elem->SetAlert(p ? !p->FlyingStart() : true);
1006  }
1007 
1008  elem->SetIntelLevel(Intel::KNOWN);
1009  elem->SetRegion(squadron->GetRegion());
1010 
1011  if (strike_target) {
1012  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, strike_target->Name());
1013 
1014  if (obj) {
1015  if (airborne)
1017 
1018  elem->AddObjective(obj);
1019  }
1020  }
1021 
1022  ward = elem;
1023  mission->AddElement(elem);
1024 
1025 
1026  StarSystem* system = mission->GetStarSystem();
1027  OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
1028  Point delta = rgn1->Location() - rgn1->Primary()->Location();
1029  Point npt_loc = elem->Location();
1030  Instruction* n = 0;
1031 
1032  if (airborne) {
1033  delta.Normalize();
1034  delta *= -30.0e3;
1035  npt_loc += delta;
1036 
1037  n = new(__FILE__,__LINE__) Instruction(elem->Region(),
1038  npt_loc,
1040  if (n) {
1041  n->SetSpeed(500);
1042  elem->AddNavPoint(n);
1043  }
1044 
1045  npt_loc = Point(0, 0, 10.0e3);
1046 
1047  n = new(__FILE__,__LINE__) Instruction(air_region,
1048  npt_loc,
1050  if (n) {
1051  n->SetSpeed(500);
1052  elem->AddNavPoint(n);
1053  }
1054  }
1055 
1056  // IP:
1057  if (strike_target) {
1058  delta = strike_target->Location() - npt_loc;
1059  delta.Normalize();
1060  delta *= 15.0e3;
1061 
1062  npt_loc = strike_target->Location() + delta + Point(0, 0, 8.0e3);
1063 
1064  n = new(__FILE__,__LINE__) Instruction(strike_target->GetRegion(),
1065  npt_loc,
1067  if (n) {
1068  n->SetSpeed(500);
1069  elem->AddNavPoint(n);
1070  }
1071  }
1072 
1073  if (airborne) {
1074  n = new(__FILE__,__LINE__) Instruction(air_region,
1075  Point(0, 0, 30.0e3),
1077  if (n) {
1078  n->SetSpeed(500);
1079  elem->AddNavPoint(n);
1080  }
1081  }
1082 
1083  if (carrier) {
1084  n = new(__FILE__,__LINE__) Instruction(elem->Region(),
1085  carrier->Location() - Point(0, -20.0e3, 0),
1087  if (n) {
1088  n->SetSpeed(500);
1089  elem->AddNavPoint(n);
1090  }
1091  }
1092 
1093  // find the strike target element:
1094  if (strike_target) {
1096  }
1097 }
1098 
1099 // +--------------------------------------------------------------------+
1100 
1101 void
1103 {
1104  bool escort_needed = false;
1105 
1107  if (request && request->GetObjective()) {
1108  int tgt_type = request->GetObjective()->Type();
1109 
1110  if (tgt_type == CombatGroup::CARRIER_GROUP ||
1111  tgt_type == CombatGroup::STATION ||
1112  tgt_type == CombatGroup::STARBASE)
1113 
1114  escort_needed = true;
1115  }
1116  }
1117 
1118  if (player_elem && escort_needed) {
1120 
1121  if (s && s->IsAssignable()) {
1123 
1124  if (elem) {
1125  Point offset = Point(2.0e3, 2.0e3, 1.0e3);
1126 
1128  while (++npt_iter) {
1129  Instruction* npt = npt_iter.value();
1130  Instruction* n = new(__FILE__,__LINE__) Instruction(npt->RegionName(),
1131  npt->Location() + offset,
1133  if (n) {
1134  n->SetSpeed(npt->Speed());
1135  elem->AddNavPoint(n);
1136  }
1137  }
1138 
1139  mission->AddElement(elem);
1140  }
1141  }
1142  }
1143 }
1144 
1145 // +--------------------------------------------------------------------+
1146 
1147 void
1149 {
1150  switch (mission->Type()) {
1151  default:
1152  case Mission::DEFEND:
1153  case Mission::PATROL: CreateTargetsPatrol(); break;
1154  case Mission::SWEEP: CreateTargetsSweep(); break;
1157 
1158  case Mission::ESCORT:
1161  case Mission::STRIKE: CreateTargetsStrike(); break;
1162  case Mission::ASSAULT: CreateTargetsAssault(); break;
1163  }
1164 }
1165 
1166 void
1168 {
1169  if (!squadron || !player_elem) return;
1170 
1171  Text region = squadron->GetRegion();
1172  Point base_loc = player_elem->Location();
1173  Point patrol_loc;
1174 
1175  if (airborne)
1176  base_loc = RandomPoint() * 2 + Point(0, 0, 12.0e3);
1177 
1178  else if (carrier_elem)
1179  base_loc = carrier_elem->Location();
1180 
1181  if (airborne) {
1182  if (!airbase)
1184  region = air_region;
1185  patrol_loc = base_loc +
1186  RandomDirection() * Random( 60e3, 100e3);
1187  }
1188  else {
1189  patrol_loc = base_loc +
1190  RandomDirection() * Random(110e3, 160e3);
1191  }
1192 
1193  Instruction* n = new(__FILE__,__LINE__) Instruction(region,
1194  patrol_loc,
1196  if (n)
1198 
1199  int ntargets = (int) Random(2.0,5.1);
1200 
1201  while (ntargets > 0) {
1202  int t = CreateRandomTarget(region, patrol_loc);
1203  ntargets -= t;
1204  if (t < 1) break;
1205  }
1206 
1207  if (airborne && !airbase) {
1209  }
1210 
1211  Instruction* obj = new(__FILE__,__LINE__) Instruction(*n);
1212  obj->SetTargetDesc("inbound enemy units");
1213  player_elem->AddObjective(obj);
1214 
1215  if (carrier_elem && !airborne) {
1216  obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier_elem->Name());
1217  if (obj) {
1218  obj->SetTargetDesc(Text("the ") + carrier_elem->Name() + " battle group");
1219  player_elem->AddObjective(obj);
1220  }
1221  }
1222 }
1223 
1224 void
1226 {
1227  if (!squadron || !player_elem) return;
1228 
1229  double traverse = PI;
1230  double a = Random(-PI/2, PI/2);
1231  Point base_loc = player_elem->Location();
1232  Point sweep_loc = base_loc;
1233  Text region = player_elem->Region();
1234  Instruction* n = 0;
1235 
1236  if (carrier_elem)
1237  base_loc = carrier_elem->Location();
1238 
1239  if (airborne) {
1241  region = air_region;
1242  sweep_loc = RandomPoint() + Point(0, 0, 10.0e3); // keep it airborne!
1243  }
1244 
1245  sweep_loc += Point(sin(a), -cos(a), 0) * 100.0e3;
1246 
1247  n = new(__FILE__,__LINE__) Instruction(region,
1248  sweep_loc,
1250  if (n) {
1251  n->SetSpeed(750);
1253  }
1254 
1255  int index = 0;
1256  int ntargets = 6;
1257 
1258  while (traverse > 0) {
1259  double a1 = Random(PI/4, PI/2);
1260  traverse -= a1;
1261  a += a1;
1262 
1263  sweep_loc += Point(sin(a), -cos(a), 0) * 80.0e3;
1264 
1265  n = new(__FILE__,__LINE__) Instruction(region,
1266  sweep_loc,
1268  if (n) {
1269  n->SetSpeed(750);
1272  }
1273 
1274  if (ntargets && RandomChance()) {
1275  ntargets -= CreateRandomTarget(region, sweep_loc);
1276  }
1277 
1278  index++;
1279  }
1280 
1281  if (ntargets > 0)
1282  CreateRandomTarget(region, sweep_loc);
1283 
1284  if (airborne && !airbase) {
1286  region = player_elem->Region();
1287  }
1288 
1289  sweep_loc = base_loc;
1290  sweep_loc.y += 30.0e3;
1291 
1292  n = new(__FILE__,__LINE__) Instruction(region,
1293  sweep_loc,
1295  if (n) {
1296  n->SetSpeed(750);
1298  }
1299 
1300  Instruction* obj = new(__FILE__,__LINE__) Instruction(region,
1301  sweep_loc,
1303  if (obj) {
1304  obj->SetTargetDesc("enemy patrols");
1305  player_elem->AddObjective(obj);
1306  }
1307 
1308  if (carrier_elem && !airborne) {
1309  obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier_elem->Name());
1310  if (obj) {
1311  obj->SetTargetDesc(Text("the ") + carrier_elem->Name() + " battle group");
1312  player_elem->AddObjective(obj);
1313  }
1314  }
1315 }
1316 
1317 void
1319 {
1320  if (!squadron || !player_elem) return;
1321 
1322  CombatUnit* carrier = FindCarrier(squadron);
1325 
1326  if (!s || !s2) return;
1327 
1328  int ninbound = 2 + (int) (RandomIndex() < 5);
1329  bool second = ninbound > 2;
1330  Text attacker;
1331 
1332  while (ninbound--) {
1334  if (elem) {
1335  elem->SetIntelLevel(Intel::KNOWN);
1336  elem->Loadouts().destroy();
1337  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Hvy Ship Strike"));
1338 
1339  if (carrier) {
1340  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, carrier->Name());
1341  if (obj) {
1342  elem->AddObjective(obj);
1343  elem->SetLocation(carrier->Location() + RandomPoint() * 6);
1344  }
1345  }
1346  else {
1347  elem->SetLocation(squadron->Location() + RandomPoint() * 5);
1348  }
1349 
1350  mission->AddElement(elem);
1351 
1352  attacker = elem->Name();
1353 
1354  if (!prime_target) {
1355  prime_target = elem;
1356  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::INTERCEPT, attacker);
1357  if (obj) {
1358  obj->SetTargetDesc(Text("inbound strike package '") + elem->Name() + "'");
1359  player_elem->AddObjective(obj);
1360  }
1361  }
1362 
1364  if (e2) {
1366  e2->SetLocation(elem->Location() + RandomPoint() * 0.25);
1367 
1368  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1369  if (obj)
1370  e2->AddObjective(obj);
1371  mission->AddElement(e2);
1372  }
1373  }
1374  }
1375 
1376  if (second) {
1377  // second friendly fighter package
1379 
1380  if (s) {
1382  if (elem) {
1384  elem->SetAlert(p ? !p->FlyingStart() : true);
1385 
1386  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::INTERCEPT, attacker);
1387  if (obj)
1388  elem->AddObjective(obj);
1389  mission->AddElement(elem);
1390  }
1391  }
1392  }
1393 
1394  if (carrier && !airborne) {
1395  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::DEFEND, carrier->Name());
1396  if (obj) {
1397  obj->SetTargetDesc(Text("the ") + carrier->Name() + " battle group");
1398  player_elem->AddObjective(obj);
1399  }
1400  }
1401 }
1402 
1403 void
1405 {
1406  if (!squadron || !player_elem) return;
1407 
1408  if (!ward) {
1410  return;
1411  }
1412 
1413  CombatUnit* carrier = FindCarrier(squadron);
1416 
1417  if (!s) s = s2;
1418 
1419  if (!s || !s2) return;
1420 
1422  if (elem) {
1423  elem->SetIntelLevel(Intel::KNOWN);
1424 
1425  elem->SetLocation(ward->Location() + RandomPoint() * 5);
1426 
1427  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, ward->Name());
1428  if (obj)
1429  elem->AddObjective(obj);
1430  mission->AddElement(elem);
1431 
1433  if (e2) {
1435  e2->SetLocation(elem->Location() + RandomPoint() * 0.25);
1436 
1437  Instruction* obj2 = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1438  if (obj2)
1439  e2->AddObjective(obj2);
1440  mission->AddElement(e2);
1441  }
1442  }
1443 
1444  Instruction* obj3 = new(__FILE__,__LINE__) Instruction(mission->GetRegion(),
1445  Point(0,0,0),
1447 
1448  if (obj3) {
1449  obj3->SetTargetDesc("enemy patrols");
1450  player_elem->AddObjective(obj3);
1451  }
1452 }
1453 
1454 void
1456 {
1458 }
1459 
1460 // +--------------------------------------------------------------------+
1461 
1462 void
1464 {
1465  if (!squadron || !player_elem) return;
1466 
1467  if (ward) {
1468  Point offset = Point(2.0e3, 2.0e3, 1.0e3);
1469 
1470  ListIter<Instruction> npt_iter = ward->NavList();
1471  while (++npt_iter) {
1472  Instruction* npt = npt_iter.value();
1473  Instruction* n = new(__FILE__,__LINE__) Instruction(npt->RegionName(),
1474  npt->Location() + offset,
1476  if (n) {
1477  n->SetSpeed(npt->Speed());
1479  }
1480  }
1481  }
1482 }
1483 
1484 // +--------------------------------------------------------------------+
1485 
1486 void
1488 {
1489  if (!squadron || !player_elem) return;
1490 
1491  if (request && request->GetObjective())
1493 
1494  if (strike_target && strike_group) {
1496 
1498  while (++e_iter) {
1499  MissionElement* elem = e_iter.value();
1500 
1501  if (elem->GetCombatGroup() == strike_target) {
1502  prime_target = elem;
1503  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::STRIKE, elem->Name());
1504  if (obj) {
1505  obj->SetTargetDesc(Text("preplanned target '") + elem->Name() + "'");
1506  player_elem->AddObjective(obj);
1507  }
1508 
1509  // create flight plan:
1510  RLoc rloc;
1511  Point loc = Point(0, 0, 15e3);
1512  Instruction* n = 0;
1513 
1515 
1516  // target approach and strike:
1517  Point delta = prime_target->Location() - loc;
1518 
1519  if (delta.length() >= 100e3) {
1520  Point mid = loc + delta * 0.5;
1521  mid.z = 10.0e3;
1522 
1523  rloc.SetReferenceLoc(0);
1524  rloc.SetBaseLocation(mid);
1525  rloc.SetDistance(20e3);
1526  rloc.SetDistanceVar(5e3);
1527  rloc.SetAzimuth(90*DEGREES);
1528  rloc.SetAzimuthVar(25*DEGREES);
1529 
1530  n = new(__FILE__,__LINE__) Instruction(prime_target->Region(),
1531  Point(),
1533  if (n) {
1534  n->SetSpeed(750);
1535  n->GetRLoc() = rloc;
1537  }
1538 
1539  loc = mid;
1540  }
1541 
1542  delta = loc - prime_target->Location();
1543  delta.Normalize();
1544  delta *= 25.0e3;
1545 
1546  loc = prime_target->Location() + delta;
1547  loc.z = 8.0e3;
1548 
1549  n = new(__FILE__,__LINE__) Instruction(prime_target->Region(),
1550  loc,
1552  if (n) {
1553  n->SetSpeed(500);
1555  }
1556 
1557  // exeunt:
1558  rloc.SetReferenceLoc(0);
1559  rloc.SetBaseLocation(Point(0, 0, 30.0e3));
1560  rloc.SetDistance(50e3);
1561  rloc.SetDistanceVar(5e3);
1562  rloc.SetAzimuth(-90*DEGREES);
1563  rloc.SetAzimuthVar(25*DEGREES);
1564 
1565  n = new(__FILE__,__LINE__) Instruction(prime_target->Region(),
1566  Point(),
1568  if (n) {
1569  n->SetSpeed(750);
1570  n->GetRLoc() = rloc;
1572  }
1573 
1574  if (carrier_elem) {
1575  rloc.SetReferenceLoc(0);
1577  rloc.SetDistance(60e3);
1578  rloc.SetDistanceVar(10e3);
1579  rloc.SetAzimuth(180*DEGREES);
1580  rloc.SetAzimuthVar(30*DEGREES);
1581 
1582  n = new(__FILE__,__LINE__) Instruction(carrier_elem->Region(),
1583  Point(),
1585  if (n) {
1586  n->SetSpeed(750);
1587  n->GetRLoc() = rloc;
1589  }
1590  }
1591 
1592  break;
1593  }
1594  }
1595  }
1596 }
1597 
1598 // +--------------------------------------------------------------------+
1599 
1600 void
1602 {
1603  if (!squadron || !player_elem) return;
1604 
1605  CombatGroup* assigned = 0;
1606 
1607  if (request)
1608  assigned = request->GetObjective();
1609 
1610  if (assigned) {
1611  if (assigned->Type() > CombatGroup::WING && assigned->Type() < CombatGroup::FLEET) {
1613  }
1614  else {
1615  CreateElements(assigned);
1616  }
1617 
1618  // select the prime target element - choose the lowest ranking
1619  // unit of a DESRON, CBG, or CVBG:
1620 
1622  while (++e_iter) {
1623  MissionElement* elem = e_iter.value();
1624 
1625  if (elem->GetCombatGroup() == assigned) {
1626  if (!prime_target || assigned->Type() <= CombatGroup::CARRIER_GROUP) {
1627  prime_target = elem;
1628  }
1629  }
1630  }
1631 
1632  if (prime_target) {
1633  MissionElement* elem = prime_target;
1634 
1635  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, elem->Name());
1636  if (obj) {
1637  obj->SetTargetDesc(Text("preplanned target '") + elem->Name() + "'");
1638  player_elem->AddObjective(obj);
1639  }
1640 
1641  // create flight plan:
1642  RLoc rloc;
1643  Vec3 dummy(0,0,0);
1644  Instruction* instr = 0;
1645  Point loc = player_elem->Location();
1646  Point tgt = elem->Location();
1647  Point mid;
1648 
1649  CombatGroup* tgt_group = elem->GetCombatGroup();
1650  if (tgt_group && tgt_group->GetFirstUnit() && tgt_group->IsMovable()) {
1651  tgt = tgt_group->GetFirstUnit()->Location();
1652  }
1653 
1654  if (carrier_elem)
1655  loc = carrier_elem->Location();
1656 
1657  mid = loc + (elem->Location() - loc) * 0.5;
1658 
1659  rloc.SetReferenceLoc(0);
1660  rloc.SetBaseLocation(mid);
1661  rloc.SetDistance(40e3);
1662  rloc.SetDistanceVar(5e3);
1663  rloc.SetAzimuth(90*DEGREES);
1664  rloc.SetAzimuthVar(45*DEGREES);
1665 
1666  instr = new(__FILE__,__LINE__) Instruction(elem->Region(), dummy, Instruction::VECTOR);
1667  if (instr) {
1668  instr->SetSpeed(750);
1669  instr->GetRLoc() = rloc;
1670 
1671  player_elem->AddNavPoint(instr);
1672 
1673  if (RandomChance()) {
1674  CreateRandomTarget(elem->Region(), rloc.Location());
1675  }
1676  }
1677 
1678  rloc.SetReferenceLoc(0);
1679  rloc.SetBaseLocation(tgt);
1680  rloc.SetDistance(60e3);
1681  rloc.SetDistanceVar(5e3);
1682  rloc.SetAzimuth(120*DEGREES);
1683  rloc.SetAzimuthVar(15*DEGREES);
1684 
1685  instr = new(__FILE__,__LINE__) Instruction(elem->Region(), dummy, Instruction::ASSAULT);
1686  if (instr) {
1687  instr->SetSpeed(750);
1688  instr->GetRLoc() = rloc;
1689  instr->SetTarget(elem->Name());
1690 
1691  player_elem->AddNavPoint(instr);
1692  }
1693 
1694  if (carrier_elem) {
1695  rloc.SetReferenceLoc(0);
1696  rloc.SetBaseLocation(loc);
1697  rloc.SetDistance(30e3);
1698  rloc.SetDistanceVar(0);
1699  rloc.SetAzimuth(180*DEGREES);
1700  rloc.SetAzimuthVar(60*DEGREES);
1701 
1702  instr = new(__FILE__,__LINE__) Instruction(carrier_elem->Region(), dummy, Instruction::RTB);
1703  if (instr) {
1704  instr->SetSpeed(500);
1705  instr->GetRLoc() = rloc;
1706 
1707  player_elem->AddNavPoint(instr);
1708  }
1709  }
1710  }
1711  }
1712 }
1713 
1714 // +--------------------------------------------------------------------+
1715 
1716 int
1718 {
1719  if (!mission) return 0;
1720 
1721  int ntargets = 0;
1722  int ttype = RandomIndex();
1723  bool oca = (mission->Type() == Mission::SWEEP);
1724 
1725  if (ttype < 8) {
1726  CombatGroup* s = 0;
1727 
1728  if (ttype < 4)
1730  else
1732 
1733  if (s) {
1735  if (elem) {
1736  elem->SetIntelLevel(Intel::KNOWN);
1737  elem->SetRegion(rgn);
1738  elem->SetLocation(base_loc + RandomPoint() * 1.5);
1739  mission->AddElement(elem);
1740  ntargets++;
1741  }
1742  }
1743  }
1744  else if (ttype < 12) {
1745  if (oca) {
1747 
1748  if (s) {
1750  if (elem) {
1751  elem->SetIntelLevel(Intel::KNOWN);
1752  elem->SetRegion(rgn);
1753  elem->SetLocation(base_loc + RandomPoint() * 2);
1754  mission->AddElement(elem);
1755  ntargets++;
1756 
1758 
1759  if (s2) {
1761  if (e2) {
1763  e2->SetRegion(rgn);
1764  e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
1765 
1766  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1767  if (obj)
1768  e2->AddObjective(obj);
1769  mission->AddElement(e2);
1770  ntargets++;
1771  }
1772  }
1773  }
1774  }
1775  }
1776  else {
1778 
1779  if (s) {
1781  if (elem) {
1782  elem->SetIntelLevel(Intel::KNOWN);
1783  elem->SetRegion(rgn);
1784  elem->SetLocation(base_loc + RandomPoint() * 1.3);
1785  mission->AddElement(elem);
1786  ntargets++;
1787  }
1788  }
1789  }
1790  }
1791  else if (ttype < 15) {
1792  if (oca) {
1793  CombatGroup* s = 0;
1794 
1795  if (airborne)
1797  else
1799 
1800  if (s) {
1802  if (elem) {
1803  elem->SetIntelLevel(Intel::KNOWN);
1804  elem->SetRegion(rgn);
1805  elem->SetLocation(base_loc + RandomPoint() * 2);
1806  mission->AddElement(elem);
1807  ntargets++;
1808 
1810 
1811  if (s2) {
1813  if (e2) {
1815  e2->SetRegion(rgn);
1816  e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
1817 
1818  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1819  if (obj)
1820  e2->AddObjective(obj);
1821  mission->AddElement(e2);
1822  ntargets++;
1823  }
1824  }
1825  }
1826  }
1827  }
1828  else {
1830 
1831  if (s) {
1833  if (elem) {
1834  elem->SetIntelLevel(Intel::KNOWN);
1835  elem->SetRegion(rgn);
1836  elem->SetLocation(base_loc + RandomPoint() * 1.1);
1837  mission->AddElement(elem);
1838  ntargets++;
1839 
1841 
1842  if (s2) {
1844  if (e2) {
1846  e2->SetRegion(rgn);
1847  e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
1848 
1849  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1850  if (obj)
1851  e2->AddObjective(obj);
1852  mission->AddElement(e2);
1853  ntargets++;
1854  }
1855  }
1856  }
1857  }
1858  }
1859  }
1860  else {
1862 
1863  if (s) {
1865  if (elem) {
1866  elem->SetIntelLevel(Intel::KNOWN);
1867  elem->SetRegion(rgn);
1868  elem->SetLocation(base_loc + RandomPoint() * 2);
1869  mission->AddElement(elem);
1870  ntargets++;
1871  }
1872  }
1873  }
1874 
1875  return ntargets;
1876 }
1877 
1878 // +--------------------------------------------------------------------+
1879 
1880 void
1882 {
1883  if (!mission || !elem) return;
1884  if (!mission->GetStarSystem()) return;
1885 
1886  MissionElement* carrier = mission->FindElement(elem->Commander());
1887  StarSystem* system = mission->GetStarSystem();
1888  OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
1889  OrbitalRegion* rgn2 = system->FindRegion(air_region);
1890  Point npt_loc = elem->Location();
1891  Instruction* n = 0;
1893 
1894  int flying_start = p ? p->FlyingStart() : 0;
1895 
1896  if (carrier && !flying_start) {
1897  npt_loc = carrier->Location() + Point(1e3, -5e3, 0);
1898  }
1899 
1900  if (rgn1 && rgn2) {
1901  double delta_t = mission->Start() - campaign->GetTime();
1902  Point r1 = rgn1->PredictLocation(delta_t);
1903  Point r2 = rgn2->PredictLocation(delta_t);
1904 
1905  Point delta = r2 - r1;
1906 
1907  delta.y *= -1;
1908  delta.Normalize();
1909  delta *= 10e3;
1910 
1911  npt_loc += delta;
1912 
1913  n = new(__FILE__,__LINE__) Instruction(elem->Region(),
1914  npt_loc,
1916  if (n) {
1917  n->SetSpeed(750);
1918  elem->AddNavPoint(n);
1919  }
1920  }
1921 
1922  n = new(__FILE__,__LINE__) Instruction(air_region,
1923  Point(0, 0, 15e3),
1925  if (n) {
1926  n->SetSpeed(750);
1927  elem->AddNavPoint(n);
1928  }
1929 }
1930 
1931 void
1933 {
1934  Instruction* n = new(__FILE__,__LINE__) Instruction(air_region,
1935  Point(0, 0, 30.0e3),
1937  if (n) {
1938  n->SetSpeed(750);
1939  elem->AddNavPoint(n);
1940  }
1941 }
1942 
1943 // +--------------------------------------------------------------------+
1944 
1947 {
1948  if (!squadron) return 0;
1949 
1950  CombatUnit* fighter = squadron->GetUnits().at(0);
1951  CombatUnit* carrier = FindCarrier(squadron);
1952 
1953  if (!fighter)
1954  return 0;
1955 
1956  int avail = fighter->LiveCount();
1957  int actual = count;
1958 
1959  if (avail < actual)
1960  actual = avail;
1961 
1962  if (avail < 1) {
1963  ::Print("CMF - Insufficient fighters in squadron '%s' - %d required, %d available\n",
1964  squadron->Name().data(), count, avail);
1965  return 0;
1966  }
1967 
1968  MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
1969  if (!elem) {
1970  Exit();
1971  return 0;
1972  }
1973 
1974  elem->SetName(Callsign::GetCallsign(fighter->GetIFF()));
1975  elem->SetElementID(pkg_id++);
1976 
1977  if (carrier) {
1978  elem->SetCommander(carrier->Name());
1979  elem->SetHeading(carrier->GetHeading());
1980  }
1981  else {
1982  elem->SetHeading(fighter->GetHeading());
1983  }
1984 
1985  elem->SetDesign(fighter->GetDesign());
1986  elem->SetCount(actual);
1987  elem->SetIFF(fighter->GetIFF());
1988  elem->SetIntelLevel(squadron->IntelLevel());
1989  elem->SetRegion(fighter->GetRegion());
1990  elem->SetSquadron(squadron->Name());
1991  elem->SetMissionRole(role);
1992 
1993  switch (role) {
1994  case Mission::ASSAULT:
1995  if (request->GetObjective() &&
1997  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Rockets"));
1998  else
1999  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ship Strike"));
2000  break;
2001 
2002  case Mission::STRIKE:
2003  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ground Strike"));
2004  break;
2005 
2006  default:
2007  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "ACM Medium Range"));
2008  break;
2009  }
2010 
2011  if (carrier) {
2012  Point offset = RandomPoint() * 0.3;
2013  offset.y = fabs(offset.y);
2014  offset.z += 2e3;
2015  elem->SetLocation(carrier->Location() + offset);
2016  }
2017  else {
2018  elem->SetLocation(fighter->Location() + RandomPoint());
2019  }
2020 
2021  elem->SetCombatGroup(squadron);
2022  elem->SetCombatUnit(fighter);
2023 
2024  return elem;
2025 }
2026 
2027 // +--------------------------------------------------------------------+
2028 
2029 static CombatGroup* FindCombatGroup(CombatGroup* g, int type)
2030 {
2031  if (g->IntelLevel() <= Intel::RESERVE)
2032  return 0;
2033 
2034  if (g->GetUnits().size() > 0) {
2035  for (int i = 0; i < g->GetUnits().size(); i++) {
2036  CombatUnit* u = g->GetUnits().at(i);
2037  if (g->Type() == type && u->LiveCount() > 0)
2038  return g;
2039  }
2040  }
2041 
2042  CombatGroup* result = 0;
2043 
2044  ListIter<CombatGroup> subgroup = g->GetComponents();
2045  while (++subgroup && !result)
2046  result = FindCombatGroup(subgroup.value(), type);
2047 
2048  return result;
2049 }
2050 
2051 // +--------------------------------------------------------------------+
2052 
2053 CombatGroup*
2055 {
2056  if (!squadron) return 0;
2057 
2058  CombatGroup* result = 0;
2060 
2061  if (campaign) {
2062  ListIter<Combatant> combatant = campaign->GetCombatants();
2063  while (++combatant && !result) {
2064  if (combatant->GetIFF() == iff) {
2065  result = ::FindCombatGroup(combatant->GetForce(), type);
2066 
2067  if (result && result->CountUnits() < 1) {
2068  result = 0;
2069  }
2070  }
2071  }
2072  }
2073 
2074  return result;
2075 }
2076 
2077 // +--------------------------------------------------------------------+
2078 
2079 void
2081 {
2082  if (!mission || !player_elem) return;
2083 
2085  if (ward) mission->SetWard(ward);
2086 
2087  Text objectives;
2088 
2089  for (int i = 0; i < player_elem->Objectives().size(); i++) {
2090  Instruction* obj = player_elem->Objectives().at(i);
2091  objectives += "* ";
2092  objectives += obj->GetDescription();
2093  objectives += ".\n";
2094  }
2095 
2096  mission->SetObjective(objectives);
2097 }
2098 
2099 // +--------------------------------------------------------------------+
2100 
2101 MissionInfo*
2103 {
2104  if (!mission || !player_elem) return 0;
2105 
2106  char name[256];
2107  char player_info[256];
2108 
2110  sprintf_s(name, "MSN-%03d %s", mission->Identity(), mission_info->name.data());
2111  else if (ward)
2112  sprintf_s(name, "MSN-%03d %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(), ward->Name().data());
2113  else if (prime_target)
2114  sprintf_s(name, "MSN-%03d %s %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(),
2116  prime_target->Name().data());
2117  else
2118  sprintf_s(name, "MSN-%03d %s", mission->Identity(), Game::GetText(mission->TypeName()).data());
2119 
2120  if (player_elem) {
2121  sprintf_s(player_info, "%d x %s %s '%s'",
2122  player_elem->Count(),
2123  (const char*) player_elem->GetDesign()->abrv,
2124  (const char*) player_elem->GetDesign()->name,
2125  (const char*) player_elem->Name());
2126  }
2127 
2128  MissionInfo* info = new(__FILE__,__LINE__) MissionInfo;
2129 
2130  info->id = mission->Identity();
2131  info->mission = mission;
2132  info->name = name;
2133  info->type = mission->Type();
2134  info->player_info = player_info;
2135  info->description = mission->Objective();
2136  info->start = mission->Start();
2137 
2138  if (mission->GetStarSystem())
2139  info->system = mission->GetStarSystem()->Name();
2140  info->region = mission->GetRegion();
2141 
2142  mission->SetName(name);
2143 
2144  return info;
2145 }
2146 
2147 // +--------------------------------------------------------------------+
2148 
2149 void
2151 {
2153  if (stars)
2155 }