Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
RadioView.cpp
Go to the documentation of this file.
1 /* Project Starshatter 5.0
2  Destroyer Studios LLC
3  Copyright © 1997-2007. All Rights Reserved.
4 
5  SUBSYSTEM: Stars.exe
6  FILE: RadioView.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  View class for Radio Communications HUD Overlay
13 */
14 
15 #include "MemDebug.h"
16 #include "RadioView.h"
17 #include "RadioMessage.h"
18 #include "RadioTraffic.h"
19 #include "QuantumView.h"
20 #include "HUDView.h"
21 #include "Ship.h"
22 #include "Element.h"
23 #include "Sim.h"
24 #include "Starshatter.h"
25 
26 #include "CameraView.h"
27 #include "Color.h"
28 #include "Window.h"
29 #include "Video.h"
30 #include "Screen.h"
31 #include "DataLoader.h"
32 #include "Scene.h"
33 #include "FontMgr.h"
34 #include "FormatUtil.h"
35 #include "Keyboard.h"
36 #include "Mouse.h"
37 #include "Game.h"
38 #include "Menu.h"
39 
40 static Color hud_color = Color::Black;
41 static Color txt_color = Color::White;
42 
43 // +====================================================================+
44 //
45 // RADIO COMMUNICATIONS MENU:
46 //
47 
48 static Menu* fighter_menu = 0;
49 static Menu* starship_menu = 0;
50 static Menu* target_menu = 0;
51 static Menu* combat_menu = 0;
52 static Menu* formation_menu = 0;
53 static Menu* sensors_menu = 0;
54 static Menu* mission_menu = 0;
55 static Menu* wing_menu = 0;
56 static Menu* elem_menu = 0;
57 static Menu* control_menu = 0;
58 
59 static int starship_page = 0;
60 static int num_pages = 0;
61 const int PAGE_SIZE = 9;
62 
63 static MenuHistory history;
64 
65 void
67 {
68  static int initialized = 0;
69  if (initialized) return;
70 
71  target_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.TARGET"));
72  target_menu->AddItem(Game::GetText("RadioView.item.attack"), RadioMessage::ATTACK);
73  target_menu->AddItem(Game::GetText("RadioView.item.bracket"), RadioMessage::BRACKET);
74  target_menu->AddItem(Game::GetText("RadioView.item.escort"), RadioMessage::ESCORT);
75 
76  combat_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.COMBAT"));
77  combat_menu->AddItem(Game::GetText("RadioView.item.cover"), RadioMessage::COVER_ME);
78  combat_menu->AddItem(Game::GetText("RadioView.item.break-attack"), RadioMessage::WEP_FREE);
79  combat_menu->AddItem(Game::GetText("RadioView.item.form-up"), RadioMessage::FORM_UP);
80 
81  formation_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.FORMATION"));
82  formation_menu->AddItem(Game::GetText("RadioView.item.diamond"), RadioMessage::GO_DIAMOND);
83  formation_menu->AddItem(Game::GetText("RadioView.item.spread"), RadioMessage::GO_SPREAD);
84  formation_menu->AddItem(Game::GetText("RadioView.item.box"), RadioMessage::GO_BOX);
85  formation_menu->AddItem(Game::GetText("RadioView.item.trail"), RadioMessage::GO_TRAIL);
86 
87  sensors_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.SENSORS"));
88  sensors_menu->AddItem(Game::GetText("RadioView.item.emcon-1"), RadioMessage::GO_EMCON1);
89  sensors_menu->AddItem(Game::GetText("RadioView.item.emcon-2"), RadioMessage::GO_EMCON2);
90  sensors_menu->AddItem(Game::GetText("RadioView.item.emcon-3"), RadioMessage::GO_EMCON3);
91  sensors_menu->AddItem(Game::GetText("RadioView.item.probe"), RadioMessage::LAUNCH_PROBE);
92 
93  mission_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.MISSION"));
94  mission_menu->AddItem(Game::GetText("RadioView.item.skip-navpt"), RadioMessage::SKIP_NAVPOINT);
95  mission_menu->AddItem(Game::GetText("RadioView.item.resume"), RadioMessage::RESUME_MISSION);
96  mission_menu->AddItem(Game::GetText("RadioView.item.rtb"), RadioMessage::RTB);
97 
98  wing_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.WINGMAN"));
99  wing_menu->AddMenu(Game::GetText("RadioView.item.target"), target_menu);
100  wing_menu->AddMenu(Game::GetText("RadioView.item.combat"), combat_menu);
101  wing_menu->AddMenu(Game::GetText("RadioView.item.formation"), formation_menu);
102  wing_menu->AddMenu(Game::GetText("RadioView.item.mission"), mission_menu);
103  wing_menu->AddMenu(Game::GetText("RadioView.item.sensors"), sensors_menu);
104 
105  elem_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.ELEMENT"));
106  elem_menu->AddMenu(Game::GetText("RadioView.item.target"), target_menu);
107  elem_menu->AddMenu(Game::GetText("RadioView.item.combat"), combat_menu);
108  elem_menu->AddMenu(Game::GetText("RadioView.item.formation"), formation_menu);
109  elem_menu->AddMenu(Game::GetText("RadioView.item.mission"), mission_menu);
110  elem_menu->AddMenu(Game::GetText("RadioView.item.sensors"), sensors_menu);
111 
112  control_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.CONTROL"));
113  control_menu->AddItem(Game::GetText("RadioView.item.picture"), RadioMessage::REQUEST_PICTURE);
114  control_menu->AddItem(Game::GetText("RadioView.item.backup"), RadioMessage::REQUEST_SUPPORT);
115  control_menu->AddItem(Game::GetText("RadioView.item.call-inbound"), RadioMessage::CALL_INBOUND);
116  control_menu->AddItem(Game::GetText("RadioView.item.call-finals"), RadioMessage::CALL_FINALS);
117 
118  fighter_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.RADIO"));
119  fighter_menu->AddMenu(Game::GetText("RadioView.item.wingman"), wing_menu);
120  fighter_menu->AddMenu(Game::GetText("RadioView.item.element"), elem_menu);
121  fighter_menu->AddMenu(Game::GetText("RadioView.item.control"), control_menu);
122 
123  starship_menu = new(__FILE__,__LINE__) Menu(Game::GetText("RadioView.menu.RADIO"));
124 
125  initialized = 1;
126 }
127 
128 void
130 {
131  history.Clear();
132 
133  delete fighter_menu;
134  delete starship_menu;
135  delete target_menu;
136  delete combat_menu;
137  delete formation_menu;
138  delete sensors_menu;
139  delete mission_menu;
140  delete wing_menu;
141  delete elem_menu;
142  delete control_menu;
143 }
144 
145 static bool TargetRequired(const MenuItem* item)
146 {
147  if (item) {
148  switch (item->GetData()) {
152  return true;
153 
154  default:
155  if (item->GetData() == (DWORD) target_menu)
156  return true;
157  }
158  }
159 
160  return false;
161 }
162 
163 // +====================================================================+
164 
167 
169 : View(c), sim(0), ship(0), font(0), dst_elem(0)
170 {
171  radio_view = this;
172  sim = Sim::GetSim();
173 
174  width = window->Width();
175  height = window->Height();
176  xcenter = (width / 2.0) - 0.5;
177  ycenter = (height / 2.0) + 0.5;
178  font = FontMgr::Find("HUD");
179 
180  HUDView* hud = HUDView::GetInstance();
181  if (hud)
182  SetColor(hud->GetTextColor());
183 
184  for (int i = 0; i < MAX_MSG; i++)
185  msg_time[i] = 0;
186 }
187 
189 {
190  radio_view = 0;
191 }
192 
193 void
195 {
196  width = window->Width();
197  height = window->Height();
198  xcenter = (width / 2.0) - 0.5;
199  ycenter = (height / 2.0) + 0.5;
200 }
201 
202 // +--------------------------------------------------------------------+
203 
204 bool
206 {
207  if (obj == ship) {
208  ship = 0;
209  history.Clear();
210  }
211 
212  return SimObserver::Update(obj);
213 }
214 
215 const char*
217 {
218  return "RadioView";
219 }
220 
221 // +--------------------------------------------------------------------+
222 
223 void
225 {
226  sim = Sim::GetSim();
227 
228  if (!font)
229  return;
230 
231  font->SetColor(txt_color);
232  font->SetAlpha(1);
233 
234  if (sim && ship != sim->GetPlayerShip()) {
235  ship = sim->GetPlayerShip();
236  history.Clear();
237 
238  if (ship) {
239  if (ship->Life() == 0 || ship->IsDying() || ship->IsDead()) {
240  ship = 0;
241  }
242  else {
243  Observe(ship);
244  }
245  }
246  }
247 
249 
250  if (!qv || !qv->IsMenuShown()) {
251  Menu* menu = history.GetCurrent();
252 
253  if (menu) {
254  Rect menu_rect(width-115, 10, 115, 12);
255 
256  font->DrawText(menu->GetTitle(), 0, menu_rect, DT_CENTER);
257  menu_rect.y += 15;
258 
259  ListIter<MenuItem> item = menu->GetItems();
260  while (++item) {
261  if (ship->GetEMCON() < 2 ||
262  (TargetRequired(item.value()) && !ship->GetTarget()) ||
263  item->GetText().contains("KIA")) {
264  item->SetEnabled(false);
265  font->SetAlpha(0.35);
266  }
267  else {
268  item->SetEnabled(true);
269  font->SetAlpha(1);
270  }
271 
272  font->DrawText(item->GetText(), 0, menu_rect, DT_LEFT);
273  menu_rect.y += 10;
274  }
275  }
276  }
277 
278  int message_queue_empty = true;
279 
280  // age messages:
281  for (int i = 0; i < MAX_MSG; i++) {
282  if (msg_time[i] > 0) {
283  msg_time[i] -= Game::GUITime();
284 
285  if (msg_time[i] <= 0) {
286  msg_time[i] = 0;
287  msg_text[i] = "";
288  }
289 
290  message_queue_empty = false;
291  }
292  }
293 
294  if (!message_queue_empty) {
295  // advance message pipeline:
296  for (int i = 0; i < MAX_MSG; i++) {
297  if (msg_time[0] == 0) {
298  for (int j = 0; j < MAX_MSG-1; j++) {
299  msg_time[j] = msg_time[j+1];
300  msg_text[j] = msg_text[j+1];
301  }
302 
303  msg_time[MAX_MSG-1] = 0;
304  msg_text[MAX_MSG-1] = "";
305  }
306  }
307 
308  bool hud_off = false;
309 
310  if (HUDView::GetInstance())
311  hud_off = (HUDView::GetInstance()->GetHUDMode() == HUDView::HUD_MODE_OFF);
312 
313  // draw messages:
314  if (!hud_off) {
315  for (int i = 0; i < MAX_MSG; i++) {
316  if (msg_time[i] > 0) {
317  Rect msg_rect(0, 95 + i*10, width, 12);
318 
319  if (msg_time[i] > 1)
320  font->SetAlpha(1);
321  else
322  font->SetAlpha(0.5 + 0.5*msg_time[i]);
323 
324  font->DrawText(msg_text[i].data(), msg_text[i].length(), msg_rect, DT_CENTER);
325  }
326  }
327 
328  font->SetAlpha(1);
329  }
330  }
331 
333  if (stars && stars->GetChatMode()) {
334  Text chat;
335 
336  switch (stars->GetChatMode()) {
337  case 1: chat = "ALL: "; break;
338  case 2: chat = "TEAM: "; break;
339  case 3: chat = "WING: "; break;
340  case 4: chat = "UNIT: "; break;
341  }
342 
343  chat += stars->GetChatText();
344 
345  Rect chat_rect(width/2 - 250, height-150, 500, 12);
346  font->DrawText(chat, 0, chat_rect, DT_LEFT);
347 
348  chat_rect.Inflate(2,2);
349  window->DrawRect(chat_rect, hud_color);
350  }
351 }
352 
353 // +--------------------------------------------------------------------+
354 
355 void
357 {
358  if (!ship || !item) return;
359  Element* elem = ship->GetElement();
360  if (!elem) return;
361 
362  // check destination:
363  if (dst_elem) {
364  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(dst_elem, ship, item->GetData());
365 
366  if (TargetRequired(item))
367  msg->AddTarget(ship->GetTarget());
368 
370  dst_elem = 0;
371  }
372 
373  else if (history.Find(Game::GetText("RadioView.menu.WINGMAN"))) { // wingman menu
374  int index = ship->GetElementIndex();
375  int wing = 0;
376 
377  switch (index) {
378  case 1: wing = 2; break;
379  case 2: wing = 1; break;
380  case 3: wing = 4; break;
381  case 4: wing = 3; break;
382  }
383 
384  if (wing) {
385  Ship* dst = elem->GetShip(wing);
386  if (dst) {
387  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(dst, ship, item->GetData());
388 
389  if (TargetRequired(item))
390  msg->AddTarget(ship->GetTarget());
391 
393  }
394  }
395  }
396 
397  else if (history.Find(Game::GetText("RadioView.menu.ELEMENT"))) { // element menu
398  RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(elem, ship, item->GetData());
399 
400  if (TargetRequired(item))
401  msg->AddTarget(ship->GetTarget());
402 
404  }
405 
406  else if (history.Find(Game::GetText("RadioView.menu.CONTROL"))) { // control menu
407  RadioMessage* msg = 0;
408  Ship* controller = ship->GetController();
409 
410  if (controller) {
411  msg = new(__FILE__,__LINE__) RadioMessage(controller, ship, item->GetData());
413  }
414  }
415 }
416 
417 // +--------------------------------------------------------------------+
418 
419 void
421 {
422  HUDView* hud = HUDView::GetInstance();
423  if (hud) {
424  if (txt_color != hud->GetTextColor()) {
425  txt_color = hud->GetTextColor();
426  SetColor(txt_color);
427  }
428 
429  hud_color = hud->GetHUDColor();
430  }
431 
432  static int current_key = 0;
433 
434  if (current_key > 0 && Keyboard::KeyDown(current_key))
435  return;
436 
437  current_key = 0;
438 
439  Menu* menu = history.GetCurrent();
440  if (menu) {
441  int max_items = menu->NumItems();
442 
443  if (menu == starship_menu && Keyboard::KeyDown('0')) {
444  current_key = '0';
445  if (++starship_page >= num_pages)
446  starship_page = 0;
447 
448  history.Pop();
449  history.Push(GetRadioMenu(ship));
450  }
451  else {
452  for (int i = 0; i < max_items; i++) {
453  if (Keyboard::KeyDown('1' + i)) {
454  current_key = '1' + i;
455  MenuItem* item = menu->GetItem(i);
456  if (item && item->GetEnabled()) {
457  if (item->GetSubmenu()) {
458  if (history.GetCurrent() == starship_menu)
459  dst_elem = (Element*) item->GetData();
460 
461  history.Push(item->GetSubmenu());
462  }
463  else {
464  // execute radio message:
465  SendRadioMessage(ship, item);
466 
467  // clear radio menu:
468  history.Clear();
469  }
470 
471  break;
472  }
473  }
474  }
475  }
476  }
477 }
478 
479 // +--------------------------------------------------------------------+
480 
481 void
483 {
484  HUDView* hud = HUDView::GetInstance();
485 
486  if (hud) {
487  hud_color = hud->GetHUDColor();
488  txt_color = hud->GetTextColor();
489  }
490  else {
491  hud_color = c;
492  txt_color = c;
493  }
494 }
495 
496 // +--------------------------------------------------------------------+
497 
498 bool
500 {
501  return history.GetCurrent() != 0;
502 }
503 
504 void
506 {
507  if (!ship) return;
508 
509  if (!history.GetCurrent()) {
510  history.Push(GetRadioMenu(ship));
511 
512  for (int i = 0; i < 10; i++) {
513  if (Keyboard::KeyDown('1' + i)) {
514  // just need to clear the key down flag
515  // so we don't process old keystrokes
516  // as valid menu picks...
517  }
518  }
519  }
520 }
521 
522 void
524 {
525  history.Clear();
526  dst_elem = 0;
527  starship_page = 0;
528  num_pages = 0;
529 }
530 
531 // +--------------------------------------------------------------------+
532 
533 Menu*
535 {
536  dst_elem = 0;
537 
538  if (s && sim) {
539  if (s->IsStarship()) {
540  starship_menu->ClearItems();
541 
542  int n = 0;
543  int page_offset = starship_page*PAGE_SIZE;
544 
546 
547  if (num_pages == 0) {
548  while (++elem) {
549  if (elem->IsFinished() || elem->IsSquadron() || elem->IsStatic())
550  continue;
551 
552  if (ship->GetIFF() == elem->GetIFF() && ship->GetElement() != elem.value())
553  n++;
554  }
555 
556  num_pages = (n/PAGE_SIZE) + (n%PAGE_SIZE > 0);
557  n = 0;
558  elem.reset();
559  }
560 
561  while (++elem) {
562  if (elem->IsFinished() || elem->IsSquadron() || elem->IsStatic())
563  continue;
564 
565  if (ship->GetIFF() == elem->GetIFF() && ship->GetElement() != elem.value()) {
566  if (n >= page_offset && n < page_offset+PAGE_SIZE) {
567  char text[64];
568  sprintf_s(text, "%d. %s", n+1 - page_offset, (const char*) elem->Name());
569 
570  if (elem->IsActive()) {
571  starship_menu->AddMenu(text, elem_menu, (DWORD) elem.value());
572  }
573  else {
574  strcat_s(text, " ");
575  strcat_s(text, Game::GetText("RadioView.item.not-avail").data());
576  starship_menu->AddItem(text, 0, false);
577  }
578  }
579  n++;
580  }
581  }
582 
583  if (num_pages > 1) {
584  char text[64];
585  sprintf_s(text, Game::GetText("RadioView.item.next-page").data(), starship_page + 1, num_pages);
586  starship_menu->AddItem(text);
587  }
588 
589  return starship_menu;
590  }
591  else if (s->IsDropship()) {
592  return fighter_menu;
593  }
594  }
595 
596  return 0;
597 }
598 
599 // +--------------------------------------------------------------------+
600 
601 void
602 RadioView::Message(const char* msg)
603 {
604  AutoThreadSync a(sync);
605 
606  if (radio_view) {
607  int index = -1;
608 
609  for (int i = 0; i < MAX_MSG; i++) {
610  if (radio_view->msg_time[i] <= 0) {
611  index = i;
612  break;
613  }
614  }
615 
616  // no space; advance pipeline:
617  if (index < 0) {
618  for (int i = 0; i < MAX_MSG-1; i++) {
621  }
622 
623  index = MAX_MSG-1;
624  }
625 
626  radio_view->msg_text[index] = msg;
627  radio_view->msg_time[index] = 10;
628  }
629 }
630 
631 void
633 {
634  if (radio_view) {
635  for (int i = 0; i < MAX_MSG-1; i++) {
636  radio_view->msg_text[i] = Text();
637  radio_view->msg_time[i] = 0;
638  }
639  }
640 }