Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CampaignPlanEvent.cpp
Go to the documentation of this file.
1 /* Project Starshatter 4.5
2  Destroyer Studios LLC
3  Copyright © 1997-2004. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: CampaignPlanEvent.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  CampaignPlanEvent generates simulated combat
13  events based on a statistical analysis of the
14  combatants within the context of a dynamic
15  campaign.
16 */
17 
18 #include "MemDebug.h"
19 #include "CampaignPlanEvent.h"
20 #include "Campaign.h"
21 #include "Combatant.h"
22 #include "CombatAction.h"
23 #include "CombatAssignment.h"
24 #include "CombatEvent.h"
25 #include "CombatGroup.h"
26 #include "CombatUnit.h"
27 #include "CombatZone.h"
28 #include "Mission.h"
29 #include "Random.h"
30 #include "Ship.h"
31 #include "ShipDesign.h"
32 #include "FormatUtil.h"
33 
34 // +--------------------------------------------------------------------+
35 
37 : CampaignPlan(c), event_time(0)
38 {
39  if (campaign) {
40  event_time = (int) campaign->GetTime();
41  }
42 }
43 
45 { }
46 
47 // +--------------------------------------------------------------------+
48 
49 void
51 {
52  if (campaign && campaign->IsActive()) {
53  if (!campaign->GetPlayerGroup())
54  return;
55 
56  // once every twenty minutes is plenty:
57  if (Campaign::Stardate() - exec_time < 1200)
58  return;
59 
60  if (!ExecScriptedEvents())
62 
64  event_time = (int) campaign->GetTime();
65  }
66 }
67 
68 void
70 {
71  exec_time = Campaign::Stardate() + seconds;
72 }
73 
74 // +--------------------------------------------------------------------+
75 
76 bool
78 {
79  bool scripted_event = false;
80 
81  if (campaign) {
83  while (++iter) {
84  CombatAction* action = iter.value();
85 
86  if (action->IsAvailable()) {
87 
88  switch (action->Type()) {
90  {
91  CombatEvent* event = new(__FILE__,__LINE__)
93  action->Subtype(),
94  (int) campaign->GetTime(),
95  action->GetIFF(),
96  action->Source(),
97  action->Region());
98 
99  if (!event)
100  return false;
101 
102  event->SetTitle(action->GetText());
103 
104  if (*action->Filename() != 0)
105  event->SetFilename(action->Filename());
106 
107  if (*action->ImageFile() != 0)
108  event->SetImageFile(action->ImageFile());
109 
110  if (*action->SceneFile() != 0)
111  event->SetSceneFile(action->SceneFile());
112 
113  event->Load();
114 
115  ProsecuteKills(action);
116  campaign->GetEvents().append(event);
117 
118  action->FireAction();
119  scripted_event = true;
120 
121  if (action->Subtype() == CombatEvent::CAMPAIGN_END) {
122  ::Print(">>>>> CAMPAIGN %d END (Action %03d) <<<<<\n", campaign->GetCampaignId(), action->Identity());
124  }
125 
126  else if (action->Subtype() == CombatEvent::CAMPAIGN_FAIL) {
127  ::Print(">>>>> CAMPAIGN %d FAIL (Action %03d) <<<<<\n", campaign->GetCampaignId(), action->Identity());
129  }
130  }
131  break;
132 
134  {
135  CombatGroup* g = campaign->FindGroup(action->GetIFF(),
136  action->AssetType(),
137  action->AssetId());
138 
139  if (g) {
140  g->SetStrategicDirection(action->GetText());
141  action->FireAction();
142  }
143  else {
144  action->FailAction();
145  }
146 
147  scripted_event = true;
148  }
149  break;
150 
152  {
153  campaign->SetSituation(action->GetText());
154  action->FireAction();
155  scripted_event = true;
156  }
157  break;
158 
160  {
161  campaign->SetOrders(action->GetText());
162  action->FireAction();
163  scripted_event = true;
164  }
165  break;
166 
168  {
169  CombatGroup* g = campaign->FindGroup(action->GetIFF(),
170  action->AssetType(),
171  action->AssetId());
172 
173  if (g) {
174  g->SetIntelLevel(action->Subtype());
175  action->FireAction();
176  }
177  else {
178  ::Print("WARNING: Action %d (intel level) Could not find group (IFF:%d, type:%d, id:%d)\n",
179  action->Identity(),
180  action->GetIFF(),
181  action->AssetType(),
182  action->AssetId());
183 
184  action->FailAction();
185  }
186 
187  scripted_event = true;
188  }
189  break;
190 
192  {
193  CombatGroup* g = campaign->FindGroup(action->GetIFF(),
194  action->AssetType(),
195  action->AssetId());
196 
197  if (g) {
198  bool found = false;
199 
200  if (*action->Region()) {
201  CombatZone* zone = campaign->GetZone(action->Region());
202 
203  if (zone) {
204  g->SetAssignedZone(zone);
205  g->SetZoneLock(true);
206  found = true;
207 
208  // don't announce the move unless it's for the player's team:
209  if (action->GetIFF() == campaign->GetPlayerIFF() && _stricmp(action->GetText(), "do-not-display")) {
210  CombatEvent* event = new(__FILE__,__LINE__)
213  (int) campaign->GetTime(),
214  action->GetIFF(),
216  action->Region());
217 
218  if (!event)
219  return false;
220 
221  Text title = Text(g->Name()) + " Orders: Proceed to " + action->Region() + " Sector";
222  event->SetTitle(title);
223 
224  double eta = campaign->GetTime() + 3600;
225  eta -= fmod(eta, 1800);
226 
227  char text[64];
228  FormatDayTime(text, eta);
229 
230  Text info = "ORDERS:\n\nEffective immediately, ";
231  info += g->GetDescription();
232  info += " and all associated units shall proceed to ";
233  info += action->Region();
234  info += " sector and commence spaceborne operations in that area. ETA rendevous point ";
235  info += text;
236  info += ".\n\nFleet Admiral A. Evars FORCOM\nCommanding";
237 
238  event->SetInformation(info);
239 
240  if (*action->ImageFile() != 0)
241  event->SetImageFile(action->ImageFile());
242 
243  if (*action->SceneFile() != 0)
244  event->SetSceneFile(action->SceneFile());
245 
246  event->Load();
247  campaign->GetEvents().append(event);
248  }
249  }
250  }
251 
252  if (!found) {
253  ::Print("WARNING: Action %d Could not find assigned zone '%s' for '%s'\n",
254  action->Identity(),
255  action->Region() ? action->Region() : "NULL",
256  g->Name().data());
257 
258  g->SetAssignedZone(0);
259  }
260 
261  action->FireAction();
262  }
263  else {
264  ::Print("WARNING: Action %d (zone assignment) Could not find group (IFF:%d, type:%d, id:%d)\n",
265  action->Identity(),
266  action->GetIFF(),
267  action->AssetType(),
268  action->AssetId());
269 
270  action->FailAction();
271  }
272 
273  scripted_event = true;
274  }
275  break;
276 
278  {
279  CombatGroup* g = campaign->FindGroup(action->GetIFF(),
280  action->AssetType(),
281  action->AssetId());
282 
283  if (g) {
284  bool found = false;
285 
286  if (*action->System()) {
287  Text system = action->System();
288 
289  if (campaign->GetSystem(system)) {
290  g->SetAssignedSystem(system);
291  found = true;
292 
293  // don't announce the move unless it's for the player's team:
294  if (action->GetIFF() == campaign->GetPlayerIFF() && _stricmp(action->GetText(), "do-not-display")) {
295  CombatEvent* event = new(__FILE__,__LINE__)
298  (int) campaign->GetTime(),
299  action->GetIFF(),
301  action->Region());
302 
303  if (!event)
304  return false;
305 
306  Text title = Text(g->Name()) + " Orders: Proceed to " + action->System() + " System";
307  event->SetTitle(title);
308 
309  double eta = campaign->GetTime() + 3600;
310  eta -= fmod(eta, 1800);
311 
312  char text[64];
313  FormatDayTime(text, eta);
314 
315  Text info = "ORDERS:\n\nEffective immediately, ";
316  info += g->GetDescription();
317  info += " and all associated units shall proceed to the ";
318  info += action->System();
319  info += " star system and commence spaceborne operations in that area. ETA rendevous point ";
320  info += text;
321  info += ".\n\nFleet Admiral A. Evars FORCOM\nCommanding";
322 
323  event->SetInformation(info);
324 
325  if (*action->ImageFile() != 0)
326  event->SetImageFile(action->ImageFile());
327 
328  if (*action->SceneFile() != 0)
329  event->SetSceneFile(action->SceneFile());
330 
331  event->Load();
332  campaign->GetEvents().append(event);
333  }
334  }
335  }
336 
337  if (!found) {
338  ::Print("WARNING: Action %d Could not find assigned system '%s' for '%s'\n",
339  action->Identity(),
340  action->System() ? action->System() : "NULL",
341  g->Name().data());
342 
343  g->SetAssignedSystem("");
344  }
345 
346  action->FireAction();
347  }
348  else {
349  ::Print("WARNING: Action %d (system assignment) Could not find group (IFF:%d, type:%d, id:%d)\n",
350  action->Identity(),
351  action->GetIFF(),
352  action->AssetType(),
353  action->AssetId());
354 
355  action->FailAction();
356  }
357 
358  scripted_event = true;
359  }
360  break;
361 
363  action->FireAction();
364  scripted_event = true;
365  break;
366 
367  default:
368  break;
369  }
370  }
371  }
372  }
373 
374  return scripted_event;
375 }
376 
377 // +--------------------------------------------------------------------+
378 
379 void
381 {
382  if (action->AssetKills().size() > 0) {
383  CombatGroup* g = campaign->FindGroup(action->GetIFF(),
384  action->AssetType(),
385  action->AssetId());
386 
387  if (g) {
388  ListIter<Text> iter = action->AssetKills();
389  while (++iter) {
390  Text* name = iter.value();
391  CombatUnit* asset = g->FindUnit(*name);
392 
393  if (asset) {
394  int value_killed = asset->Kill(1);
395 
397  while (++iter) {
398  Combatant* c = iter.value();
399  if (c->GetIFF() > 0 && c->GetIFF() != asset->GetIFF()) {
400  // damage to neutral assets must be scored to bad guys:
401  if (asset->GetIFF() > 0 || c->GetIFF() > 1) {
402  c->AddScore(value_killed);
403  break;
404  }
405  }
406  }
407  }
408  }
409  }
410  }
411 
412  if (action->TargetKills().size() > 0) {
413  CombatGroup* g = campaign->FindGroup(action->TargetIFF(),
414  action->TargetType(),
415  action->TargetId());
416 
417  if (g) {
418  ListIter<Text> iter = action->TargetKills();
419  while (++iter) {
420  Text* name = iter.value();
421  CombatUnit* target = g->FindUnit(*name);
422 
423  if (target) {
424  int value_killed = target->Kill(1);
425 
427  while (++iter) {
428  Combatant* c = iter.value();
429  if (c->GetIFF() > 0 && c->GetIFF() != target->GetIFF()) {
430  // damage to neutral assets must be scored to bad guys:
431  if (target->GetIFF() > 0 || c->GetIFF() > 1) {
432  c->AddScore(value_killed);
433  break;
434  }
435  }
436  }
437  }
438  }
439  }
440  }
441 }
442 
443 // +--------------------------------------------------------------------+
444 
445 bool
447 {
448  bool result = false;
449 
450  if (campaign) {
452  while (++iter && !result) {
453  Combatant* c = iter.value();
455 
456  // prefer assignments not in player's zone:
457  if (a) {
458  CombatGroup* objective = a->GetObjective();
459  CombatGroup* player = campaign->GetPlayerGroup();
460 
461  if (objective && player &&
462  objective->GetCurrentZone() == player->GetCurrentZone())
463  a = ChooseAssignment(c->GetForce());
464  }
465 
466  if (a) {
467  result = CreateEvent(a);
468  }
469  }
470  }
471 
472  return result;
473 }
474 
475 // +--------------------------------------------------------------------+
476 
477 bool
479 {
480  CombatEvent* event = 0;
481 
482  if (campaign && a && a->GetResource() && RandomChance(1,2)) {
484 
485  CombatGroup* group = a->GetResource();
486 
487  if (group == campaign->GetPlayerGroup()) {
488 
489  if (group->Type() == CombatGroup::DESTROYER_SQUADRON ||
490  group->Type() == CombatGroup::BATTLE_GROUP ||
491  group->Type() == CombatGroup::CARRIER_GROUP) {
492 
493  return false;
494  }
495  }
496 
497  CombatGroup* target = a->GetObjective();
498 
499  if (target && target == campaign->GetPlayerGroup()) {
500 
501  if (target->Type() == CombatGroup::DESTROYER_SQUADRON ||
502  target->Type() == CombatGroup::BATTLE_GROUP ||
503  target->Type() == CombatGroup::CARRIER_GROUP) {
504 
505  return false;
506  }
507  }
508 
509  switch (a->Type()) {
510  case Mission::DEFEND:
511  event = CreateEventDefend(a);
512  break;
513 
514  case Mission::ASSAULT:
515  if (group->IsStarshipGroup())
516  event = CreateEventStarship(a);
517  else
518  event = CreateEventFighterAssault(a);
519  break;
520 
521  case Mission::STRIKE:
522  if (group->IsStarshipGroup())
523  event = CreateEventStarship(a);
524  else
525  event = CreateEventFighterStrike(a);
526  break;
527 
528  case Mission::SWEEP:
529  event = CreateEventFighterSweep(a);
530  break;
531  }
532 
533  if (event) {
534  campaign->GetEvents().append(event);
535  return true;
536  }
537  }
538 
539  return false;
540 }
541 
542 // +--------------------------------------------------------------------+
543 
544 static void FindAssignments(CombatGroup* g, List<CombatAssignment>& alist)
545 {
546  if (!g) return;
547 
548  alist.append(g->GetAssignments());
549 
551  while (++iter)
552  FindAssignments(iter.value(), alist);
553 }
554 
557 {
559  FindAssignments(g, alist);
560 
561  int tries = 5;
562 
563  if (alist.size() > 0) {
564  while (tries-- > 0) {
565  int index = (int) Random(0, alist.size());
566 
567  if (index >= alist.size())
568  index = 0;
569 
570  CombatAssignment* a = alist[index];
571 
572  if (!a) continue;
573 
574  CombatGroup* resource = a->GetResource();
575  CombatGroup* objective = a->GetObjective();
576 
577  if (!resource || !objective)
578  continue;
579 
580  if (resource->IsReserve() || objective->IsReserve())
581  continue;
582 
583  if (resource->CalcValue() < 50 || objective->CalcValue() < 50)
584  continue;
585 
586  if (resource == campaign->GetPlayerGroup() || objective == campaign->GetPlayerGroup())
587  continue;
588 
589  return a;
590  }
591  }
592 
593  return 0;
594 }
595 
596 // +--------------------------------------------------------------------+
597 
600 {
601  bool friendly = IsFriendlyAssignment(a);
602 
603  if (!friendly)
604  return 0;
605 
606  CombatEvent* event = 0;
607  CombatGroup* group = a->GetResource();
608  CombatGroup* obj = a->GetObjective();
609  CombatUnit* unit = group->GetRandomUnit();
610  CombatUnit* tgt = obj->GetRandomUnit();
611 
612  if (!unit || !tgt)
613  return 0;
614 
615  bool success = Success(a);
616  Text rgn = group->GetRegion();
617  Text title = Text(group->Name()) + " in Defensive Engagement";
618  Text info;
619 
620  event = new(__FILE__,__LINE__) CombatEvent(campaign,
622  event_time,
623  group->GetIFF(),
625  rgn);
626 
627  if (!event)
628  return 0;
629 
630  int tgt_count = 0;
631  int unit_count = 0;
632 
633  if (!success) {
634  if (tgt) {
635  if (tgt->Kill(1) > 0)
636  tgt_count++;
637  Combatant* c = group->GetCombatant();
638  if (c) c->AddScore(tgt->GetSingleValue());
639  }
640 
641  if (unit && RandomChance(1,5)) {
642  if (unit->Kill(1) > 0)
643  unit_count++;
644  Combatant* c = obj->GetCombatant();
645  if (c) c->AddScore(unit->GetSingleValue());
646  }
647  }
648 
649  CombatGroup* us = group;
650  CombatGroup* them = obj;
651  int us_count = unit_count;
652  int them_count = tgt_count;
653 
654  if (obj->IsStrikeTarget()) {
655  info = Text("EVENT: ") + rgn + " Sector\n\n";
656  }
657 
658  else {
659  info = Text("MISSION: Escort ") + obj->Name() + ", " + rgn + " Sector\n\n";
660  }
661 
662  info += GetTeamName(group);
663  info += Text(" ") + group->GetDescription();
664 
665  if (success)
666  info += " successfully defended ";
667  else
668  info += " was unable to defend ";
669 
670  info += GetTeamName(obj);
671  info += Text(" ") + obj->GetDescription() + ".\n\n";
672 
673  // need to find an enemy group to do the attacking...
674 
675  event->SetTitle(title);
676  event->SetInformation(info);
677  return event;
678 }
679 
680 // +--------------------------------------------------------------------+
681 
684 {
685  CombatEvent* event = 0;
686  CombatGroup* group = a->GetResource();
687  CombatGroup* obj = a->GetObjective();
688  CombatUnit* unit = group->GetRandomUnit();
689  CombatUnit* tgt = obj->GetRandomUnit();
690 
691  if (!unit || !tgt)
692  return 0;
693 
694  bool success = Success(a);
695  Text rgn = group->GetRegion();
696  Text title = Text(group->Name());
697  Text info;
698 
699  event = new(__FILE__,__LINE__) CombatEvent(campaign,
701  event_time,
702  group->GetIFF(),
704  rgn);
705 
706  if (!event)
707  return 0;
708 
709  title += Text(" Assault ") + obj->Name();
710 
711  int tgt_count = 0;
712  int unit_count = 0;
713 
714  if (success) {
715  if (tgt) {
716  int killed = tgt->Kill(1 + tgt->Count()/2);
717  if (killed > 0)
718  tgt_count += killed / tgt->GetSingleValue();
719  Combatant* c = group->GetCombatant();
720  if (c) c->AddScore(tgt->GetSingleValue());
721  }
722 
723  if (unit && RandomChance(1,5)) {
724  if (unit->Kill(1) > 0)
725  unit_count++;
726  Combatant* c = obj->GetCombatant();
727  if (c) c->AddScore(unit->GetSingleValue());
728  }
729  }
730  else {
731  for (int i = 0; i < 2; i++) {
732  if (unit && RandomChance(1,4)) {
733  if (unit->Kill(1) > 0)
734  unit_count++;
735  Combatant* c = obj->GetCombatant();
736  if (c) c->AddScore(unit->GetSingleValue());
737  }
738  }
739  }
740 
741  CombatGroup* us = group;
742  CombatGroup* them = obj;
743  int us_count = unit_count;
744  int them_count = tgt_count;
745 
746  bool friendly = IsFriendlyAssignment(a);
747 
748  if (friendly) {
749  info = Text("MISSION: Strike, ") + rgn + " Sector\n\n";
750  }
751 
752  else {
753  info = Text("EVENT: ") + rgn + " Sector\n\n";
754 
755  us = obj;
756  them = group;
757  us_count = tgt_count;
758  them_count = unit_count;
759  }
760 
761  info += GetTeamName(group);
762  info += Text(" ") + group->GetDescription();
763 
764  if (success)
765  info += " successfully assault ";
766  else if (!friendly)
767  info += " assault averted against ";
768  else
769  info += " attempted assault on ";
770 
771  info += GetTeamName(obj);
772  info += Text(" ") + obj->GetDescription() + ".\n\n";
773 
774  char text[256];
775 
776  if (them_count) {
777  if (friendly) {
778  if (them_count > 1)
779  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, tgt->Name().data());
780  else
781  sprintf_s(text, "ENEMY KILLED:\t %s destroyed\n", tgt->Name().data());
782  } else {
783  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, them->Name().data());
784  }
785 
786  info += text;
787  } else {
788  info += "ENEMY KILLED:\t 0\n";
789  }
790 
791  if (us_count) {
792  if (!friendly)
793  sprintf_s(text, "ALLIED LOSSES:\t %s destroyed\n", tgt->Name().data());
794  else
795  sprintf_s(text, "ALLIED LOSSES:\t %d %s destroyed", us_count, us->Name().data());
796 
797  info += text;
798  }
799  else {
800  info += "ALLIED LOSSES:\t 0";
801  }
802 
803 
804  event->SetTitle(title);
805  event->SetInformation(info);
806  return event;
807 }
808 
809 // +--------------------------------------------------------------------+
810 
813 {
814  CombatEvent* event = 0;
815  CombatGroup* group = a->GetResource();
816  CombatGroup* obj = a->GetObjective();
817  CombatUnit* unit = group->GetRandomUnit();
818  CombatUnit* tgt = obj->GetRandomUnit();
819 
820  if (!unit || !tgt)
821  return 0;
822 
823  bool success = Success(a);
824  Text rgn = group->GetRegion();
825  Text title = Text(group->Name());
826  Text info;
827 
828  event = new(__FILE__,__LINE__) CombatEvent(campaign,
830  event_time,
831  group->GetIFF(),
833  rgn);
834 
835  if (!event)
836  return 0;
837 
838  if (unit)
839  title += Text(" ") + unit->GetDesign()->abrv + "s";
840 
841  if (success) {
842  title += " Successfully Strike " + obj->Name();
843  }
844  else {
845  title += " Attempt Strike on " + obj->Name();
846  }
847 
848  int tgt_count = 0;
849  int unit_count = 0;
850 
851  if (success) {
852  if (tgt) {
853  int killed = tgt->Kill(1 + tgt->Count()/2);
854  if (killed > 0)
855  tgt_count += killed / tgt->GetSingleValue();
856  Combatant* c = group->GetCombatant();
857  if (c) c->AddScore(tgt->GetSingleValue());
858  }
859 
860  if (unit && RandomChance(1,5)) {
861  if (unit->Kill(1) > 0)
862  unit_count++;
863  Combatant* c = obj->GetCombatant();
864  if (c) c->AddScore(unit->GetSingleValue());
865  }
866  }
867  else {
868  for (int i = 0; i < 2; i++) {
869  if (unit && RandomChance(1,4)) {
870  if (unit->Kill(1) > 0)
871  unit_count++;
872  Combatant* c = obj->GetCombatant();
873  if (c) c->AddScore(unit->GetSingleValue());
874  }
875  }
876  }
877 
878  CombatGroup* us = group;
879  CombatGroup* them = obj;
880  int us_count = unit_count;
881  int them_count = tgt_count;
882 
883  bool friendly = IsFriendlyAssignment(a);
884 
885  if (friendly) {
886  info = Text("MISSION: Strike, ") + rgn + " Sector\n\n";
887  }
888 
889  else {
890  info = Text("EVENT: ") + rgn + " Sector\n\n";
891 
892  us = obj;
893  them = group;
894  us_count = tgt_count;
895  them_count = unit_count;
896  }
897 
898  info += GetTeamName(group);
899  info += Text(" ") + group->GetDescription();
900 
901  if (success)
902  info += " successfully strike ";
903  else if (!friendly)
904  info += " strike against ";
905  else
906  info += " attempted strike on ";
907 
908  info += GetTeamName(obj);
909  info += Text(" ") + obj->GetDescription();
910 
911  if (!success && !friendly)
912  info += " averted.\n\n";
913  else
914  info += ".\n\n";
915 
916  char text[256];
917 
918  if (them_count) {
919  if (friendly) {
920  if (them_count > 1)
921  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, tgt->Name().data());
922  else
923  sprintf_s(text, "ENEMY KILLED:\t %s destroyed\n", tgt->Name().data());
924  } else {
925  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, them->Name().data());
926  }
927 
928  info += text;
929  } else {
930  info += "ENEMY KILLED:\t 0\n";
931  }
932 
933  if (us_count) {
934  if (!friendly)
935  sprintf_s(text, "ALLIED LOSSES:\t %s destroyed\n", tgt->Name().data());
936  else
937  sprintf_s(text, "ALLIED LOSSES:\t %d %s destroyed", us_count, us->Name().data());
938 
939  info += text;
940  } else {
941  info += "ALLIED LOSSES:\t 0";
942  }
943 
944  event->SetTitle(title);
945  event->SetInformation(info);
946  return event;
947 }
948 
949 // +--------------------------------------------------------------------+
950 
953 {
954  CombatEvent* event = 0;
955  CombatGroup* group = a->GetResource();
956  CombatGroup* obj = a->GetObjective();
957  CombatUnit* unit = group->GetRandomUnit();
958  CombatUnit* tgt = obj->GetRandomUnit();
959 
960  if (!unit || !tgt)
961  return 0;
962 
963  bool success = Success(a);
964  Text rgn = group->GetRegion();
965  Text title = Text(group->Name());
966  Text info;
967 
968  event = new(__FILE__,__LINE__) CombatEvent(campaign,
970  event_time,
971  group->GetIFF(),
973  rgn);
974 
975  if (!event)
976  return 0;
977 
978  if (unit)
979  title += Text(" ") + unit->GetDesign()->abrv + "s";
980  else
981  title += " Fighters";
982 
983  if (RandomChance(1, 4)) title += " Clash with ";
984  else if (RandomChance(1, 4)) title += " Engage ";
985  else if (RandomChance(1, 4)) title += " Intercept ";
986  else title += " Encounter ";
987 
988  title += obj->Name();
989 
990  int tgt_count = 0;
991  int unit_count = 0;
992 
993  if (success) {
994  for (int i = 0; i < 2; i++) {
995  if (tgt && RandomChance(3,4)) {
996  if (tgt->Kill(1) > 0)
997  tgt_count++;
998  Combatant* c = group->GetCombatant();
999  if (c) c->AddScore(tgt->GetSingleValue());
1000  }
1001  }
1002 
1003  if (tgt_count > 1) {
1004  if (tgt && RandomChance(1,4)) {
1005  if (tgt->Kill(1) > 0)
1006  tgt_count++;
1007  Combatant* c = group->GetCombatant();
1008  if (c) c->AddScore(tgt->GetSingleValue());
1009  }
1010  }
1011 
1012  else {
1013  if (unit && RandomChance(1,5)) {
1014  if (unit->Kill(1) > 0)
1015  unit_count++;
1016  Combatant* c = obj->GetCombatant();
1017  if (c) c->AddScore(unit->GetSingleValue());
1018  }
1019  }
1020  }
1021  else {
1022  for (int i = 0; i < 2; i++) {
1023  if (unit && RandomChance(3,4)) {
1024  if (unit->Kill(1) > 0)
1025  unit_count++;
1026  Combatant* c = obj->GetCombatant();
1027  if (c) c->AddScore(unit->GetSingleValue());
1028  }
1029  }
1030 
1031  if (tgt && RandomChance(1,4)) {
1032  if (tgt->Kill(1) > 0)
1033  tgt_count++;
1034  Combatant* c = group->GetCombatant();
1035  if (c) c->AddScore(tgt->GetSingleValue());
1036  }
1037  }
1038 
1039  CombatGroup* us = group;
1040  CombatGroup* them = obj;
1041  int us_count = unit_count;
1042  int them_count = tgt_count;
1043 
1044  bool friendly = IsFriendlyAssignment(a);
1045 
1046  if (!friendly) {
1047  us = obj;
1048  them = group;
1049  us_count = tgt_count;
1050  them_count = unit_count;
1051  }
1052 
1053  if (friendly) {
1054  if (RandomChance())
1055  info = Text("MISSION: OCA Sweep, ") + rgn + " Sector\n\n";
1056  else
1057  info = Text("MISSION: FORCAP, ") + rgn + " Sector\n\n";
1058 
1059  info += GetTeamName(group);
1060  info += Text(" ") + group->GetDescription();
1061  info += Text(" engaged ") + GetTeamName(obj);
1062  info += Text(" ") + obj->GetDescription() + ".\n\n";
1063  }
1064  else {
1065  info = Text("MISSION: Patrol, ") + rgn + " Sector\n\n";
1066 
1067  info += GetTeamName(obj);
1068  info += Text(" ") + obj->GetDescription();
1069  info += Text(" engaged ") + GetTeamName(group);
1070  info += Text(" ") + group->GetDescription() + ".\n\n";
1071  }
1072 
1073  char text[256];
1074 
1075  if (them_count) {
1076  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, them->Name().data());
1077 
1078  info += text;
1079  } else {
1080  info += "ENEMY KILLED:\t 0\n";
1081  }
1082 
1083  if (us_count) {
1084  sprintf_s(text, "ALLIED LOSSES:\t %d %s destroyed", us_count, us->Name().data());
1085  info += text;
1086  } else {
1087  info += "ALLIED LOSSES:\t 0";
1088  }
1089 
1090  event->SetTitle(title);
1091  event->SetInformation(info);
1092  return event;
1093 }
1094 
1095 // +--------------------------------------------------------------------+
1096 
1097 CombatEvent*
1099 {
1100  CombatEvent* event = 0;
1101  CombatGroup* group = a->GetResource();
1102  CombatGroup* obj = a->GetObjective();
1103  CombatUnit* unit = group->GetRandomUnit();
1104  CombatUnit* tgt = obj->GetRandomUnit();
1105 
1106  if (!unit || !tgt)
1107  return 0;
1108 
1109  bool success = Success(a);
1110  Text rgn = group->GetRegion();
1111  Text title = Text(group->Name());
1112  Text info;
1113 
1114  event = new(__FILE__,__LINE__) CombatEvent(campaign,
1116  event_time,
1117  group->GetIFF(),
1119  group->GetRegion());
1120 
1121  if (!event)
1122  return 0;
1123 
1124  title += Text(" Assaults ") + a->GetObjective()->Name();
1125 
1126  int tgt_count = 0;
1127  int unit_count = 0;
1128 
1129  if (success) {
1130  if (tgt) {
1131  if (tgt->Kill(1) > 0)
1132  tgt_count++;
1133  Combatant* c = group->GetCombatant();
1134  if (c) c->AddScore(tgt->GetSingleValue());
1135  }
1136 
1137  if (unit && RandomChance(1,5)) {
1138  if (unit->Kill(1) > 0)
1139  unit_count++;
1140  Combatant* c = obj->GetCombatant();
1141  if (c) c->AddScore(unit->GetSingleValue());
1142  }
1143  }
1144  else {
1145  for (int i = 0; i < 2; i++) {
1146  if (unit && RandomChance(1,4)) {
1147  if (unit->Kill(1) > 0)
1148  unit_count++;
1149  Combatant* c = obj->GetCombatant();
1150  if (c) c->AddScore(unit->GetSingleValue());
1151  }
1152  }
1153  }
1154 
1155  CombatGroup* us = group;
1156  CombatGroup* them = obj;
1157  int us_count = unit_count;
1158  int them_count = tgt_count;
1159 
1160  bool friendly = IsFriendlyAssignment(a);
1161 
1162  if (friendly) {
1163  info = Text("MISSION: Fleet Action, ") + rgn + " Sector\n\n";
1164  }
1165 
1166  else {
1167  info = Text("EVENT: ") + rgn + " Sector\n\n";
1168 
1169  us = obj;
1170  them = group;
1171  us_count = tgt_count;
1172  them_count = unit_count;
1173  }
1174 
1175  info += GetTeamName(group);
1176  info += Text(" ") + group->GetDescription();
1177 
1178  if (success)
1179  info += " successfully assaulted ";
1180  else if (!friendly)
1181  info += " assault against ";
1182  else
1183  info += " attempted assault on ";
1184 
1185  info += GetTeamName(obj);
1186  info += Text(" ") + obj->GetDescription();
1187 
1188  if (!success && !friendly)
1189  info += " failed.\n\n";
1190  else
1191  info += ".\n\n";
1192 
1193  char text[256];
1194 
1195  if (them_count) {
1196  if (friendly) {
1197  if (tgt->Count() > 1) {
1198  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, tgt->Name().data());
1199  } else {
1200  sprintf_s(text, "ENEMY KILLED:\t %s destroyed\n", tgt->Name().data());
1201  }
1202  } else {
1203  if (unit->Count() > 1) {
1204  sprintf_s(text, "ENEMY KILLED:\t %d %s destroyed\n", them_count, unit->Name().data());
1205  } else {
1206  sprintf_s(text, "ENEMY KILLED:\t %s destroyed\n", unit->Name().data());
1207  }
1208  }
1209 
1210  info += text;
1211  } else {
1212  info += "ENEMY KILLED:\t 0\n";
1213  }
1214 
1215  if (us_count) {
1216  if (!friendly)
1217  sprintf_s(text, "ALLIED LOSSES:\t %s destroyed\n", tgt->Name().data());
1218  else
1219  sprintf_s(text, "ALLIED LOSSES:\t %s destroyed", unit->Name().data());
1220 
1221  info += text;
1222  } else {
1223  info += "ALLIED LOSSES:\t 0";
1224  }
1225 
1226  event->SetTitle(title);
1227  event->SetInformation(info);
1228  return event;
1229 }
1230 
1231 // +--------------------------------------------------------------------+
1232 
1233 bool
1235 {
1236  if (!campaign || !a || !a->GetResource())
1237  return false;
1238 
1239  int a_team = a->GetResource()->GetIFF();
1240  CombatGroup* player = campaign->GetPlayerGroup();
1241 
1242  if (player && (player->GetIFF() == a_team))
1243  return true;
1244 
1245  return false;
1246 }
1247 
1248 bool
1250 {
1251  if (!campaign || !a || !a->GetResource())
1252  return false;
1253 
1254  int odds = 6 - campaign->GetCampaignId();
1255 
1256  if (odds < 1)
1257  odds = 1;
1258 
1259  bool success = RandomChance(odds, 5);
1260 
1261  if (!IsFriendlyAssignment(a))
1262  success = !success;
1263 
1264  return success;
1265 }
1266 
1267 // +--------------------------------------------------------------------+
1268 
1269 Text
1271 {
1272  while (g->GetParent())
1273  g = g->GetParent();
1274 
1275  return g->Name();
1276 }