Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Hangar.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: Hangar.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Everything needed to store and maintain space craft
13 
14  See Also: FlightDeck
15 */
16 
17 #include "MemDebug.h"
18 #include "Hangar.h"
19 #include "FlightDeck.h"
20 #include "Ship.h"
21 #include "ShipDesign.h"
22 #include "Sim.h"
23 #include "Instruction.h"
24 #include "Element.h"
25 #include "Mission.h"
26 #include "RadioMessage.h"
27 #include "Campaign.h"
28 #include "Combatant.h"
29 #include "CombatGroup.h"
30 
31 #include "Game.h"
32 #include "Random.h"
33 
34 // +======================================================================+
35 
37 {
38  friend class Hangar;
39 
40 public:
41  static const char* TYPENAME() { return "HangarSlot"; }
42 
43  HangarSlot();
44  ~HangarSlot();
45  int operator == (const HangarSlot& that) const { return this == &that; }
46 
47 private:
48  Text squadron;
49  CombatGroup* group;
50  Ship* ship;
51  int iff;
52  const ShipDesign* design;
53  FlightDeck* deck;
54  int slot;
55  int state;
56  double time;
57  Element* package;
58  bool alert_hold;
59  int loadout[16];
60 };
61 
62 // +--------------------------------------------------------------------+
63 
65 : ship(0), group(0), design(0), deck(0), slot(0),
66 state(0), time(0), package(0), alert_hold(false)
67 {
68  for (int i = 0; i < 16; i++)
69  loadout[i] = -1;
70 }
71 
73 {
74 }
75 
76 // +======================================================================+
77 
80 {
81  ZeroMemory(nslots, sizeof(nslots));
82  ZeroMemory(squadrons, sizeof(squadrons));
83 }
84 
85 // +----------------------------------------------------------------------+
86 
89 {
90  ZeroMemory(nslots, sizeof(nslots));
91  ZeroMemory(squadrons, sizeof(squadrons));
92 }
93 
94 // +--------------------------------------------------------------------+
95 
97 {
98  for (int i = 0; i < MAX_SQUADRONS; i++)
99  delete [] squadrons[i];
100 }
101 
102 // +--------------------------------------------------------------------+
103 
104 void
105 Hangar::ExecFrame(double seconds)
106 {
107  for (int n = 0; n < nsquadrons; n++) {
108  if (squadrons[n] && nslots[n] > 0) {
109  for (int i = 0; i < nslots[n]; i++) {
110  HangarSlot* slot = &squadrons[n][i];
111 
112  switch (slot->state) {
113  case UNAVAIL:
114  case STORAGE:
115  case APPROACH:
116  break;
117 
118  case ACTIVE:
119  if (slot->ship && slot->ship->GetFlightPhase() == Ship::APPROACH)
120  slot->state = APPROACH;
121  break;
122 
123  case MAINT:
124  if (slot->time > 0) {
125  slot->time -= seconds;
126  }
127  else {
128  slot->time = 0;
129  slot->state = STORAGE;
130  }
131  break;
132 
133 
134  case PREP:
135  if (slot->time > 0) {
136  slot->time -= seconds;
137  }
138  else {
139  slot->time = 0;
140  FinishPrep(slot);
141  }
142  break;
143 
144  case ALERT:
145  if (slot->time > 0) {
146  slot->time -= seconds;
147  }
148  else if (slot->deck) {
149  slot->time = 0;
150 
151  // if package has specific objective, launch as soon as possible:
152  if (!slot->alert_hold)
153  slot->deck->Launch(slot->slot);
154 
155  switch (slot->deck->State(slot->slot)) {
156  case FlightDeck::READY: slot->state = ALERT; break;
157  case FlightDeck::QUEUED: slot->state = QUEUED; break;
158  case FlightDeck::LOCKED: slot->state = LOCKED; break;
159  case FlightDeck::LAUNCH: slot->state = LAUNCH; break;
160  default: slot->state = STORAGE; break;
161  }
162  }
163  break;
164 
165  case QUEUED:
166  case LOCKED:
167  if (slot->deck) {
168  switch (slot->deck->State(slot->slot)) {
169  case FlightDeck::READY: slot->state = ALERT; break;
170  case FlightDeck::QUEUED: slot->state = QUEUED; break;
171  case FlightDeck::LOCKED: slot->state = LOCKED; break;
172  case FlightDeck::LAUNCH: slot->state = LAUNCH; break;
173  default: slot->state = STORAGE; break;
174  }
175 
176  slot->time = slot->deck->TimeRemaining(slot->slot);
177  }
178  break;
179 
180  case LAUNCH:
181  if (slot->deck) {
182  slot->time = slot->deck->TimeRemaining(slot->slot);
183 
184  if (slot->ship && slot->ship->GetFlightPhase() > Ship::LAUNCH) {
185  slot->state = ACTIVE;
186  slot->time = 0;
187  }
188  }
189  break;
190 
191  case RECOVERY:
192  break;
193  }
194  }
195  }
196  }
197 }
198 
199 // +--------------------------------------------------------------------+
200 
201 bool
203 {
204  if (slot->deck->SpaceLeft(slot->design->type)) {
205  Sim* sim = Sim::GetSim();
206 
207  Text ship_name = slot->squadron;
208 
209  slot->ship = sim->CreateShip(ship_name, "",
210  (ShipDesign*) slot->design,
211  ship->GetRegion()->Name(),
212  Point(0, 0, 0),
213  slot->iff,
215  slot->loadout);
216 
217  Observe(slot->ship);
218 
219  if (slot->package) {
220  slot->package->SetCommander(ship->GetElement());
221  slot->package->AddShip(slot->ship);
222 
223  if (slot->group) {
224  slot->package->SetCombatGroup(slot->group);
225  slot->package->SetCombatUnit(slot->group->GetNextUnit());
226  }
227 
228  char name[64];
229  sprintf_s(name, "%s %d",
230  (const char*) slot->package->Name(),
231  slot->ship->GetElementIndex());
232  slot->ship->SetName(name);
233  }
234 
235  slot->slot = -1; // take first available slot
236  if (slot->deck->Spot(slot->ship, slot->slot)) {
237  slot->state = ALERT;
238  return true;
239  }
240 
241  Print("WARNING: Could not spot alert ship - carrier: '%s' ship '%s'\n",
242  ship->Name(), slot->ship->Name());
243  }
244 
245  return false;
246 }
247 
248 // +--------------------------------------------------------------------+
249 
250 bool
252 {
253  bool found = false;
254 
255  for (int n = 0; !found && n < nsquadrons; n++) {
256  if (squadrons[n] && nslots[n] > 0) {
257  for (int i = 0; !found && i < nslots[n]; i++) {
258  HangarSlot* slot = &squadrons[n][i];
259 
260  if (slot->ship == obj) {
261  // was ship destroyed in combat,
262  // or did it just dock here?
263  if (slot->state != MAINT) {
264  slot->state = UNAVAIL;
265  slot->ship = 0;
266  slot->deck = 0;
267  slot->time = 0;
268  slot->package = 0;
269  }
270 
271  found = true;
272  }
273  }
274  }
275  }
276 
277  return SimObserver::Update(obj);
278 }
279 
280 const char*
282 {
283  static char name[64];
284  if (ship)
285  sprintf_s(name, "Hangar(%s)", ship->Name());
286  else
287  sprintf_s(name, "Hangar");
288  return name;
289 }
290 
291 // +--------------------------------------------------------------------+
292 
293 bool
295 const ShipDesign* design, int count, int iff,
296 int* def_load, int maint_count, int dead_count)
297 {
298  if (nsquadrons < MAX_SQUADRONS && count > 0) {
299  HangarSlot* s = new(__FILE__,__LINE__) HangarSlot[count];
300 
301  for (int i = 0; i < count; i++) {
302  s[i].squadron = squadron;
303  s[i].group = group;
304  s[i].design = design;
305  s[i].iff = iff;
306 
307  if (def_load)
308  CopyMemory(s[i].loadout, def_load, sizeof(s[i].loadout));
309  }
310 
311  squadrons[nsquadrons] = s;
312  nslots[nsquadrons] = count;
313  names[nsquadrons] = squadron;
314 
315  int i = count-1;
316  while (dead_count-- > 0)
317  s[i--].state = UNAVAIL;
318 
319  while (maint_count-- > 0) {
320  s[i].state = MAINT;
321  s[i--].time = 600 + rand() / 15;
322  }
323 
324  nsquadrons++;
325  return true;
326  }
327 
328  return false;
329 }
330 
331 bool
332 Hangar::GotoActiveFlight(int squadron, int slot_index, Element* elem, int* loadout)
333 {
334  if (elem && squadron < nsquadrons && slot_index < nslots[squadron]) {
335  HangarSlot* slot = &(squadrons[squadron][slot_index]);
336 
337  if (slot->state == STORAGE) {
338  slot->deck = 0;
339  slot->state = ACTIVE;
340  slot->time = 0;
341  slot->package = elem;
342  slot->alert_hold = false;
343 
344  if (loadout)
345  CopyMemory(slot->loadout, loadout, sizeof(slot->loadout));
346 
347  Sim* sim = Sim::GetSim();
348 
349  Text ship_name = slot->squadron;
350 
351  slot->ship = sim->CreateShip(ship_name, "",
352  (ShipDesign*) slot->design,
353  ship->GetRegion()->Name(),
354  ship->Location() + RandomPoint(),
355  slot->iff,
357  slot->loadout);
358 
359  if (slot->ship) {
360  Observe(slot->ship);
361 
362  elem->SetCommander(ship->GetElement());
363  elem->AddShip(slot->ship);
364 
365  if (slot->group) {
366  elem->SetCombatGroup(slot->group);
367  elem->SetCombatUnit(slot->group->GetNextUnit());
368  }
369 
370  char name[64];
371  sprintf_s(name, "%s %d",
372  (const char*) elem->Name(),
373  slot->ship->GetElementIndex());
374 
375  slot->ship->SetName(name);
376  }
377 
378  return true;
379  }
380  }
381 
382  return false;
383 }
384 
385 bool
386 Hangar::GotoAlert(int squadron, int slot, FlightDeck* d, Element* elem, int* loadout, bool pkg, bool expedite)
387 {
388  if (squadron < nsquadrons && slot < nslots[squadron]) {
389  HangarSlot* s = &(squadrons[squadron][slot]);
390 
391  if (s->state == STORAGE) {
392  s->deck = d;
393  s->state = PREP;
394  s->time = expedite ? 3 : s->design->prep_time;
395  s->package = elem;
396  s->alert_hold = !pkg;
397 
398  if (loadout)
399  CopyMemory(s->loadout, loadout, sizeof(s->loadout));
400 
401  if (expedite)
402  FinishPrep(s);
403 
404  return true;
405  }
406  }
407 
408  return false;
409 }
410 
411 bool
412 Hangar::Launch(int squadron, int slot)
413 {
414  if (squadron < nsquadrons && slot < nslots[squadron]) {
415  HangarSlot* s = &(squadrons[squadron][slot]);
416 
417  if (s->state == ALERT && s->deck)
418  return s->deck->Launch(s->slot);
419  }
420 
421  return false;
422 }
423 
424 bool
425 Hangar::StandDown(int squadron, int slot)
426 {
427  if (squadron < nsquadrons && slot < nslots[squadron]) {
428  HangarSlot* s = &(squadrons[squadron][slot]);
429 
430  Element* package = 0;
431  bool clear_slot = false;
432 
433  if (s->state == ALERT && s->deck) {
434  if (s->deck->Clear(s->slot)) {
435  if (s->ship) {
436  Sim* sim = Sim::GetSim();
437 
438  if (s->package) {
439  package = s->package;
440  package->DelShip(s->ship);
441  }
442 
443  sim->DestroyShip(s->ship);
444  }
445 
446  clear_slot = true;
447  }
448  }
449 
450  else if (s->state == PREP) {
451  clear_slot = true;
452  package = s->package;
453  }
454 
455  if (clear_slot) {
456  s->state = STORAGE;
457  s->deck = 0;
458  s->slot = 0;
459  s->ship = 0;
460  s->package = 0;
461 
462  if (package) {
463  int npkg = 0;
464  for (int i = 0; i < nslots[squadron]; i++) {
465  if (squadrons[squadron][i].package == package)
466  npkg++;
467  }
468 
469  if (npkg == 0) {
470  Sim::GetSim()->DestroyElement(package);
471  }
472  }
473 
474  return true;
475  }
476  }
477 
478  return false;
479 }
480 
481 // +--------------------------------------------------------------------+
482 
483 bool
485 {
486  int squadron = -1;
487  int slot = -1;
488 
489  if (FindSlot(incoming, squadron, slot))
490  return true;
491 
492  return false;
493 }
494 
495 // +--------------------------------------------------------------------+
496 
497 bool
498 Hangar::Stow(Ship* incoming)
499 {
500  int squadron = -1;
501  int slot = -1;
502 
503  if (FindSlot(incoming, squadron, slot)) {
504  HangarSlot* s = &(squadrons[squadron][slot]);
505  s->state = MAINT;
506  s->design = incoming->Design();
507  s->time = 2400;
508  s->package = 0; // XXX MEMORY LEAK?
509 
510  // extra maintenance time?
511  if (incoming->Integrity() < incoming->Design()->integrity) {
512  double damage = 100 * ((double) incoming->Design()->integrity - (double) incoming->Integrity()) / (double) incoming->Design()->integrity;
513 
514  if (damage < 10) s->time *= 1.2;
515  else if (damage < 25) s->time *= 2;
516  else if (damage < 50) s->time *= 4;
517  else s->time *= 10;
518  }
519 
520  // quicker turnaround during network play:
521  Sim* sim = Sim::GetSim();
522  if (sim && sim->IsNetGame())
523  s->time /= 40;
524 
525  return true;
526  }
527 
528  return false;
529 }
530 
531 bool
532 Hangar::FindSlot(Ship* test, int& squadron, int& slot, int desired_state)
533 {
534  if (test) {
535  // if test is already inbound to this carrier,
536  // keep the inbound squadron and slot selections:
537  if (desired_state == UNAVAIL && test->GetInbound()) {
538  InboundSlot* inbound = test->GetInbound();
539  FlightDeck* deck = inbound->GetDeck();
540 
541  if (deck && deck->GetCarrier() == ship && deck->IsPowerOn()) {
542  squadron = inbound->Squadron();
543  slot = inbound->Index();
544  return true;
545  }
546  }
547 
548  int avail_squadron = -1;
549  int avail_slot = -1;
550 
551  for (int i = 0; i < nsquadrons; i++) {
552  if (squadron < 0 || squadron == i) {
553  for (int j = 0; j < nslots[i]; j++) {
554  HangarSlot* s = &(squadrons[i][j]);
555  if (s->ship == test) {
556  squadron = i;
557  slot = j;
558  return true;
559  }
560 
561  else if (avail_slot < 0 && s->ship == 0) {
562  if ((desired_state > STORAGE && s->state == STORAGE) ||
563  (desired_state < STORAGE && s->state == UNAVAIL)) {
564  avail_squadron = i;
565  avail_slot = j;
566  }
567  }
568  }
569  }
570  }
571 
572  if (avail_squadron >= 0 && avail_slot >= 0) {
573  squadron = avail_squadron;
574  slot = avail_slot;
575 
576  if (desired_state > STORAGE) {
577  HangarSlot* s = &(squadrons[squadron][slot]);
578 
579  s->ship = test;
580  s->design = test->Design();
581  s->state = desired_state;
582  s->deck = 0;
583  s->slot = 0;
584  s->package = test->GetElement();
585  s->time = 0;
586 
587  Observe(s->ship);
588  }
589 
590  return true;
591  }
592  }
593 
594  return false;
595 }
596 
597 bool
598 Hangar::FindSquadronAndSlot(Ship* test, int& squadron, int& slot)
599 {
600  if (test) {
601  for (int i = 0; i < nsquadrons; i++) {
602  if (squadron < 0 || squadron == i) {
603  for (int j = 0; j < nslots[i]; j++) {
604  HangarSlot* s = &(squadrons[i][j]);
605  if (s->ship == test) {
606  squadron = i;
607  slot = j;
608  return true;
609  }
610  }
611  }
612  }
613  }
614 
615  return false;
616 }
617 
618 
619 bool
620 Hangar::FindAvailSlot(const ShipDesign* design, int& squadron, int& slot)
621 {
622  if (design) {
623  for (int i = 0; i < nsquadrons; i++) {
624  if (nslots[i] > 0 && squadrons[i]->design == design) {
625  for (int j = 0; j < nslots[i]; j++) {
626  HangarSlot* s = &(squadrons[i][j]);
627 
628  if (s->state == STORAGE) {
629  squadron = i;
630  slot = j;
631  return true;
632  }
633  }
634  }
635  }
636  }
637 
638  return false;
639 }
640 
641 bool
642 Hangar::Ready(int squadron, int slot, FlightDeck* d)
643 {
644  if (squadron < 0 || squadron >= nsquadrons || slot < 0 || slot >= nslots[squadron] || !d)
645  return false;
646 
647  HangarSlot* s = &(squadrons[squadron][slot]);
648 
649  s->time = 3; // 5;
650  s->deck = d;
651  s->slot = -1; // take first available slot
652 
653  if (d->Spot(s->ship, s->slot)) {
654  s->state = ALERT;
655  s->alert_hold = false;
656  return true;
657  }
658 
659  return false;
660 }
661 
662 // +--------------------------------------------------------------------+
663 
664 Text
666 {
667  if (n >= 0 && n < nsquadrons)
668  return names[n];
669 
670  return Game::GetText("Unknown");
671 }
672 
673 int
675 {
676  if (n >= 0 && n < nsquadrons)
677  return nslots[n];
678 
679  return 0;
680 }
681 
682 int
684 {
685  if (n >= 0 && n < nsquadrons)
686  return squadrons[n]->iff;
687 
688  return 0;
689 }
690 
691 const ShipDesign*
693 {
694  if (n >= 0 && n < nsquadrons && nslots[n])
695  return squadrons[n]->design;
696 
697  return 0;
698 }
699 
700 const HangarSlot*
701 Hangar::GetSlot(int i, int j) const
702 {
703  if (i >= 0 && i < nsquadrons)
704  if (j >= 0 && j < nslots[i])
705  return squadrons[i] + j;
706 
707  return 0;
708 }
709 
710 // +--------------------------------------------------------------------+
711 
712 Ship*
714 {
715  if (s) return s->ship;
716  return 0;
717 }
718 
719 const ShipDesign*
721 {
722  if (s) return s->design;
723  return 0;
724 }
725 
726 FlightDeck*
728 {
729  if (s) return s->deck;
730  return 0;
731 }
732 
733 int
735 {
736  if (s) return s->slot;
737  return 0;
738 }
739 
740 int
742 {
743  if (s) return s->state;
744  return 0;
745 }
746 
747 double
749 {
750  if (s) return s->time;
751  return 0;
752 }
753 
754 Element*
756 {
757  if (s) return s->package;
758  return 0;
759 }
760 
761 const int*
763 {
764  if (s) return s->loadout;
765  return 0;
766 }
767 
768 Text
770 {
771  switch (s->state) {
772  default:
773  case UNAVAIL: return Game::GetText("hangar.UNAVAIL");
774  case MAINT: return Game::GetText("hangar.MAINT");
775  case STORAGE: return Game::GetText("hangar.STORAGE");
776  case PREP: return Game::GetText("hangar.PREP");
777  case ALERT: return Game::GetText("hangar.ALERT");
778  case QUEUED: {
779  Text state = Game::GetText("hangar.QUEUED");
780  char seq[8];
781  sprintf_s(seq, " %d", s->deck->Sequence(s->slot));
782  return state + seq;
783  }
784  case LOCKED: return Game::GetText("hangar.LOCKED");
785  case LAUNCH: return Game::GetText("hangar.LAUNCH");
786  case ACTIVE: return Game::GetText("hangar.ACTIVE");
787  case APPROACH: return Game::GetText("hangar.APPROACH");
788  case RECOVERY: return Game::GetText("hangar.RECOVERY");
789  }
790 }
791 
792 // +--------------------------------------------------------------------+
793 
794 int
796 {
797  int result = 0;
798 
799  for (int n = 0; n < nsquadrons; n++) {
800  if (squadrons[n] && nslots[n] > 0) {
801  for (int i = 0; i < nslots[n]; i++) {
802  HangarSlot* slot = &squadrons[n][i];
803 
804  if (slot->deck == d)
805  result++;
806  }
807  }
808  }
809 
810  return result;
811 }
812 
813 // +--------------------------------------------------------------------+
814 
815 int
817 {
818  int result = 0;
819 
820  if (n >= 0 && n < nsquadrons && squadrons[n] && nslots[n] > 0) {
821  for (int i = 0; i < nslots[n]; i++) {
822  HangarSlot* slot = &squadrons[n][i];
823 
824  if (slot->state == STORAGE)
825  result++;
826  }
827  }
828 
829  return result;
830 }
831 
832 int
834 {
835  int result = 0;
836 
837  if (n >= 0 && n < nsquadrons && squadrons[n] && nslots[n] > 0) {
838  for (int i = 0; i < nslots[n]; i++) {
839  HangarSlot* slot = &squadrons[n][i];
840 
841  if (slot->state == MAINT)
842  result++;
843  }
844  }
845 
846  return result;
847 }
848 
849 int
851 {
852  int result = 0;
853 
854  if (n >= 0 && n < nsquadrons && squadrons[n] && nslots[n] > 0) {
855  for (int i = 0; i < nslots[n]; i++) {
856  HangarSlot* slot = &squadrons[n][i];
857 
858  if (slot->state == UNAVAIL)
859  result++;
860  }
861  }
862 
863  return result;
864 }
865 
866 int
868 {
869  int result = 0;
870 
871  for (int n = 0; n < nsquadrons; n++) {
872  if (squadrons[n] && nslots[n] > 0) {
873  for (int i = 0; i < nslots[n]; i++) {
874  HangarSlot* slot = &squadrons[n][i];
875 
876  if (slot->state == UNAVAIL)
877  result++;
878  }
879  }
880  }
881 
882  return result;
883 }
884 
885 int
887 {
888  active_list.clear();
889 
890  for (int n = 0; n < nsquadrons; n++) {
891  if (squadrons[n] && nslots[n] > 0) {
892  for (int i = 0; i < nslots[n]; i++) {
893  HangarSlot* slot = &squadrons[n][i];
894 
895  if (slot->package != 0 && !active_list.contains(slot->package))
896  active_list.append(slot->package);
897  }
898  }
899  }
900 
901  return active_list.size();
902 }
903 
904 // +--------------------------------------------------------------------+
905 
906 DWORD
908 {
909  return last_patrol_launch;
910 }
911 
912 void
914 {
915  last_patrol_launch = t;
916 }
917 
918 // +--------------------------------------------------------------------+
919 
920 void
922 {
923  for (int n = 0; n < nsquadrons; n++) {
924  if (squadrons[n] && nslots[n] > 0) {
925  for (int i = 0; i < nslots[n]; i++) {
926  HangarSlot* slot = &squadrons[n][i];
927 
928  if (slot->ship)
929  slot->ship->SetIFF(iff);
930  }
931  }
932  }
933 }