Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CampaignMissionStarship.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: CampaignMissionStarship.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  CampaignMissionStarship generates missions and mission
13  info for the player's STARSHIP GROUP as part of a
14  dynamic campaign.
15 */
16 
17 #include "MemDebug.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 "Mission.h"
28 #include "MissionTemplate.h"
29 #include "Instruction.h"
30 #include "Ship.h"
31 #include "ShipDesign.h"
32 #include "Starshatter.h"
33 #include "StarSystem.h"
34 #include "Player.h"
35 #include "Random.h"
36 
37 static int pkg_id = 1000;
38 extern int dump_missions;
39 
40 // +--------------------------------------------------------------------+
41 
43 : campaign(c), player_group(0), player_unit(0), mission(0), player(0),
44 strike_group(0), strike_target(0), prime_target(0),
45 ward(0), escort(0), ownside(0), enemy(-1), mission_type(0)
46 {
47  if (!campaign || !campaign->GetPlayerGroup()) {
48  ::Print("ERROR - CMS campaign=0x%08x player_group=0x%08x\n",
50  return;
51  }
52 
55 }
56 
58 
59 // +--------------------------------------------------------------------+
60 
61 void
63 {
64  if (!campaign || !req)
65  return;
66 
67  ::Print("\n-----------------------------------------------\n");
68  if (req->Script().length())
69  ::Print("CMS CreateMission() request: %s '%s'\n",
70  Mission::RoleName(req->Type()),
71  (const char*) req->Script());
72 
73  else
74  ::Print("CMS CreateMission() request: %s %s\n",
75  Mission::RoleName(req->Type()),
76  req->GetObjective() ? req->GetObjective()->Name().data() : "(no target)");
77 
78  request = req;
79 
80  if (!player_group)
81  return;
82 
83  if (request->GetPrimaryGroup() != player_group) {
84  player_group = request->GetPrimaryGroup();
85  player_unit = 0;
86  }
87 
89  mission_info = 0;
90 
91  for (int i = 0; i < campaign->GetCombatants().size(); i++) {
92  int iff = campaign->GetCombatants().at(i)->GetIFF();
93  if (iff > 0 && iff != ownside) {
94  enemy = iff;
95  break;
96  }
97  }
98 
99  static int id_key = 1;
100  GenerateMission(id_key++);
102 
103  MissionInfo* info = DescribeMission();
104 
105  if (info) {
106  campaign->GetMissionList().append(info);
107 
108  ::Print("CMS Created %03d '%s' %s\n\n",
109  info->id,
110  (const char*) info->name,
112 
113  if (dump_missions) {
114  Text script = mission->Serialize();
115  char fname[32];
116 
117  sprintf_s(fname, "msn%03d.def", info->id);
118  FILE* f;
119  fopen_s(&f, fname, "w");
120  if (f) {
121  fprintf(f, "%s\n", script.data());
122  fclose(f);
123  }
124  }
125  }
126 
127  else {
128  ::Print("CMS failed to create mission.\n");
129  }
130 }
131 
132 // +--------------------------------------------------------------------+
133 
134 Mission*
136 {
137  bool found = false;
138 
139  SelectType();
140 
141  if (request && request->Script().length()) {
142  MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, request->Script(), campaign->Path());
143  if (mt)
145  mission = mt;
146  found = true;
147  }
148 
149  else {
151 
152  found = mission_info != 0;
153 
154  if (found) {
155  MissionTemplate* mt = new(__FILE__,__LINE__) MissionTemplate(id, mission_info->script, campaign->Path());
156  if (mt)
158  mission = mt;
159  }
160  else {
161  mission = new(__FILE__,__LINE__) Mission(id);
162  if (mission)
164  }
165  }
166 
167  if (!mission || !player_group) {
168  Exit();
169  return 0;
170  }
171 
172  char name[64];
173  sprintf_s(name, "Starship Mission %d", id);
174 
175  mission->SetName(name);
178 
179  SelectRegion();
181 
182  if (!found) {
184  mission->SetOK(true);
185  mission->Validate();
186  }
187 
188  else {
189  CreatePlayer();
190  mission->Load();
191 
192  if (mission->IsOK()) {
193  player = mission->GetPlayer();
195  ward = mission->GetWard();
196  }
197 
198  // if there was a problem, scrap the mission
199  // and start over:
200  else {
201  delete mission;
202 
203  mission = new(__FILE__,__LINE__) Mission(id);
204 
205  if (!mission) {
206  Exit();
207  return 0;
208  }
209 
211  mission->SetName(name);
214 
215  SelectRegion();
218 
219  mission->SetOK(true);
220  mission->Validate();
221  }
222  }
223 
224  return mission;
225 }
226 
227 void
229 {
230  if (request)
232 
233  else
235 
238 }
239 
240 void
242 {
243  if (!player_group) {
244  ::Print("WARNING: CMS - no player group in SelectRegion\n");
245  return;
246  }
247 
249 
250  if (!zone)
251  zone = player_group->GetCurrentZone();
252 
253  if (zone) {
255 
256  if (zone->HasRegion(player_group->GetRegion()))
258 
259  else
260  mission->SetRegion(*zone->GetRegions().at(0));
261  }
262 
263  else {
264  ::Print("WARNING: CMS - No zone for '%s'\n", player_group->Name().data());
265 
266  StarSystem* s = campaign->GetSystemList()[0];
267 
269  mission->SetRegion(s->Regions()[0]->Name());
270  }
271 }
272 
273 // +--------------------------------------------------------------------+
274 
275 void
277 {
279  while (++z) {
280  ListIter<ZoneForce> iter = z->GetForces();
281  while (++iter) {
282  ZoneForce* force = iter.value();
283  ListIter<CombatGroup> group = force->GetGroups();
284 
285  while (++group) {
286  CombatGroup* g = group.value();
287 
288  switch (g->Type()) {
293  CreateSquadron(g);
294  break;
295 
299  CreateElements(g);
300  break;
301 
310  case CombatGroup::SUPPLY:
311  case CombatGroup::REPAIR:
312  CreateElements(g);
313  break;
314 
326  CreateElements(g);
327  break;
328  }
329  }
330  }
331  }
332 }
333 
334 // +--------------------------------------------------------------------+
335 
336 void
338 {
339  CreatePlayer();
340  CreateWards();
341  CreateTargets();
342 
343  if (ward && player) {
344  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, ward->Name());
345 
346  if (obj) {
347  switch (mission->Type()) {
349  obj->SetTargetDesc(Text("the star freighter ") + ward->Name());
350  break;
351 
353  obj->SetTargetDesc(Text("the shuttle ") + ward->Name());
354  break;
355 
357  obj->SetTargetDesc(Text("the ") + ward->Name() + Text(" strike package"));
358  break;
359 
360  default:
361  if (ward->GetCombatGroup()) {
362  obj->SetTargetDesc(Text("the ") + ward->GetCombatGroup()->GetDescription());
363  }
364  else {
365  obj->SetTargetDesc(Text("the ") + ward->Name());
366  }
367  break;
368  }
369 
370  player->AddObjective(obj);
371  }
372  }
373 }
374 
375 // +--------------------------------------------------------------------+
376 
377 void
379 {
380  // prepare elements for the player's group
381  MissionElement* elem = 0;
382 
383  if (player_group) {
385  while (++iter) {
386  MissionElement* e = iter.value();
387  if (e->GetCombatGroup() == player_group) {
389 
390  // match the player to the requested unit, if possible:
391  if ((!player_unit && !elem) || (player_unit == e->GetCombatUnit())) {
392  elem = e;
393  }
394  }
395  }
396  }
397 
398  if (elem) {
399  elem->SetPlayer(1);
400  elem->SetCommandAI(0);
401  player = elem;
402  }
403  else if (player_group) {
404  ::Print("CMS GenerateMissionElements() could not find player element '%s'\n",
405  player_group->Name().data());
406  }
407  else {
408  ::Print("CMS GenerateMissionElements() could not find player element (no player group)\n");
409  }
410 }
411 
412 // +--------------------------------------------------------------------+
413 
414 void
416 {
417  MissionElement* elem = 0;
418  List<CombatUnit>& units = g->GetUnits();
419 
420  CombatUnit* cmdr = 0;
421 
422  for (int i = 0; i < units.size(); i++) {
423  elem = CreateSingleElement(g, units[i]);
424 
425  if (elem) {
426  if (!cmdr) {
427  cmdr = units[i];
428 
429  if (player_group && player_group->GetIFF() == g->GetIFF()) {
430  // the grand admiral is all powerful!
432  if (player && player->Rank() >= 10) {
433  elem->SetCommander(player_group->Name());
434  }
435  }
436  }
437  else {
438  elem->SetCommander(cmdr->Name());
439 
440  if (g->Type() == CombatGroup::CARRIER_GROUP &&
441  elem->MissionRole() == Mission::ESCORT) {
442  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, cmdr->Name());
443  if (obj) {
444  obj->SetTargetDesc(Text("the ") + g->GetDescription());
445  elem->AddObjective(obj);
446  }
447  }
448  }
449 
450  mission->AddElement(elem);
451  }
452  }
453 }
454 
457 {
458  if (!g || g->IsReserve()) return 0;
459  if (!u || u->LiveCount() < 1) return 0;
460  if (!mission->GetStarSystem()) return 0;
461 
462  // no ground units in starship missions:
463  StarSystem* system = mission->GetStarSystem();
464  OrbitalRegion* rgn = system->FindRegion(u->GetRegion());
465 
466  if (!rgn || rgn->Type() == Orbital::TERRAIN)
467  return 0;
468 
469  // make sure this unit isn't already in the mission:
471  while (++e_iter) {
472  MissionElement* elem = e_iter.value();
473 
474  if (elem->GetCombatUnit() == u)
475  return 0;
476  }
477 
478  MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
479  if (!elem) {
480  Exit();
481  return 0;
482  }
483 
484  if (u->Name().length())
485  elem->SetName(u->Name());
486  else
487  elem->SetName(u->DesignName());
488 
489  elem->SetElementID(pkg_id++);
490 
491  elem->SetDesign(u->GetDesign());
492  elem->SetCount(u->LiveCount());
493  elem->SetIFF(u->GetIFF());
494  elem->SetIntelLevel(g->IntelLevel());
495  elem->SetRegion(u->GetRegion());
496  elem->SetHeading(u->GetHeading());
497 
498  int unit_index = g->GetUnits().index(u);
499  Point base_loc = u->Location();
500  bool exact = u->IsStatic(); // exact unit-level placement
501 
502  if (base_loc.length() < 1) {
503  base_loc = g->Location();
504  exact = false;
505  }
506 
507  if (unit_index < 0 || unit_index > 0 && !exact) {
508  Point loc = RandomDirection();
509 
510  if (!u->IsStatic()) {
511  while (fabs(loc.y) > fabs(loc.x))
512  loc = RandomDirection();
513 
514  loc *= 10e3 + 9e3 * unit_index;
515  }
516  else {
517  loc *= 2e3 + 2e3 * unit_index;
518  }
519 
520  elem->SetLocation(base_loc + loc);
521  }
522  else {
523  elem->SetLocation(base_loc);
524  }
525 
526  if (g->Type() == CombatGroup::CARRIER_GROUP) {
527  if (u->Type() == Ship::CARRIER) {
529  }
530  else {
532  }
533  }
534  else if (u->Type() == Ship::STATION || u->Type() == Ship::FARCASTER) {
536 
537  // link farcaster to other terminus:
538  if (u->Type() == Ship::FARCASTER) {
539  Text name = u->Name();
540  int dash = -1;
541 
542  for (int i = 0; i < (int) name.length(); i++)
543  if (name[i] == '-')
544  dash = i;
545 
546  Text src = name.substring(0, dash);
547  Text dst = name.substring(dash+1, name.length() - (dash+1));
548 
549  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::VECTOR, dst + "-" + src);
550  if (obj)
551  elem->AddObjective(obj);
552  }
553  }
554  else if ((u->Type() & Ship::STARSHIPS) != 0) {
556  }
557 
558  elem->SetCombatGroup(g);
559  elem->SetCombatUnit(u);
560 
561  return elem;
562 }
563 
564 CombatUnit*
566 {
567  CombatGroup* carrier = g->FindCarrier();
568 
569  if (carrier && carrier->GetUnits().size()) {
570  MissionElement* carrier_elem = mission->FindElement(carrier->Name());
571 
572  if (carrier_elem)
573  return carrier->GetUnits().at(0);
574  }
575 
576  return 0;
577 }
578 
579 void
581 {
582  if (!g || g->IsReserve()) return;
583 
584  CombatUnit* fighter = g->GetUnits().at(0);
585  CombatUnit* carrier = FindCarrier(g);
586 
587  if (!fighter || !carrier) return;
588 
589  int live_count = fighter->LiveCount();
590  int maint_count = (live_count > 4) ? live_count / 2 : 0;
591 
592  MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
593 
594  if (!elem) {
595  Exit();
596  return;
597  }
598 
599  elem->SetName(g->Name());
600  elem->SetElementID(pkg_id++);
601 
602  elem->SetDesign(fighter->GetDesign());
603  elem->SetCount(fighter->Count());
604  elem->SetDeadCount(fighter->DeadCount());
605  elem->SetMaintCount(maint_count);
606  elem->SetIFF(fighter->GetIFF());
607  elem->SetIntelLevel(g->IntelLevel());
608  elem->SetRegion(fighter->GetRegion());
609 
610  elem->SetCarrier(carrier->Name());
611  elem->SetCommander(carrier->Name());
612  elem->SetLocation(carrier->Location() + RandomPoint());
613 
614  elem->SetCombatGroup(g);
615  elem->SetCombatUnit(fighter);
616 
617  mission->AddElement(elem);
618 }
619 
620 // +--------------------------------------------------------------------+
621 
622 void
624 {
625  switch (mission->Type()) {
627  default: break;
628  }
629 }
630 
631 void
633 {
634  if (!mission || !mission->GetStarSystem() || !player_group) return;
635 
636  CombatGroup* freight = 0;
637 
638  if (request)
639  freight = request->GetObjective();
640 
641  if (!freight)
643 
644  if (!freight || freight->CalcValue() < 1) return;
645 
646  CombatUnit* unit = freight->GetNextUnit();
647  if (!unit) return;
648 
649  MissionElement* elem = CreateSingleElement(freight, unit);
650  if (!elem) return;
651 
654  elem->SetRegion(player_group->GetRegion());
655 
656  ward = elem;
657  mission->AddElement(elem);
658 
659 
660  StarSystem* system = mission->GetStarSystem();
661  OrbitalRegion* rgn1 = system->FindRegion(elem->Region());
662  Point delta = rgn1->Location() - rgn1->Primary()->Location();
663  Point navpt_loc = elem->Location();
664  Instruction* n = 0;
665 
666  delta.Normalize();
667  delta *= 200.0e3;
668 
669  navpt_loc += delta;
670 
671  n = new(__FILE__,__LINE__) Instruction(elem->Region(),
672  navpt_loc,
674  if (n) {
675  n->SetSpeed(500);
676  elem->AddNavPoint(n);
677  }
678 
679  Text rgn2 = elem->Region();
680  List<CombatZone>& zones = campaign->GetZones();
681  if (zones[zones.size()-1]->HasRegion(rgn2))
682  rgn2 = *zones[0]->GetRegions()[0];
683  else
684  rgn2 = *zones[zones.size()-1]->GetRegions()[0];
685 
686  n = new(__FILE__,__LINE__) Instruction(rgn2,
687  Point(0, 0, 0),
689  if (n) {
690  n->SetSpeed(750);
691  elem->AddNavPoint(n);
692  }
693 }
694 
695 // +--------------------------------------------------------------------+
696 
697 void
699 {
700 }
701 
702 // +--------------------------------------------------------------------+
703 
704 void
706 {
709  }
710 
711  else {
712  switch (mission->Type()) {
713  default:
714  case Mission::PATROL: CreateTargetsPatrol(); break;
715  case Mission::ASSAULT:
716  case Mission::STRIKE: CreateTargetsAssault(); break;
718  }
719  }
720 }
721 
722 // +--------------------------------------------------------------------+
723 
724 void
726 {
727  if (!player) return;
728 
729  CombatGroup* assigned = 0;
730 
731  if (request)
732  assigned = request->GetObjective();
733 
734  if (assigned) {
735  CreateElements(assigned);
736 
738  while (++e_iter) {
739  MissionElement* elem = e_iter.value();
740 
741  if (elem->GetCombatGroup() == assigned) {
742  if (!prime_target) {
743  prime_target = elem;
744 
745  MissionElement* player_lead = player_group_elements[0];
746 
747  if (!player_lead) return;
748 
749  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, prime_target->Name());
750  if (obj) {
751  obj->SetTargetDesc(Text("preplanned target '") + prime_target->Name() + "'");
752  player_lead->AddObjective(obj);
753  }
754 
755  // create flight plan:
756  RLoc rloc;
757  RLoc* ref = 0;
758  Vec3 dummy(0,0,0);
759  Instruction* instr = 0;
760  Point loc = player_lead->Location();
761  Point tgt = prime_target->Location();
762  Point mid;
763 
764  mid = loc + (prime_target->Location() - loc) * 0.35;
765 
766  rloc.SetReferenceLoc(0);
767  rloc.SetBaseLocation(mid);
768  rloc.SetDistance(50e3);
769  rloc.SetDistanceVar(5e3);
770  rloc.SetAzimuth(90*DEGREES);
771  rloc.SetAzimuthVar(45*DEGREES);
772 
773  instr = new(__FILE__,__LINE__) Instruction(prime_target->Region(), dummy, Instruction::VECTOR);
774 
775  if (!instr)
776  return;
777 
778  instr->SetSpeed(750);
779  instr->GetRLoc() = rloc;
780 
781  ref = &instr->GetRLoc();
782 
783  player_lead->AddNavPoint(instr);
784 
785  for (int i = 1; i < player_group_elements.size(); i++) {
787  RLoc rloc2;
788 
789  rloc2.SetReferenceLoc(ref);
790  rloc2.SetDistance(50e3);
791  rloc2.SetDistanceVar(5e3);
792 
793  instr = new(__FILE__,__LINE__) Instruction(prime_target->Region(), dummy, Instruction::VECTOR);
794 
795  if (!instr)
796  return;
797 
798  instr->SetSpeed(750);
799  instr->GetRLoc() = rloc2;
800 
801  pge->AddNavPoint(instr);
802  }
803 
804  double extra = 10e3;
805 
806  if (prime_target && prime_target->GetDesign()) {
807  switch (prime_target->GetDesign()->type) {
808  default: extra = 20e3; break;
809  case Ship::FRIGATE: extra = 25e3; break;
810  case Ship::DESTROYER: extra = 30e3; break;
811  case Ship::CRUISER: extra = 50e3; break;
812  case Ship::BATTLESHIP: extra = 70e3; break;
813  case Ship::DREADNAUGHT: extra = 80e3; break;
814  case Ship::CARRIER: extra = 90e3; break;
815  }
816  }
817 
818  rloc.SetReferenceLoc(0);
819  rloc.SetBaseLocation(tgt);
820  rloc.SetDistance(100e3 + extra);
821  rloc.SetDistanceVar(15e3);
822  rloc.SetAzimuth(90*DEGREES);
823  rloc.SetAzimuthVar(45*DEGREES);
824 
825  instr = new(__FILE__,__LINE__) Instruction(prime_target->Region(), dummy, Instruction::ASSAULT);
826 
827  if (!instr)
828  return;
829 
830  instr->SetSpeed(500);
831  instr->GetRLoc() = rloc;
832  instr->SetTarget(prime_target->Name());
833 
834  ref = &instr->GetRLoc();
835 
836  player_lead->AddNavPoint(instr);
837 
838  for (int i = 1; i < player_group_elements.size(); i++) {
840  RLoc rloc2;
841 
842  rloc2.SetReferenceLoc(ref);
843  rloc2.SetDistance(50e3);
844  rloc2.SetDistanceVar(5e3);
845 
846  instr = new(__FILE__,__LINE__) Instruction(prime_target->Region(), dummy, Instruction::ASSAULT);
847 
848  if (!instr)
849  return;
850 
851  instr->SetSpeed(500);
852  instr->GetRLoc() = rloc2;
853  instr->SetTarget(prime_target->Name());
854 
855  pge->AddNavPoint(instr);
856  }
857  }
858  }
859  }
860  }
861 }
862 
863 
864 // +--------------------------------------------------------------------+
865 
866 void
868 {
869  if (!player_group || !player) return;
870 
871  Text region = player_group->GetRegion();
872  Point base_loc = player->Location();
873  Point patrol_loc = base_loc +
874  RandomDirection() * Random( 75e3, 150e3);
875  Point loc2 = patrol_loc +
876  RandomDirection() * Random( 50e3, 100e3);
877 
878 
879  int ntargets = 2 + (RandomChance() ? 1 : 0);
880  int ntries = 8;
881 
882  while (ntargets > 0 && ntries > 0) {
883  Point target_loc = RandomChance() ? patrol_loc : loc2;
884  int t = CreateRandomTarget(region, target_loc);
885  ntargets -= t;
886  if (t < 1) ntries--;
887  }
888 }
889 
890 // +--------------------------------------------------------------------+
891 
892 void
894 {
895  if (!player_group || !player) return;
896 
897  Text region = player_group->GetRegion();
898  Point base_loc = player->Location();
899  Point patrol_loc = base_loc +
900  RandomDirection() * Random(170e3, 250e3);
901 
902  Instruction* n = new(__FILE__,__LINE__) Instruction(region,
903  patrol_loc,
905  player->AddNavPoint(n);
906 
907  for (int i = 1; i < player_group_elements.size(); i++) {
909 
910  n = new(__FILE__,__LINE__) Instruction(region,
911  patrol_loc + RandomDirection() * Random(20e3, 40e3),
913  if (n)
914  elem->AddNavPoint(n);
915  }
916 
917  Point loc2 = patrol_loc + RandomDirection() * Random(150e3, 200e3);
918 
919  n = new(__FILE__,__LINE__) Instruction(region,
920  loc2,
922  if (n)
923  player->AddNavPoint(n);
924 
925  for (int i = 1; i < player_group_elements.size(); i++) {
927 
928  n = new(__FILE__,__LINE__) Instruction(region,
929  loc2 + RandomDirection() * Random(20e3, 40e3),
931 
932  if (n)
933  elem->AddNavPoint(n);
934  }
935 
936  int ntargets = 2 + (RandomChance() ? 1 : 0);
937  int ntries = 8;
938 
939  while (ntargets > 0 && ntries > 0) {
940  Point target_loc = RandomChance() ? patrol_loc : loc2;
941  int t = CreateRandomTarget(region, target_loc);
942  ntargets -= t;
943  if (t < 1) ntries--;
944  }
945 
946  Instruction* obj = new(__FILE__,__LINE__) Instruction(*n);
947  if (obj) {
948  obj->SetTargetDesc("inbound enemy units");
949  player->AddObjective(obj);
950  }
951 }
952 
953 // +--------------------------------------------------------------------+
954 
955 void
957 {
958  if (!ward) {
960  return;
961  }
962 
965 
966  if (!s || !s2) return;
967 
969  if (elem) {
971 
972  elem->SetLocation(ward->Location() + RandomPoint() * 5);
973 
974  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ASSAULT, ward->Name());
975  if (obj)
976  elem->AddObjective(obj);
977  mission->AddElement(elem);
978 
980  if (e2) {
982  e2->SetLocation(elem->Location() + RandomPoint() * 0.25);
983 
984  Instruction* obj2 = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
985  if (obj2)
986  e2->AddObjective(obj2);
987  mission->AddElement(e2);
988  }
989  }
990 
991  Instruction* obj3 = new(__FILE__,__LINE__) Instruction(mission->GetRegion(),
992  Point(0,0,0),
994  if (player && obj3) {
995  obj3->SetTargetDesc("enemy patrols");
996  player->AddObjective(obj3);
997  }
998 }
999 
1000 // +--------------------------------------------------------------------+
1001 
1002 int
1004 {
1005  int ntargets = 0;
1006  int ttype = RandomIndex();
1007 
1009  switch (ttype) {
1010  case 0:
1011  case 1:
1012  case 2:
1013  case 3: ttype = 0; break;
1014  case 4:
1015  case 5: ttype = 1; break;
1016  case 6:
1017  case 7: ttype = 2; break;
1018  case 8:
1019  case 9: ttype = 3; break;
1020  case 10:
1021  case 11: ttype = 4; break;
1022  case 12:
1023  case 13:
1024  case 14:
1025  case 15: ttype = 5; break;
1026  }
1027  }
1028  else {
1029  switch (ttype) {
1030  case 0:
1031  case 1:
1032  case 2:
1033  case 3:
1034  case 4:
1035  case 5: ttype = 0; break;
1036  case 6:
1037  case 7:
1038  case 8: ttype = 1; break;
1039  case 9:
1040  case 10: ttype = 4; break;
1041  case 11:
1042  case 12:
1043  case 13:
1044  case 14:
1045  case 15: ttype = 5; break;
1046  }
1047  }
1048 
1049  switch (ttype) {
1050  case 0: {
1051  CombatGroup* s = 0;
1052 
1054 
1055  if (s) {
1056  for (int i = 0; i < 2; i++) {
1057  CombatUnit* u = s->GetRandomUnit();
1058  MissionElement* elem = CreateSingleElement(s, u);
1059  if (elem) {
1060  elem->SetIntelLevel(Intel::KNOWN);
1061  elem->SetRegion(rgn);
1062  elem->SetLocation(base_loc + RandomPoint() * 1.5);
1064  mission->AddElement(elem);
1065  ntargets++;
1066  }
1067  }
1068  }
1069  }
1070  break;
1071 
1072  case 1: {
1074 
1075  if (s) {
1077  if (elem) {
1078  elem->SetIntelLevel(Intel::KNOWN);
1079  elem->SetRegion(rgn);
1080  elem->SetLocation(base_loc + RandomPoint() * 2);
1081  mission->AddElement(elem);
1082  ntargets++;
1083 
1085 
1086  if (s2) {
1088  if (e2) {
1090  e2->SetRegion(rgn);
1091  e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
1092 
1093  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1094  if (obj)
1095  e2->AddObjective(obj);
1096 
1097  mission->AddElement(e2);
1098  }
1099  }
1100  }
1101  }
1102  }
1103  break;
1104 
1105  case 2: {
1107 
1108  if (s) {
1110  if (elem) {
1112  elem->SetRegion(rgn);
1113  elem->SetLocation(base_loc);
1114  mission->AddElement(elem);
1115  ntargets++;
1116  }
1117  }
1118  }
1119  break;
1120 
1121  case 3: {
1123 
1124  if (s) {
1126  if (elem) {
1127  elem->SetIntelLevel(Intel::KNOWN);
1128  elem->Loadouts().destroy();
1129  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Ship Strike"));
1130  elem->SetRegion(rgn);
1131  elem->SetLocation(base_loc + RandomPoint());
1132  mission->AddElement(elem);
1133 
1134  if (player) {
1135  Instruction* n = new(__FILE__,__LINE__) Instruction(player->Region(),
1136  player->Location() + RandomPoint(),
1138  n->SetTarget(player->Name());
1139  elem->AddNavPoint(n);
1140  }
1141 
1142  ntargets++;
1143  }
1144  }
1145  }
1146  break;
1147 
1148  case 4: {
1150 
1151  if (s) {
1153  if (elem) {
1154  elem->SetIntelLevel(Intel::KNOWN);
1155  elem->Loadouts().destroy();
1156  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "Hvy Ship Strike"));
1157  elem->SetRegion(rgn);
1158  elem->SetLocation(base_loc + RandomPoint() * 1.3);
1159  mission->AddElement(elem);
1160 
1161  if (player) {
1162  Instruction* n = new(__FILE__,__LINE__) Instruction(player->Region(),
1163  player->Location() + RandomPoint(),
1165  n->SetTarget(player->Name());
1166  elem->AddNavPoint(n);
1167  }
1168 
1169  ntargets++;
1170  }
1171  }
1172  }
1173  break;
1174 
1175  default: {
1176  CombatGroup* s = 0;
1177 
1179 
1180  if (s) {
1181  CombatUnit* u = s->GetRandomUnit();
1182  MissionElement* elem = CreateSingleElement(s, u);
1183  if (elem) {
1184  elem->SetIntelLevel(Intel::KNOWN);
1185  elem->SetRegion(rgn);
1186  elem->SetLocation(base_loc + RandomPoint() * 2);
1188  mission->AddElement(elem);
1189  ntargets++;
1190 
1192 
1193  if (s2) {
1195  if (e2) {
1197  e2->SetRegion(rgn);
1198  e2->SetLocation(elem->Location() + RandomPoint() * 0.5);
1199 
1200  Instruction* obj = new(__FILE__,__LINE__) Instruction(Instruction::ESCORT, elem->Name());
1201  if (obj)
1202  e2->AddObjective(obj);
1203  mission->AddElement(e2);
1204  ntargets++;
1205  }
1206  }
1207  }
1208  }
1209  }
1210  break;
1211  }
1212 
1213  return ntargets;
1214 }
1215 
1216 // +--------------------------------------------------------------------+
1217 
1220 {
1221  if (!squadron || squadron->IsReserve())
1222  return 0;
1223 
1224  CombatUnit* fighter = squadron->GetUnits().at(0);
1225  CombatUnit* carrier = FindCarrier(squadron);
1226 
1227  if (!fighter)
1228  return 0;
1229 
1230  int avail = fighter->LiveCount();
1231  int actual = count;
1232 
1233  if (avail < actual)
1234  actual = avail;
1235 
1236  if (avail < 1) {
1237  ::Print("CMS - Insufficient fighters in squadron '%s' - %d required, %d available\n",
1238  squadron->Name().data(), count, avail);
1239  return 0;
1240  }
1241 
1242  MissionElement* elem = new(__FILE__,__LINE__) MissionElement;
1243 
1244  if (!elem) {
1245  Exit();
1246  return 0;
1247  }
1248 
1249  elem->SetName(Callsign::GetCallsign(fighter->GetIFF()));
1250  elem->SetElementID(pkg_id++);
1251 
1252  if (carrier) {
1253  elem->SetCommander(carrier->Name());
1254  elem->SetHeading(carrier->GetHeading());
1255  }
1256  else {
1257  elem->SetHeading(fighter->GetHeading());
1258  }
1259 
1260  elem->SetDesign(fighter->GetDesign());
1261  elem->SetCount(actual);
1262  elem->SetIFF(fighter->GetIFF());
1263  elem->SetIntelLevel(squadron->IntelLevel());
1264  elem->SetRegion(fighter->GetRegion());
1265  elem->SetSquadron(fighter->Name());
1266  elem->SetMissionRole(role);
1267  elem->Loadouts().append(new(__FILE__,__LINE__) MissionLoad(-1, "ACM Medium Range"));
1268 
1269  if (carrier)
1270  elem->SetLocation(carrier->Location() + RandomPoint() * 0.3);
1271  else
1272  elem->SetLocation(fighter->Location() + RandomPoint());
1273 
1274  elem->SetCombatGroup(squadron);
1275  elem->SetCombatUnit(fighter);
1276 
1277  return elem;
1278 }
1279 
1280 // +--------------------------------------------------------------------+
1281 
1282 CombatGroup*
1284 {
1285  if (!player_group) return 0;
1286 
1287  CombatGroup* result = 0;
1289  if (!zone) zone = player_group->GetCurrentZone();
1290 
1291  if (!zone) {
1292  ::Print("CMS Warning: no zone for %s\n", player_group->Name().data());
1293  return result;
1294  }
1295 
1296  ZoneForce* force = zone->FindForce(iff);
1297 
1298  if (force) {
1299  List<CombatGroup> groups;
1300  ListIter<CombatGroup> group = force->GetGroups();
1301  while (++group) {
1302  CombatGroup* g = group.value();
1303 
1304  if (g->Type() == type && g->CountUnits() > 0) {
1305  result = g;
1306  groups.append(g);
1307  }
1308  }
1309 
1310  if (groups.size() > 1) {
1311  int index = (int) Random(0, groups.size());
1312  if (index >= groups.size()) index = groups.size() - 1;
1313  result = groups[index];
1314  }
1315  }
1316 
1317  return result;
1318 }
1319 
1320 // +--------------------------------------------------------------------+
1321 
1322 void
1324 {
1325  if (!mission || !player) return;
1326 
1328  if (ward) mission->SetWard(ward);
1329 
1330  Text objectives;
1331 
1332  if (player->Objectives().size() > 0) {
1333  for (int i = 0; i < player->Objectives().size(); i++) {
1334  Instruction* obj = player->Objectives().at(i);
1335  objectives += "* ";
1336  objectives += obj->GetDescription();
1337  objectives += ".\n";
1338  }
1339  }
1340  else {
1341  objectives += "* Perform standard fleet operations in the ";
1342  objectives += mission->GetRegion();
1343  objectives += " sector.\n";
1344  }
1345 
1346  mission->SetObjective(objectives);
1347 }
1348 
1349 // +--------------------------------------------------------------------+
1350 
1351 MissionInfo*
1353 {
1354  if (!mission || !player) return 0;
1355 
1356  char name[256];
1357  char player_info[256];
1358 
1360  sprintf_s(name, "MSN-%03d %s", mission->Identity(), mission_info->name.data());
1361  else if (ward)
1362  sprintf_s(name, "MSN-%03d %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(), ward->Name().data());
1363  else if (prime_target)
1364  sprintf_s(name, "MSN-%03d %s %s %s", mission->Identity(), Game::GetText(mission->TypeName()).data(),
1366  prime_target->Name().data());
1367  else
1368  sprintf_s(name, "MSN-%03d %s", mission->Identity(), Game::GetText(mission->TypeName()).data());
1369 
1370  if (player) {
1371  strcpy_s(player_info, player->GetCombatGroup()->GetDescription());
1372  }
1373 
1374  MissionInfo* info = new(__FILE__,__LINE__) MissionInfo;
1375 
1376  if (info) {
1377  info->id = mission->Identity();
1378  info->mission = mission;
1379  info->name = name;
1380  info->type = mission->Type();
1381  info->player_info = player_info;
1382  info->description = mission->Objective();
1383  info->start = mission->Start();
1384 
1385  if (mission->GetStarSystem())
1386  info->system = mission->GetStarSystem()->Name();
1387  info->region = mission->GetRegion();
1388  }
1389 
1390  mission->SetName(name);
1391 
1392  return info;
1393 }
1394 
1395 // +--------------------------------------------------------------------+
1396 
1397 void
1399 {
1401  if (stars)
1403 }