Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CmdForceDlg.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: CmdForceDlg.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Operational Command Dialog (Order of Battle Tab)
13 */
14 
15 #include "MemDebug.h"
16 #include "CmdForceDlg.h"
17 #include "CmdMsgDlg.h"
18 #include "CmpnScreen.h"
19 #include "Starshatter.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 "Ship.h"
27 #include "ShipDesign.h"
28 #include "Player.h"
29 #include "Weapon.h"
30 
31 #include "Game.h"
32 #include "DataLoader.h"
33 #include "Button.h"
34 #include "ComboBox.h"
35 #include "ListBox.h"
36 #include "Slider.h"
37 #include "Video.h"
38 #include "Keyboard.h"
39 #include "Mouse.h"
40 #include "ParseUtil.h"
41 #include "FormatUtil.h"
42 
43 // +--------------------------------------------------------------------+
44 // DECLARE MAPPING FUNCTIONS:
45 
49 DEF_MAP_CLIENT(CmdForceDlg, OnForces);
50 DEF_MAP_CLIENT(CmdForceDlg, OnCombat);
51 DEF_MAP_CLIENT(CmdForceDlg, OnTransfer);
52 
53 // +--------------------------------------------------------------------+
54 
56 : FormWindow(s, 0, 0, s->Width(), s->Height()), manager(mgr),
57 CmdDlg(mgr),
58 cmb_forces(0), lst_combat(0), lst_desc(0),
59 stars(0), campaign(0), current_group(0), current_unit(0),
60 btn_transfer(0)
61 {
64 
65  Init(def);
66 }
67 
69 {
70 }
71 
72 // +--------------------------------------------------------------------+
73 
74 void
76 {
78  lst_combat = (ListBox*) FindControl(401);
79  lst_desc = (ListBox*) FindControl(402);
81 
82  RegisterCmdControls(this);
83 
84  if (btn_save)
86 
87  if (btn_exit)
89 
90  for (int i = 0; i < 5; i++) {
91  if (btn_mode[i])
93  }
94 
95  if (cmb_forces)
97 
98  if (lst_combat) {
99  lst_combat->AddColumn("datatype", 0);
101  }
102 
103  if (btn_transfer) {
104  btn_transfer->SetEnabled(false);
106  }
107 }
108 
109 // +--------------------------------------------------------------------+
110 
111 void
113 {
115 }
116 
117 // +--------------------------------------------------------------------+
118 
119 void
121 {
122  mode = MODE_FORCES;
123 
125  ShowCmdDlg();
126 
128 
130 
131  if (campaign) {
132  List<Combatant>& combatants = campaign->GetCombatants();
133 
134  if (combatants.size() > 0) {
135  for (int i = 0; i < combatants.size(); i++) {
136  if (IsVisible(combatants[i])) {
137  cmb_forces->AddItem(combatants[i]->Name());
138  }
139  }
140 
142  Combatant* c = combatants[0];
143  ShowCombatant(c);
144  }
145  }
146 }
147 
148 // +--------------------------------------------------------------------+
149 
150 bool
152 {
153  int nvis = 0;
154 
155  if (c) {
156  CombatGroup* force = c->GetForce();
157 
158  if (force) {
159  List<CombatGroup>& groups = force->GetComponents();
160  for (int i = 0; i < groups.size(); i++) {
161  CombatGroup* g = groups[i];
162 
163  if (g->Type() < CombatGroup::CIVILIAN &&
164  g->CountUnits() > 0 &&
165  g->IntelLevel() >= Intel::KNOWN)
166 
167  nvis++;
168  }
169  }
170  }
171 
172  return nvis > 0;
173 }
174 
175 // +--------------------------------------------------------------------+
176 
177 static char pipe_stack[32];
178 static bool blank_line = false;
179 
180 void
182 {
183  if (!lst_combat || !c) return;
184 
186  ZeroMemory(pipe_stack, 32);
187 
188  CombatGroup* force = c->GetForce();
189 
190  if (force) {
191  List<CombatGroup>& groups = force->GetComponents();
192  for (int i = 0; i < groups.size(); i++) {
193  CombatGroup* g = groups[i];
194  if (g->Type() < CombatGroup::CIVILIAN && g->CountUnits() > 0)
195  AddCombatGroup(g);
196  }
197  }
198 
199  current_group = 0;
200  current_unit = 0;
201 
202  if (lst_desc) lst_desc->ClearItems();
203  if (btn_transfer) btn_transfer->SetEnabled(false);
204 }
205 
206 void
208 {
209  if (!lst_combat || !grp || grp->IntelLevel() < Intel::KNOWN) return;
210 
211  char prefix[4];
212 
213  if (!grp->GetParent() || grp->GetParent()->Type() == CombatGroup::FORCE) {
214  if (!grp->IsExpanded()) {
215  prefix[0] = Font::PIPE_PLUS;
216  prefix[1] = 0;
217  }
218  else {
219  prefix[0] = Font::PIPE_MINUS;
220  prefix[1] = 0;
221  }
222  }
223  else {
224  prefix[0] = last_child ? Font::PIPE_LL : Font::PIPE_LT;
225  prefix[1] = Font::PIPE_HORZ;
226  prefix[2] = 0;
227  prefix[3] = 0;
228 
229  if (grp->GetLiveComponents().size() > 0 || grp->GetUnits().size() > 0) {
230  if (grp->IsExpanded())
231  prefix[1] = Font::PIPE_MINUS;
232  else
233  prefix[1] = Font::PIPE_PLUS;
234  }
235  }
236 
237  int index = lst_combat->AddItemWithData(
238  Text(pipe_stack) +
239  Text(prefix) +
240  grp->GetDescription(),
241  (DWORD) grp);
242  lst_combat->SetItemData(index-1, 1, 0);
243  blank_line = false;
244 
245  int stacklen = strlen(pipe_stack);
246 
247  if (!grp->GetParent() || grp->GetParent()->Type() == CombatGroup::FORCE)
248  ; // no stack after first entry
249  else if (prefix[0] == Font::PIPE_LT)
250  pipe_stack[stacklen++] = Font::PIPE_VERT;
251  else
252  pipe_stack[stacklen++] = Font::PIPE_NBSP;
253  pipe_stack[stacklen] = 0;
254 
255  if (grp->IsExpanded() && grp->GetUnits().size() > 0) {
256  prefix[0] = (grp->GetLiveComponents().size() > 0) ? Font::PIPE_VERT : Font::PIPE_NBSP;
257  prefix[1] = Font::PIPE_NBSP;
258  prefix[2] = 0;
259  prefix[3] = 0;
260 
261  ListIter<CombatUnit> unit_iter = grp->GetUnits();
262  while (++unit_iter) {
263  CombatUnit* unit = unit_iter.value();
264  char info[512];
265  int damage = (int) (100 * unit->GetSustainedDamage() / unit->GetDesign()->integrity);
266 
267  if (damage < 1 || unit->DeadCount() >= unit->Count()) {
268  sprintf_s(info, "%s%s%s", pipe_stack, prefix, unit->GetDescription());
269  } else {
270  sprintf_s(info, "%s%s%s %d%% damage", pipe_stack, prefix, unit->GetDescription(), damage);
271  }
272 
273  int index = lst_combat->AddItemWithData(info, (DWORD) unit);
274 
275  lst_combat->SetItemData(index-1, 1, 1);
276  lst_combat->SetItemColor(index-1, lst_combat->GetForeColor() * 0.65);
277  }
278 
279  // blank line after last unit in group:
280  lst_combat->AddItem(Text(pipe_stack) + Text(prefix));
281  blank_line = true;
282  }
283 
284  if (grp->IsExpanded() && grp->GetLiveComponents().size() > 0) {
285  List<CombatGroup>& groups = grp->GetLiveComponents();
286  for (int i = 0; i < groups.size(); i++) {
287  AddCombatGroup(groups[i], i == groups.size()-1);
288  }
289 
290  // blank line after last group in group:
291  if (!blank_line) {
292  lst_combat->AddItem(pipe_stack);
293  blank_line = true;
294  }
295  }
296 
297  pipe_stack[stacklen-1] = 0;
298 }
299 
300 // +--------------------------------------------------------------------+
301 
302 void
304 {
305  Text name = cmb_forces->GetSelectedItem();
306 
308 
309  if (campaign) {
311 
312  while (++iter) {
313  Combatant* c = iter.value();
314 
315  if (name == c->Name()) {
316  ShowCombatant(c);
317  break;
318  }
319  }
320  }
321 }
322 
323 // +--------------------------------------------------------------------+
324 
325 struct WepGroup {
327  int count;
328 
329  WepGroup() : count(0) { }
330 };
331 
332 WepGroup* FindWepGroup(WepGroup* weapons, const char* name)
333 {
334  WepGroup* group = 0;
335  WepGroup* iter = weapons;
336  int w = 0;
337  int first = -1;
338 
339  while (!group && w < 8) {
340  if (first < 0 && iter->name.length() == 0)
341  first = w;
342 
343  if (!_stricmp(iter->name, name))
344  group = iter;
345 
346  iter++;
347  w++;
348  }
349 
350  if (!group && first >= 0) {
351  group = weapons + first;
352  group->name = name;
353  }
354 
355  return group;
356 }
357 
358 void
360 {
361  static int old_index = -1;
362 
363  int top_index = 0;
364  bool expand = false;
365  DWORD data = 0;
366  DWORD type = 0;
367 
368  current_group = 0;
369  current_unit = 0;
370 
371  if (lst_combat) {
372  top_index = lst_combat->GetTopIndex();
373 
374  int index = lst_combat->GetListIndex();
375  data = lst_combat->GetItemData(index);
376  type = lst_combat->GetItemData(index, 1);
377  Text item = lst_combat->GetItemText(index);
378  int nplus = item.indexOf(Font::PIPE_PLUS);
379  int xplus = -1;
380  int dx = 10000;
381 
382  if (nplus < 0)
383  nplus = item.indexOf(Font::PIPE_MINUS);
384 
385  if (nplus >= 0 && nplus < 64) {
386  char pipe[64];
387  strncpy(pipe, item.data(), nplus+1);
388  pipe[nplus+1] = 0;
389 
390  Rect rect(0, 0, 1000, 20);
391  lst_combat->DrawText(pipe, 0, rect, DT_LEFT|DT_SINGLELINE|DT_VCENTER|DT_CALCRECT);
392 
393  xplus = rect.w;
394  }
395 
396  if (xplus > 0) {
397  dx = Mouse::X() - (lst_combat->GetRect().x + xplus - 16);
398  }
399 
400  // look for click on plus/minus in pipe
401  if (dx >= 0 && dx < 16) {
402  if (data && type == 0) {
403  CombatGroup* grp = (CombatGroup*) data;
404  grp->SetExpanded(!grp->IsExpanded());
405  expand = true;
406 
407  current_group = grp;
408  current_unit = 0;
409  }
410  }
411 
412  old_index = index;
413  }
414 
415  if (campaign && data) {
416  if (!expand) {
417  lst_desc->ClearItems();
418 
419  // combat group
420  if (type == 0) {
421  CombatGroup* grp = (CombatGroup*) data;
422 
423  current_group = grp;
424  current_unit = 0;
425 
426  // if has units, show location and assignment
427  if (grp->GetUnits().size() > 0) {
428  char txt[64];
429  int n;
430 
431  n = lst_desc->AddItem("Group:") - 1;
432  lst_desc->SetItemText(n, 1, grp->GetDescription());
433  n = lst_desc->AddItem("Sector:") - 1;
434  lst_desc->SetItemText(n, 1, grp->GetRegion());
435 
436  lst_desc->AddItem(" ");
437  n = lst_desc->AddItem("Sorties:") - 1;
438 
439  if (grp->Sorties() >= 0)
440  sprintf_s(txt, "%d", grp->Sorties());
441  else
442  strcpy_s(txt, "Unavail");
443 
444  lst_desc->SetItemText(n, 1, txt);
445 
446  n = lst_desc->AddItem("Kills:") - 1;
447 
448  if (grp->Kills() >= 0)
449  sprintf_s(txt, "%d", grp->Kills());
450  else
451  strcpy_s(txt, "Unavail");
452 
453  lst_desc->SetItemText(n, 1, txt);
454 
455  n = lst_desc->AddItem("Eff Rating:") - 1;
456 
457  if (grp->Points() >= 0) {
458  if (grp->Sorties() > 0)
459  sprintf_s(txt, "%.1f", (double) grp->Points() / grp->Sorties());
460  else
461  sprintf_s(txt, "%.1f", (double) grp->Points());
462  } else {
463  strcpy_s(txt, "Unavail");
464  }
465 
466  lst_desc->SetItemText(n, 1, txt);
467  }
468 
469  // else (if high-level) show components
470  else {
471  int n;
472 
473  n = lst_desc->AddItem("Group:") - 1;
474  lst_desc->SetItemText(n, 1, grp->GetDescription());
475 
477  while (++c) {
478  n = lst_desc->AddItem("-") - 1;
479  lst_desc->SetItemText(n, 1, c->GetDescription());
480  }
481  }
482  }
483  // combat unit
484  else {
485  CombatUnit* unit = (CombatUnit*) data;
486  current_group = unit->GetCombatGroup();
487  current_unit = unit;
488 
489  int n;
490  char txt[64];
491 
492  n = lst_desc->AddItem("Unit:") - 1;
493  lst_desc->SetItemText(n, 1, unit->GetDescription());
494  n = lst_desc->AddItem("Sector:") - 1;
495  lst_desc->SetItemText(n, 1, unit->GetRegion());
496 
497  const ShipDesign* design = unit->GetDesign();
498  if (design) {
499  lst_desc->AddItem(" ");
500  n = lst_desc->AddItem("Type:") - 1;
501  lst_desc->SetItemText(n, 1, Ship::ClassName(design->type));
502  n = lst_desc->AddItem("Class:") - 1;
503  lst_desc->SetItemText(n, 1, design->DisplayName());
504 
505  if (design->type < Ship::STATION)
506  FormatNumber(txt, design->radius/2);
507  else
508  FormatNumber(txt, design->radius*2);
509 
510  strcat_s(txt, " m");
511 
512  n = lst_desc->AddItem("Length:") - 1;
513  lst_desc->SetItemText(n, 1, txt);
514 
515  FormatNumber(txt, design->mass);
516  strcat_s(txt, " T");
517 
518  n = lst_desc->AddItem("Mass:") - 1;
519  lst_desc->SetItemText(n, 1, txt);
520 
521  FormatNumber(txt, design->integrity);
522  n = lst_desc->AddItem("Hull:") - 1;
523  lst_desc->SetItemText(n, 1, txt);
524 
525  if (design->weapons.size()) {
526  lst_desc->AddItem(" ");
527  n = lst_desc->AddItem("Weapons:") - 1;
528 
529  WepGroup groups[8];
530  for (int w = 0; w < design->weapons.size(); w++) {
531  Weapon* gun = design->weapons[w];
532  WepGroup* group = FindWepGroup(groups, gun->Group());
533 
534  if (group)
535  group->count++;
536  }
537 
538  for (int g = 0; g < 8; g++) {
539  WepGroup* group = &groups[g];
540  if (group && group->count) {
541  sprintf_s(txt, "%s (%d)", group->name.data(), group->count);
542  if (g > 0) n = lst_desc->AddItem(" ") - 1;
543  lst_desc->SetItemText(n, 1, txt);
544  }
545  }
546  }
547  }
548  }
549  }
550 
551  else {
552  List<Combatant>& combatants = campaign->GetCombatants();
553  Combatant* c = combatants[0];
554 
555  if (cmb_forces) {
556  Text name = cmb_forces->GetSelectedItem();
557 
558  for (int i = 0; i < combatants.size(); i++) {
559  c = combatants[i];
560 
561  if (name == c->Name()) {
562  break;
563  }
564  }
565  }
566 
567  if (c) {
568  ShowCombatant(c);
569 
570  lst_combat->ScrollTo(top_index);
571  lst_combat->SetSelected(old_index);
572  }
573  }
574  }
575 
579 }
580 
581 // +--------------------------------------------------------------------+
582 
583 bool
585 {
586  if (!grp || !campaign)
587  return false;
588 
589  if (grp->Type() < CombatGroup::WING)
590  return false;
591 
592  if (grp->Type() > CombatGroup::CARRIER_GROUP)
593  return false;
594 
595  if (grp->Type() == CombatGroup::FLEET ||
597  return false;
598 
599  CombatGroup* player_group = campaign->GetPlayerGroup();
600  if (player_group->GetIFF() != grp->GetIFF())
601  return false;
602 
603  return true;
604 }
605 
606 
607 // +--------------------------------------------------------------------+
608 
609 void
611 {
612  CmdDlg::OnSave(event);
613 }
614 
615 void
617 {
618  CmdDlg::OnExit(event);
619 }
620 
621 void
623 {
624  CmdDlg::OnMode(event);
625 }
626 
627 
628 // +--------------------------------------------------------------------+
629 
630 void
632 {
633  if (campaign && current_group) {
634 
635  // check player rank/responsibility:
636  Player* player = Player::GetCurrentPlayer();
637  int cmd_class = Ship::FIGHTER;
638 
639  switch (current_group->Type()) {
640  case CombatGroup::WING:
643  cmd_class = Ship::FIGHTER;
644  break;
645 
647  cmd_class = Ship::ATTACK;
648  break;
649 
651  cmd_class = Ship::LCA;
652  break;
653 
655  cmd_class = Ship::DESTROYER;
656  break;
657 
659  cmd_class = Ship::CRUISER;
660  break;
661 
663  case CombatGroup::FLEET:
664  cmd_class = Ship::CARRIER;
665  break;
666  }
667 
668  char transfer_info[512];
669 
670  if (player->CanCommand(cmd_class)) {
671  if (current_unit) {
673 
674  sprintf_s(transfer_info, "Your transfer request has been approved, %s %s. You are now assigned to the %s. Good luck.\n\nFleet Admiral A. Evars FORCOM\nCommanding",
675  Player::RankName(player->Rank()),
676  player->Name().data(),
678  }
679  else {
681 
682  sprintf_s(transfer_info, "Your transfer request has been approved, %s %s. You are now assigned to the %s. Good luck.\n\nFleet Admiral A. Evars FORCOM\nCommanding",
683  Player::RankName(player->Rank()),
684  player->Name().data(),
686  }
687 
689 
690  CmdMsgDlg* msgdlg = manager->GetCmdMsgDlg();
691  msgdlg->Title()->SetText("Transfer Approved");
692  msgdlg->Message()->SetText(transfer_info);
693  msgdlg->Message()->SetTextAlign(DT_LEFT);
694 
696  }
697 
698  else {
700 
701  sprintf_s(transfer_info, "Your transfer request has been denied, %s %s. The %s requires a command rank of %s. Please return to your unit and your duties.\n\nFleet Admiral A. Evars FORCOM\nCommanding",
702  Player::RankName(player->Rank()),
703  player->Name().data(),
706 
707  CmdMsgDlg* msgdlg = manager->GetCmdMsgDlg();
708  msgdlg->Title()->SetText("Transfer Denied");
709  msgdlg->Message()->SetText(transfer_info);
710  msgdlg->Message()->SetTextAlign(DT_LEFT);
711 
713  }
714  }
715 }