Starshatter_Open
Open source Starshatter engine
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
MapView.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: MapView.cpp
7  AUTHOR: John DiCamillo
8 
9 
10  OVERVIEW
11  ========
12  Star Map class
13 */
14 
15 #include "MemDebug.h"
16 #include "MapView.h"
17 
18 #include "Galaxy.h"
19 #include "StarSystem.h"
20 #include "Ship.h"
21 #include "ShipDesign.h"
22 #include "Instruction.h"
23 #include "Element.h"
24 #include "NavAI.h"
25 #include "Weapon.h"
26 #include "Sim.h"
27 #include "Mission.h"
28 #include "Campaign.h"
29 #include "Combatant.h"
30 #include "CombatGroup.h"
31 #include "CombatUnit.h"
32 #include "Contact.h"
33 #include "MenuView.h"
34 
35 #include "NetLobby.h"
36 #include "NetUtil.h"
37 
38 #include "Game.h"
39 #include "DataLoader.h"
40 #include "EventDispatch.h"
41 #include "Video.h"
42 #include "Button.h"
43 #include "Bitmap.h"
44 #include "Font.h"
45 #include "FontMgr.h"
46 #include "Mouse.h"
47 #include "FormatUtil.h"
48 #include "Menu.h"
49 
50 // +--------------------------------------------------------------------+
51 
52 // Supported Selection Modes:
53 
54 const int SELECT_NONE = -1;
55 const int SELECT_SYSTEM = 0;
56 const int SELECT_PLANET = 1;
57 const int SELECT_REGION = 2;
58 const int SELECT_STATION = 3;
59 const int SELECT_STARSHIP = 4;
60 const int SELECT_FIGHTER = 5;
61 const int SELECT_NAVPT = 6;
62 
63 const int VIEW_GALAXY = 0;
64 const int VIEW_SYSTEM = 1;
65 const int VIEW_REGION = 2;
66 
67 // +--------------------------------------------------------------------+
68 
70 : View(win)
71 , system(0), zoom(1.1), offset_x(0), offset_y(0), ship(0), campaign(0)
72 , captured(false), dragging(false), adding_navpt(false)
73 , moving_navpt(false), moving_elem(false)
74 , view_mode(VIEW_SYSTEM), seln_mode(SELECT_REGION), ship_filter(0xffffffff)
75 , current_star(0), current_planet(0), current_region(0)
76 , current_ship(0), current_elem(0), current_navpt(0), mission(0)
77 , scrolling(0), scroll_x(0), scroll_y(0), click_x(0), click_y(0)
78 , active_menu(0), map_menu(0), map_system_menu(0), map_sector_menu(0)
79 , ship_menu(0), editor(false)
80 , nav_menu(0), action_menu(0), objective_menu(0), formation_menu(0), speed_menu(0)
81 , hold_menu(0), farcast_menu(0), menu_view(0)
82 {
83  for (int i = 0; i < 3; i++) {
84  view_zoom[i] = zoom;
87  }
88 
89  menu_view = new(__FILE__,__LINE__) MenuView(window);
90 
91  title_font = FontMgr::Find("Limerick12");
92  font = FontMgr::Find("Verdana");
93 
95 
96  if (active_window)
97  active_window->AddView(this);
98 }
99 
100 // +--------------------------------------------------------------------+
101 
103 {
104  ClearMenu();
106 
107  delete menu_view;
108 }
109 
110 // +--------------------------------------------------------------------+
111 
112 void
114 {
115  if (menu_view)
117 }
118 
119 // +--------------------------------------------------------------------+
120 
121 void
123 {
124  system_list.clear();
125  system_list.append(g);
126 
127  if (system_list.size() > 0) {
129  }
130 }
131 
132 void
134 {
135  if (system != s) {
136  system = s;
137 
138  // forget invalid selection:
139  current_star = 0;
140  current_planet = 0;
141  current_region = 0;
142  current_ship = 0;
143  current_elem = 0;
144  current_navpt = 0;
145 
146  // flush old object pointers:
147  stars.clear();
148  planets.clear();
149  regions.clear();
150 
151  // insert objects from star system:
152  if (system) {
154  while (++star) {
155  switch (star->Type()) {
156  case Orbital::STAR: stars.append(star.value());
157  break;
158  case Orbital::PLANET:
159  case Orbital::MOON: planets.append(star.value());
160  break;
161  }
162  }
163 
164  ListIter<OrbitalBody> planet = star->Satellites();
165  while (++planet) {
166  planets.append(planet.value());
167 
168  ListIter<OrbitalBody> moon = planet->Satellites();
169  while (++moon) {
170  planets.append(moon.value());
171  }
172  }
173 
175  while (++rgn)
176  regions.append(rgn.value());
177 
178  // sort region list by distance from the star:
179  regions.sort();
180  }
181 
182  BuildMenu();
183  }
184 }
185 
186 // +--------------------------------------------------------------------+
187 
188 void
190 {
191  if (ship != s) {
192  ship = s;
193 
194  // forget invalid selection:
195  current_star = 0;
196  current_planet = 0;
197  current_region = 0;
198  current_ship = 0;
199  current_elem = 0;
200  current_navpt = 0;
201 
202  if (ship && system_list.size() > 0) {
203  SimRegion* rgn = ship->GetRegion();
204 
205  if (rgn && rgn->System()) {
206  system = 0;
207  SetSystem(rgn->System());
208  }
209  }
210 
211  BuildMenu();
212  }
213 }
214 
215 // +--------------------------------------------------------------------+
216 
217 void
219 {
220  if (mission != m) {
221  mission = m;
222 
223  // forget invalid selection:
224  current_star = 0;
225  current_planet = 0;
226  current_region = 0;
227  current_ship = 0;
228  current_elem = 0;
229  current_navpt = 0;
230 
231  if (mission && system_list.size() > 0) {
232  system = 0;
234  }
235 
236  BuildMenu();
237  }
238 }
239 
240 // +--------------------------------------------------------------------+
241 
242 void
244 {
245  if (campaign != c) {
246  campaign = c;
247 
248  // forget invalid selection:
249  current_star = 0;
250  current_planet = 0;
251  current_region = 0;
252  current_ship = 0;
253  current_elem = 0;
254  current_navpt = 0;
255 
256  if (campaign)
258  }
259 }
260 
261 // +--------------------------------------------------------------------+
262 
264  MAP_SYSTEM = 1000,
265  MAP_SECTOR = 2000,
266  MAP_SHIP = 3000,
267  MAP_NAV = 4000,
268  MAP_ADDNAV = 4001,
269  MAP_DELETE = 4002,
270  MAP_CLEAR = 4003,
271  MAP_ACTION = 5000,
273  MAP_SPEED = 7000,
274  MAP_HOLD = 8000,
275  MAP_FARCAST = 8500,
277 };
278 
279 void
281 {
282  ClearMenu();
283 
284  map_system_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.STARSYSTEM"));
285 
286  if (system_list.size() > 0) {
287  int i = 0;
289  while (++iter) {
290  StarSystem* s = iter.value();
292  i++;
293  }
294  }
295 
296  else if (system) {
298  }
299 
300  map_sector_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.SECTOR"));
301  for (int i = 0; i < regions.size(); i++) {
302  Orbital* rgn = regions[i];
303  map_sector_menu->AddItem(rgn->Name(), MAP_SECTOR + i);
304  }
305 
306  map_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.MAP"));
307  map_menu->AddMenu("System", map_system_menu);
308  map_menu->AddMenu("Sector", map_sector_menu);
309 
310  if (ship || mission) {
311  ship_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.SHIP"));
312  ship_menu->AddMenu(Game::GetText("MapView.item.Starsystem"), map_system_menu);
313  ship_menu->AddMenu(Game::GetText("MapView.item.Sector"), map_sector_menu);
314 
315  ship_menu->AddItem("", 0);
316  ship_menu->AddItem(Game::GetText("MapView.item.Add-Nav"), MAP_ADDNAV);
317  ship_menu->AddItem(Game::GetText("MapView.item.Clear-All"), MAP_CLEAR);
318 
319  action_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.ACTION"));
320  for (int i = 0; i < Instruction::NUM_ACTIONS; i++) {
322  }
323 
324  formation_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.FORMATION"));
325  for (int i = 0; i < Instruction::NUM_FORMATIONS; i++) {
327  }
328 
329  speed_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.SPEED"));
330  speed_menu->AddItem("250", MAP_SPEED + 0);
331  speed_menu->AddItem("500", MAP_SPEED + 1);
332  speed_menu->AddItem("750", MAP_SPEED + 2);
333  speed_menu->AddItem("1000", MAP_SPEED + 3);
334 
335  hold_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.HOLD"));
336  hold_menu->AddItem(Game::GetText("MapView.item.None"), MAP_HOLD + 0);
337  hold_menu->AddItem(Game::GetText("MapView.item.1-Minute"), MAP_HOLD + 1);
338  hold_menu->AddItem(Game::GetText("MapView.item.5-Minutes"), MAP_HOLD + 2);
339  hold_menu->AddItem(Game::GetText("MapView.item.10-Minutes"), MAP_HOLD + 3);
340  hold_menu->AddItem(Game::GetText("MapView.item.15-Minutes"), MAP_HOLD + 4);
341 
342  farcast_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.FARCAST"));
343  farcast_menu->AddItem(Game::GetText("MapView.item.Use-Quantum"), MAP_FARCAST + 0);
344  farcast_menu->AddItem(Game::GetText("MapView.item.Use-Farcast"), MAP_FARCAST + 1);
345 
346  objective_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.OBJECTIVE"));
347 
348  nav_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.NAVPT"));
349  nav_menu->AddMenu(Game::GetText("MapView.item.Action"), action_menu);
350  nav_menu->AddMenu(Game::GetText("MapView.item.Objective"), objective_menu);
351  nav_menu->AddMenu(Game::GetText("MapView.item.Formation"), formation_menu);
352  nav_menu->AddMenu(Game::GetText("MapView.item.Speed"), speed_menu);
353  nav_menu->AddMenu(Game::GetText("MapView.item.Hold"), hold_menu);
354  nav_menu->AddMenu(Game::GetText("MapView.item.Farcast"), farcast_menu);
355  nav_menu->AddItem("", 0);
356  nav_menu->AddItem(Game::GetText("MapView.item.Add-Nav"), MAP_ADDNAV);
357  nav_menu->AddItem(Game::GetText("MapView.item.Del-Nav"), MAP_DELETE);
358  }
359 
360  else if (campaign) {
361  ship_menu = 0;
362  speed_menu = 0;
363  hold_menu = 0;
364  farcast_menu = 0;
365  objective_menu = 0;
366  formation_menu = 0;
367  nav_menu = 0;
368  }
369 
371 }
372 
373 // +--------------------------------------------------------------------+
374 
375 void
377 {
378  delete map_menu;
379  delete map_system_menu;
380  delete map_sector_menu;
381  delete ship_menu;
382  delete nav_menu;
383  delete action_menu;
384  delete objective_menu;
385  delete formation_menu;
386  delete speed_menu;
387  delete hold_menu;
388  delete farcast_menu;
389 
390  map_menu = 0;
391  map_system_menu = 0;
392  map_sector_menu = 0;
393  ship_menu = 0;
394  nav_menu = 0;
395  action_menu = 0;
396  objective_menu = 0;
397  formation_menu = 0;
398  speed_menu = 0;
399  hold_menu = 0;
400  farcast_menu = 0;
401 }
402 
403 // +--------------------------------------------------------------------+
404 
405 void
407 {
408  bool send_nav_data = false;
409  bool can_command = true;
410 
411  if (ship && current_ship && ship != current_ship) {
412  if (ship->GetElement() && current_ship->GetElement()) {
414  can_command = false;
415  }
416  }
417  }
418 
419  else if (current_elem && NetLobby::GetInstance()) {
420  can_command = false;
421  }
422 
423  if (action >= MAP_OBJECTIVE) {
424  int index = action - MAP_OBJECTIVE;
425 
426  if (current_navpt && can_command) {
428  send_nav_data = true;
429  }
430  }
431 
432  else if (action >= MAP_FARCAST) {
433  if (current_navpt && can_command) {
435  send_nav_data = true;
436  }
437  }
438 
439  else if (action >= MAP_HOLD) {
440  int hold_time = 0;
441  switch (action) {
442  default:
443  case MAP_HOLD + 0: hold_time = 0; break;
444  case MAP_HOLD + 1: hold_time = 60; break;
445  case MAP_HOLD + 2: hold_time = 300; break;
446  case MAP_HOLD + 3: hold_time = 600; break;
447  case MAP_HOLD + 4: hold_time = 900; break;
448  }
449 
450  if (current_navpt && can_command) {
451  current_navpt->SetHoldTime(hold_time);
452  send_nav_data = true;
453  }
454  }
455 
456  else if (action >= MAP_SPEED) {
457  if (current_navpt && can_command) {
458  current_navpt->SetSpeed((action - MAP_SPEED + 1) * 250);
459  send_nav_data = true;
460  }
461  }
462 
463  else if (action >= MAP_FORMATION) {
464  if (current_navpt && can_command) {
466  send_nav_data = true;
467  }
468  }
469 
470  else if (action >= MAP_ACTION) {
471  if (current_navpt && can_command) {
474  send_nav_data = true;
475  }
476  }
477 
478  else if (action == MAP_ADDNAV) {
479  Text rgn_name = regions[current_region]->Name();
480  Instruction* prior = current_navpt;
481  Instruction* n = 0;
482 
483  if (current_ship && can_command) {
484  Sim* sim = Sim::GetSim();
485  SimRegion* rgn = sim->FindRegion(rgn_name);
486  Point init_pt;
487 
488  if (rgn) {
489  if (rgn->IsAirSpace())
490  init_pt.z = 10e3;
491 
492  n = new(__FILE__,__LINE__) Instruction(rgn, init_pt);
493  }
494  else {
495  n = new(__FILE__,__LINE__) Instruction(rgn_name, init_pt);
496  }
497 
498  n->SetSpeed(500);
499 
500  if (prior) {
501  n->SetAction(prior->Action());
502  n->SetFormation(prior->Formation());
503  n->SetSpeed(prior->Speed());
504  n->SetTarget(prior->GetTarget());
505  }
506 
507  current_ship->AddNavPoint(n, prior);
508  }
509 
510  else if (current_elem && can_command) {
511  Point init_pt;
512 
513  if (regions[current_region]->Type() == Orbital::TERRAIN)
514  init_pt.z = 10e3;
515 
516  n = new(__FILE__,__LINE__) Instruction(rgn_name, init_pt);
517  n->SetSpeed(500);
518 
519  if (prior) {
520  n->SetAction(prior->Action());
521  n->SetFormation(prior->Formation());
522  n->SetSpeed(prior->Speed());
523  n->SetTarget(prior->GetTarget());
524  }
525 
526  current_elem->AddNavPoint(n, prior);
527  }
528 
529  if (can_command) {
530  current_navpt = n;
532  adding_navpt = true;
533  captured = SetCapture();
534  }
535  }
536 
537  else if (action == MAP_DELETE) {
538  if (current_navpt && can_command) {
539  if (current_ship)
541  else if (current_elem && can_command)
543 
544  SelectNavpt(0);
545  }
546  }
547 
548  else if (action == MAP_CLEAR) {
549  if (current_ship && can_command)
551  else if (current_elem && can_command)
553 
554  SelectNavpt(0);
555  }
556 
557  else if (action >= MAP_NAV) {
558  }
559 
560  else if (action >= MAP_SHIP) {
561  }
562 
563  else if (action >= MAP_SECTOR) {
564  int index = action - MAP_SECTOR;
565 
566  if (index < regions.size())
567  current_region = index;
568 
569  if (view_mode == VIEW_SYSTEM) {
571  SetupScroll(s);
572  }
573  }
574 
575  else if (system_list.size() > 0 && action >= MAP_SYSTEM) {
576  int index = action - MAP_SYSTEM;
577 
578  if (index < system_list.size())
579  SetSystem(system_list[index]);
580  }
581 
582  else {
583  }
584 
585  Sim* sim = Sim::GetSim();
586  if (send_nav_data && sim) {
587  Ship* s = current_ship;
588 
589  if (s && s->GetElement()) {
590  Element* elem = s->GetElement();
591  int index = elem->GetNavIndex(current_navpt);
592 
593  if (index >= 0)
594  NetUtil::SendNavData(false, elem, index-1, current_navpt);
595  }
596  }
597 }
598 
599 // +--------------------------------------------------------------------+
600 
601 bool
603 {
605  if (dispatch)
606  return dispatch->CaptureMouse(this) ? true : false;
607 
608  return 0;
609 }
610 
611 // +--------------------------------------------------------------------+
612 
613 bool
615 {
617  if (dispatch)
618  return dispatch->ReleaseMouse(this) ? true : false;
619 
620  return 0;
621 }
622 
623 // +--------------------------------------------------------------------+
624 
625 void
627 {
628  if (mode >= 0 && mode < 3) {
629  // save state:
633 
634  // switch mode:
635  view_mode = mode;
636 
637  // restore state:
638 
639  if (view_mode == VIEW_GALAXY) {
640  zoom = 1;
641  offset_x = 0;
642  offset_y = 0;
643  }
644  else {
648  }
649 
650  scrolling = 0;
651  scroll_x = 0;
652  scroll_y = 0;
653  }
654 }
655 
656 // +--------------------------------------------------------------------+
657 
658 bool
660 {
661  if (obj == current_ship) {
662  current_ship = 0;
664  }
665 
666  return SimObserver::Update(obj);
667 }
668 
669 // +--------------------------------------------------------------------+
670 
671 void
673 {
674  if (selship != current_ship) {
675  current_ship = selship;
676 
677  if (current_ship) {
678  if (current_ship->Life() == 0 || current_ship->IsDying() || current_ship->IsDead()) {
679  current_ship = 0;
680  }
681  else {
683  }
684  }
685  }
686 
687  SelectNavpt(0);
688 }
689 
690 // +--------------------------------------------------------------------+
691 
692 void
694 {
695  if (elem != current_elem) {
696  current_elem = elem;
697 
698  if (current_elem) {
699  if (current_elem->IsStarship()) {
700  ship_menu->GetItem(3)->SetEnabled(true);
701  }
702 
703  else if (current_elem->IsDropship()) {
704  ship_menu->GetItem(3)->SetEnabled(true);
705  }
706 
707  else {
708  ship_menu->GetItem(3)->SetEnabled(false);
709  }
710  }
711  }
712 
713  SelectNavpt(0);
714 }
715 
716 // +--------------------------------------------------------------------+
717 
718 void
720 {
721  current_navpt = navpt;
722 
723  if (current_navpt) {
725 
726  List<Text> ships;
728 
729  switch (current_navpt->Action()) {
730  case Instruction::VECTOR:
731  case Instruction::LAUNCH:
732  case Instruction::PATROL:
733  case Instruction::SWEEP:
734  case Instruction::RECON:
735  objective_menu->AddItem(Game::GetText("MapView.item.not-available"), 0);
736  objective_menu->GetItem(0)->SetEnabled(false);
737  break;
738 
739  case Instruction::DOCK:
740  FindShips(true, true, true, false, ships);
741  break;
742 
743  case Instruction::DEFEND:
744  FindShips(true, true, true, false, ships);
745  break;
746 
747  case Instruction::ESCORT:
748  FindShips(true, false, true, true, ships);
749  break;
750 
752  FindShips(false, false, false, true, ships);
753  break;
754 
756  FindShips(false, false, true, false, ships);
757  break;
758 
759  case Instruction::STRIKE:
760  FindShips(false, true, false, false, ships);
761  break;
762  }
763 
764  for (int i = 0; i < ships.size(); i++)
765  objective_menu->AddItem(ships[i]->data(), MAP_OBJECTIVE + i);
766 
767  ships.destroy();
768  }
769  else {
771  objective_menu->AddItem(Game::GetText("MapView.item.not-available"), 0);
772  objective_menu->GetItem(0)->SetEnabled(false);
773  }
774 }
775 
776 // +--------------------------------------------------------------------+
777 
778 void
779 MapView::FindShips(bool friendly, bool station, bool starship, bool dropship,
780 List<Text>& result)
781 {
782  if (mission) {
783  for (int i = 0; i < mission->GetElements().size(); i++) {
784  MissionElement* elem = mission->GetElements().at(i);
785 
786  if (elem->IsSquadron()) continue;
787  if (!station && elem->IsStatic()) continue;
788  if (!starship && elem->IsStarship()) continue;
789  if (!dropship && elem->IsDropship()) continue;
790 
791  if (!editor && friendly && elem->GetIFF() > 0 && elem->GetIFF() != mission->Team())
792  continue;
793 
794  if (!editor && !friendly && (elem->GetIFF() == 0 || elem->GetIFF() == mission->Team()))
795  continue;
796 
797  result.append(new(__FILE__,__LINE__) Text(elem->Name()));
798  }
799  }
800 
801  else if (ship) {
802  Sim* sim = Sim::GetSim();
803 
804  if (sim) {
805  for (int r = 0; r < sim->GetRegions().size(); r++) {
806  SimRegion* rgn = sim->GetRegions().at(r);
807 
808  for (int i = 0; i < rgn->Ships().size(); i++) {
809  Ship* s = rgn->Ships().at(i);
810 
811  if (!station && s->IsStatic()) continue;
812  if (!starship && s->IsStarship()) continue;
813  if (!dropship && s->IsDropship()) continue;
814 
815  if (friendly && s->GetIFF() > 0 && s->GetIFF() != ship->GetIFF())
816  continue;
817 
818  if (!friendly && (s->GetIFF() == 0 || s->GetIFF() == ship->GetIFF()))
819  continue;
820 
821  result.append(new(__FILE__,__LINE__) Text(s->Name()));
822  }
823  }
824  }
825  }
826 }
827 
828 // +--------------------------------------------------------------------+
829 
830 void
832 {
833  if (mode <= SELECT_NONE) {
835  return;
836  }
837 
838  if (mode != seln_mode && mode <= SELECT_FIGHTER) {
839  seln_mode = mode;
840 
841  // when changing mode,
842  // select the item closest to the current center:
843  if (system && view_mode == VIEW_SYSTEM)
844  SelectAt(rect.x + rect.w/2,
845  rect.y + rect.h/2);
846  }
847 }
848 
849 void
851 {
852  if (scrolling) return;
853  Orbital* s = 0;
854 
855  switch (seln_mode) {
856  case SELECT_SYSTEM:
857  if (index < system_list.size())
858  SetSystem(system_list[index]);
859  s = stars[current_star];
860  break;
861 
862  default:
863  case SELECT_PLANET:
864  if (index < planets.size())
865  current_planet = index;
866  s = planets[current_planet];
867  break;
868 
869  case SELECT_REGION:
870  if (index < regions.size())
871  current_region = index;
872  s = regions[current_region];
873  break;
874 
875  case SELECT_STATION:
876  {
877  if (mission) {
878  MissionElement* selected_elem = 0;
879 
881  while (++elem) {
882  if (elem->IsStatic()) {
883  if (elem->Identity() == index) {
884  selected_elem = elem.value();
885  break;
886  }
887  }
888  }
889 
890  SelectElem(selected_elem);
891 
892  if (selected_elem && regions.size()) {
894  while (++rgn) {
895  if (!_stricmp(selected_elem->Region(), rgn->Name())) {
896  Orbital* elem_region = rgn.value();
897  current_region = regions.index(elem_region);
898  }
899  }
900  }
901  }
902 
903  else {
904  Ship* selship = 0;
905 
906  if (ship) {
907  SimRegion* simrgn = ship->GetRegion();
908  if (simrgn) {
909  ListIter<Ship> s = simrgn->Ships();
910  while (++s) {
911  if (s->IsStatic()) {
912  if (s->Identity() == index) {
913  selship = s.value();
914  break;
915  }
916  }
917  }
918  }
919  }
920 
921  SelectShip(selship);
922 
923  if (selship) {
924  s = selship->GetRegion()->GetOrbitalRegion();
926  }
927  }
928  }
929  break;
930 
931  case SELECT_STARSHIP:
932  {
933  if (mission) {
934  MissionElement* selected_elem = 0;
935 
937  while (++elem) {
938  if (elem->IsStarship()) {
939  if (elem->Identity() == index) {
940  selected_elem = elem.value();
941  break;
942  }
943  }
944  }
945 
946  SelectElem(selected_elem);
947 
948  if (selected_elem && regions.size()) {
950  while (++rgn) {
951  if (!_stricmp(selected_elem->Region(), rgn->Name())) {
952  Orbital* elem_region = rgn.value();
953  current_region = regions.index(elem_region);
954  }
955  }
956  }
957  }
958 
959  else {
960  Ship* selship = 0;
961 
962  if (ship) {
963  SimRegion* simrgn = ship->GetRegion();
964  if (simrgn) {
965  ListIter<Ship> s = simrgn->Ships();
966  while (++s) {
967  if (s->IsStarship()) {
968  if (s->Identity() == index) {
969  selship = s.value();
970  break;
971  }
972  }
973  }
974  }
975  }
976 
977  SelectShip(selship);
978 
979  if (selship) {
980  s = selship->GetRegion()->GetOrbitalRegion();
982  }
983  }
984  }
985  break;
986 
987  case SELECT_FIGHTER:
988  {
989  if (mission) {
990  MissionElement* selected_elem = 0;
991 
993  while (++elem) {
994  if (elem->IsDropship() && !elem->IsSquadron()) {
995  if (elem->Identity() == index) {
996  selected_elem = elem.value();
997  break;
998  }
999  }
1000  }
1001 
1002  SelectElem(selected_elem);
1003 
1004  if (selected_elem && regions.size()) {
1005  ListIter<Orbital> rgn = regions;
1006  while (++rgn) {
1007  if (!_stricmp(selected_elem->Region(), rgn->Name())) {
1008  Orbital* elem_region = rgn.value();
1009  current_region = regions.index(elem_region);
1010  }
1011  }
1012  }
1013  }
1014 
1015  else {
1016  Ship* selship = 0;
1017 
1018  if (ship) {
1019  SimRegion* simrgn = ship->GetRegion();
1020  if (simrgn) {
1021  ListIter<Ship> s = simrgn->Ships();
1022  while (++s) {
1023  if (s->IsDropship()) {
1024  if (s->Identity() == index) {
1025  selship = s.value();
1026  break;
1027  }
1028  }
1029  }
1030  }
1031  }
1032 
1033  SelectShip(selship);
1034 
1035  if (selship) {
1036  s = selship->GetRegion()->GetOrbitalRegion();
1038  }
1039  }
1040  }
1041  break;
1042  }
1043 
1044  SetupScroll(s);
1045 }
1046 
1047 void
1049 {
1050  if (scrolling) return;
1051  Orbital* s = 0;
1052  Ship* selship = 0;
1053 
1054 
1055  switch (seln_mode) {
1056  case SELECT_SYSTEM:
1057  case SELECT_PLANET:
1058  case SELECT_REGION:
1059  default:
1060  break;
1061 
1062  case SELECT_STATION:
1063  case SELECT_STARSHIP:
1064  case SELECT_FIGHTER:
1065  {
1066  if (ship) {
1067  SimRegion* simrgn = ship->GetRegion();
1068 
1069  if (simrgn && simrgn->NumShips()) {
1070  selship = simrgn->Ships().find(ship);
1071  }
1072  }
1073 
1074  SelectShip(selship);
1075  }
1076  break;
1077  }
1078 
1079  if (selship)
1080  SetupScroll(s);
1081 }
1082 
1083 void
1085 {
1086  if (scrolling) return;
1087  Orbital* s = 0;
1088 
1089  switch (seln_mode) {
1090  case SELECT_SYSTEM:
1091  case SELECT_PLANET:
1092  case SELECT_REGION:
1093  default:
1094  break;
1095 
1096  case SELECT_STATION:
1097  case SELECT_STARSHIP:
1098  case SELECT_FIGHTER:
1099  {
1100  SelectElem(elem);
1101  }
1102  break;
1103  }
1104 
1105  if (current_elem)
1106  SetupScroll(s);
1107 }
1108 
1109 void
1111 {
1112  switch (view_mode) {
1113  case VIEW_GALAXY:
1114  zoom = 1;
1115  offset_x = 0;
1116  offset_y = 0;
1117  scrolling = 0;
1118  break;
1119 
1120  case VIEW_SYSTEM:
1121  if (s == 0) {
1122  offset_x = 0;
1123  offset_y = 0;
1124  scrolling = 0;
1125  }
1126  else {
1127  scroll_x = (offset_x + s->Location().x) / 5.0;
1128  scroll_y = (offset_y + s->Location().y) / 5.0;
1129  scrolling = 5;
1130  }
1131  break;
1132 
1133  case VIEW_REGION:
1134  if (current_navpt) {
1135  // don't move the map
1136  scrolling = 0;
1137  }
1138  else if (current_ship) {
1139  Point sloc = current_ship->Location().OtherHand();
1140 
1141  if (!IsVisible(sloc)) {
1142  scroll_x = (offset_x + sloc.x) / 5.0;
1143  scroll_y = (offset_y + sloc.y) / 5.0;
1144  scrolling = 5;
1145  }
1146  else {
1147  scroll_x = 0;
1148  scroll_y = 0;
1149  scrolling = 0;
1150  }
1151  }
1152  else if (current_elem) {
1153  Point sloc = current_elem->Location();
1154 
1155  if (!IsVisible(sloc)) {
1156  scroll_x = (offset_x + sloc.x) / 5.0;
1157  scroll_y = (offset_y + sloc.y) / 5.0;
1158  scrolling = 5;
1159  }
1160  else {
1161  scroll_x = 0;
1162  scroll_y = 0;
1163  scrolling = 0;
1164  }
1165  }
1166  else {
1167  offset_x = 0;
1168  offset_y = 0;
1169  scrolling = 0;
1170  }
1171  break;
1172  }
1173 }
1174 
1175 bool
1177 {
1178  if (view_mode == VIEW_REGION) {
1179  double scale = c/r;
1180  double ox = offset_x * scale;
1181  double oy = offset_y * scale;
1182  double sx = loc.x * scale;
1183  double sy = loc.y * scale;
1184  double cx = rect.w/2;
1185  double cy = rect.h/2;
1186 
1187  int test_x = (int) (cx + sx + ox);
1188  int test_y = (int) (cy + sy + oy);
1189 
1190  bool visible = test_x >= 0 && test_x < rect.w &&
1191  test_y >= 0 && test_y < rect.h;
1192 
1193  return visible;
1194  }
1195 
1196  return false;
1197 }
1198 
1199 // +--------------------------------------------------------------------+
1200 
1201 void
1203 {
1204  if (scrolling || rgn == 0) return;
1205 
1206  int index = regions.index(rgn);
1207 
1208  if (index < 0 || index == current_region || index >= regions.size())
1209  return;
1210 
1211  current_region = index;
1213 
1214  if (!s)
1215  return;
1216 
1217  switch (view_mode) {
1218  case VIEW_GALAXY:
1219  case VIEW_SYSTEM:
1220  scroll_x = (offset_x + s->Location().x) / 5.0;
1221  scroll_y = (offset_y + s->Location().y) / 5.0;
1222  scrolling = 5;
1223  break;
1224 
1225  case VIEW_REGION:
1226  offset_x = 0;
1227  offset_y = 0;
1228  scrolling = 0;
1229  break;
1230  }
1231 }
1232 
1233 // +--------------------------------------------------------------------+
1234 
1235 void
1236 MapView::SetRegionByName(const char* rgn_name)
1237 {
1238  OrbitalRegion* rgn = 0;
1239 
1240  for (int i = 0; i < regions.size(); i++) {
1241  Orbital* r = regions[i];
1242  if (!strcmp(rgn_name, r->Name())) {
1243  rgn = (OrbitalRegion*) r;
1244  break;
1245  }
1246  }
1247 
1248  SetRegion(rgn);
1249 }
1250 
1251 // +--------------------------------------------------------------------+
1252 
1253 void
1254 MapView::SelectAt(int x, int y)
1255 {
1256  if (scrolling) return;
1257  if (c == 0) return;
1258  if (seln_mode < 0) return;
1259 
1260  Orbital* s = 0;
1261 
1262  double scale = r/c;
1263  double cx = rect.w/2;
1264  double cy = rect.h/2;
1265  double test_x = (x - rect.x - cx) * scale - offset_x;
1266  double test_y = (y - rect.y - cy) * scale - offset_y;
1267  double dist = 1.0e20;
1268  int closest = 0;
1269 
1270  if (view_mode == VIEW_GALAXY) {
1271  c = (cx>cy) ? cx : cy;
1272  r = 10;
1273 
1274  Galaxy* g = Galaxy::GetInstance();
1275  if (g)
1276  r = g->Radius();
1277 
1278  StarSystem* closest_system = 0;
1279 
1280  // draw the list of systems, and their connections:
1282  while (++iter) {
1283  StarSystem* s = iter.value();
1284 
1285  double dx = (s->Location().x - test_x);
1286  double dy = (s->Location().y - test_y);
1287  double d = sqrt(dx*dx + dy*dy);
1288 
1289  if (d < dist) {
1290  dist = d;
1291  closest_system = s;
1292  }
1293  }
1294 
1295  if (closest_system)
1296  SetSystem(closest_system);
1297  }
1298 
1299  else if (view_mode == VIEW_SYSTEM) {
1300  switch (seln_mode) {
1301  case SELECT_SYSTEM: {
1302  if (stars.isEmpty()) return;
1303  int index = 0;
1304  ListIter<Orbital> star = stars;
1305  while (++star) {
1306  double dx = (star->Location().x - test_x);
1307  double dy = (star->Location().y - test_y);
1308  double d = sqrt(dx*dx + dy*dy);
1309 
1310  if (d < dist) {
1311  dist = d;
1312  closest = index;
1313  }
1314 
1315  index++;
1316  }
1317 
1318  current_star = closest;
1319  }
1320  s = stars[current_star];
1321  break;
1322 
1323  case SELECT_PLANET: {
1324  if (planets.isEmpty()) return;
1325  int index = 0;
1326  ListIter<Orbital> planet = planets;
1327  while (++planet) {
1328  double dx = (planet->Location().x - test_x);
1329  double dy = (planet->Location().y - test_y);
1330  double d = sqrt(dx*dx + dy*dy);
1331 
1332  if (d < dist) {
1333  dist = d;
1334  closest = index;
1335  }
1336 
1337  index++;
1338  }
1339 
1340  current_planet = closest;
1341  }
1342  s = planets[current_planet];
1343  break;
1344 
1345  default:
1346  case SELECT_REGION: {
1347  if (regions.isEmpty()) return;
1348  int index = 0;
1349  ListIter<Orbital> region = regions;
1350  while (++region) {
1351  double dx = (region->Location().x - test_x);
1352  double dy = (region->Location().y - test_y);
1353  double d = sqrt(dx*dx + dy*dy);
1354 
1355  if (d < dist) {
1356  dist = d;
1357  closest = index;
1358  }
1359 
1360  index++;
1361  }
1362 
1363  current_region = closest;
1364  }
1365  s = regions[current_region];
1366  break;
1367  }
1368  }
1369 
1370  else if (view_mode == VIEW_REGION) {
1371  dist = 5.0e3;
1372 
1373  if (mission) {
1374  Orbital* rgn = regions[current_region];
1375  MissionElement* sel_elem = 0;
1376  Instruction* sel_nav = 0;
1377 
1378  if (!rgn) return;
1379 
1380  // check nav points:
1382  while (++elem) {
1383  MissionElement* e = elem.value();
1384 
1385  if (!e->IsSquadron() && (editor || e->GetIFF() == mission->Team())) {
1386  ListIter<Instruction> navpt = e->NavList();
1387  while (++navpt) {
1388  Instruction* n = navpt.value();
1389 
1390  if (!_stricmp(n->RegionName(), rgn->Name())) {
1391  Point nloc = n->Location();
1392  double dx = nloc.x - test_x;
1393  double dy = nloc.y - test_y;
1394  double d = sqrt(dx*dx + dy*dy);
1395 
1396  if (d < dist) {
1397  dist = d;
1398  sel_nav = n;
1399  sel_elem = e;
1400  }
1401  }
1402  }
1403  }
1404  }
1405 
1406  if (sel_nav) {
1407  SelectElem(sel_elem);
1408  SelectNavpt(sel_nav);
1409  }
1410 
1411  // check elements:
1412  else {
1413  elem.reset();
1414  while (++elem) {
1415  MissionElement* e = elem.value();
1416 
1417  if (e->Region() == rgn->Name() && !e->IsSquadron()) {
1418  Point sloc = e->Location();
1419  double dx = sloc.x - test_x;
1420  double dy = sloc.y - test_y;
1421  double d = sqrt(dx*dx + dy*dy);
1422 
1423  if (d < dist) {
1424  dist = d;
1425  sel_elem = e;
1426  }
1427  }
1428  }
1429 
1430  SelectElem(sel_elem);
1431 
1432  if (sel_elem)
1433  s = rgn;
1434  }
1435  }
1436  else if (ship) {
1437  Sim* sim = Sim::GetSim();
1438  Orbital* rgn = regions[current_region];
1439  SimRegion* simrgn = 0;
1440  Ship* sel_ship = 0;
1441  Instruction* sel_nav = 0;
1442 
1443  if (sim && rgn)
1444  simrgn = sim->FindRegion(rgn->Name());
1445 
1446  // check nav points:
1447  if (simrgn) {
1448  for (int r = 0; r < sim->GetRegions().size(); r++) {
1449  SimRegion* simrgn = sim->GetRegions().at(r);
1450 
1451  for (int i = 0; i < simrgn->Ships().size(); i++) {
1452  Ship* s = simrgn->Ships().at(i);
1453 
1454  if (s->GetIFF() == ship->GetIFF() && s->GetElementIndex() == 1) {
1455  ListIter<Instruction> navpt = s->GetFlightPlan();
1456  while (++navpt) {
1457  Instruction* n = navpt.value();
1458 
1459  if (!_stricmp(n->RegionName(), rgn->Name())) {
1460  Point nloc = n->Location();
1461  double dx = nloc.x - test_x;
1462  double dy = nloc.y - test_y;
1463  double d = sqrt(dx*dx + dy*dy);
1464 
1465  if (d < dist) {
1466  dist = d;
1467  sel_nav = n;
1468  sel_ship = s;
1469  }
1470  }
1471  }
1472  }
1473  }
1474  }
1475  }
1476 
1477  if (sel_nav) {
1478  SelectShip(sel_ship);
1479  SelectNavpt(sel_nav);
1480  }
1481 
1482  // check ships:
1483  else if (simrgn->NumShips()) {
1484  ListIter<Ship> ship = simrgn->Ships();
1485  while (++ship) {
1486  Ship* s = ship.value();
1487 
1488  if (!IsClutter(*s)) {
1489  Point sloc = s->Location().OtherHand();
1490  double dx = sloc.x - test_x;
1491  double dy = sloc.y - test_y;
1492  double d = sqrt(dx*dx + dy*dy);
1493 
1494  if (d < dist) {
1495  dist = d;
1496  sel_ship = s;
1497  }
1498  }
1499  }
1500 
1501  SelectShip(sel_ship);
1502  }
1503  else {
1504  SelectShip(0);
1505  SelectNavpt(0);
1506  }
1507  }
1508  }
1509 
1510  if (s)
1511  SetupScroll(s);
1512 }
1513 
1514 // +--------------------------------------------------------------------+
1515 
1516 Orbital*
1518 {
1519  Orbital* s = 0;
1520 
1521  switch (seln_mode) {
1522  case SELECT_SYSTEM:
1523  if (current_star < stars.size())
1524  s = stars[current_star];
1525  break;
1526 
1527  default:
1528  case SELECT_PLANET:
1529  if (current_planet < planets.size())
1530  s = planets[current_planet];
1531  break;
1532 
1533  case SELECT_REGION:
1534  if (current_region < regions.size())
1535  s = regions[current_region];
1536  break;
1537 
1538  case SELECT_STATION:
1539  case SELECT_STARSHIP:
1540  case SELECT_FIGHTER:
1541  break;
1542  }
1543 
1544  return s;
1545 }
1546 
1547 Ship*
1549 {
1550  return current_ship;
1551 }
1552 
1555 {
1556  return current_elem;
1557 }
1558 
1559 // +--------------------------------------------------------------------+
1560 
1561 int
1563 {
1564  int s = 0;
1565 
1566  switch (seln_mode) {
1567  case SELECT_SYSTEM: s = current_star; break;
1568  default:
1569  case SELECT_PLANET: s = current_planet; break;
1570  case SELECT_REGION: s = current_region; break;
1571 
1572  case SELECT_STATION:
1573  case SELECT_STARSHIP:
1574  case SELECT_FIGHTER:
1575  {
1576  s = -1;
1577  Sim* sim = Sim::GetSim();
1578  Orbital* rgn = regions[current_region];
1579  SimRegion* simrgn = 0;
1580 
1581  if (sim && rgn)
1582  simrgn = sim->FindRegion(rgn->Name());
1583 
1584  if (simrgn) {
1585  if (current_ship && simrgn->NumShips()) {
1586  s = simrgn->Ships().index(current_ship);
1587  }
1588  }
1589  }
1590  break;
1591  }
1592 
1593  return s;
1594 }
1595 
1596 void
1597 MapView::DrawTabbedText(Font* font, const char* text)
1598 {
1599  if (font && text && *text) {
1600  Rect label_rect;
1601 
1602  label_rect.w = rect.w;
1603  label_rect.h = rect.h;
1604 
1605  label_rect.Inset(8,8,8,8);
1606 
1607  DWORD text_flags = DT_WORDBREAK | DT_LEFT;
1608 
1609  active_window->SetFont(font);
1610  active_window->DrawText(text, 0, label_rect, text_flags);
1611  }
1612 }
1613 
1614 // +--------------------------------------------------------------------+
1615 
1616 void
1618 {
1619  rect = window->GetRect();
1620 
1621  if (!system) {
1622  DrawGrid();
1623  DrawTabbedText(title_font, Game::GetText("MapView.item.no-system"));
1624  return;
1625  }
1626 
1627  if (font)
1629 
1630  if (scrolling) {
1631  offset_x -= scroll_x;
1632  offset_y -= scroll_y;
1633  scrolling--;
1634  }
1635 
1636  rect.w -= 2;
1637  rect.h -= 2;
1638 
1639  switch (view_mode) {
1640  case VIEW_GALAXY: DrawGalaxy(); break;
1641  case VIEW_SYSTEM: DrawSystem(); break;
1642  case VIEW_REGION: DrawRegion(); break;
1643  default: DrawGrid(); break;
1644  }
1645 
1646  rect.w += 2;
1647  rect.h += 2;
1648 
1649  if (menu_view) {
1650  if (current_navpt) {
1652  }
1653  else if (current_ship) {
1654  if (current_ship->GetIFF() == ship->GetIFF())
1656  else
1658  }
1659  else if (current_elem) {
1660  if (editor || current_elem->GetIFF() == mission->Team())
1662  else
1664  }
1665  else {
1667  }
1668 
1673 
1674  if (menu_view->GetAction()) {
1676  }
1677 
1678  menu_view->Refresh();
1679  }
1680 
1681  DrawTitle();
1682 }
1683 
1684 // +--------------------------------------------------------------------+
1685 
1686 void
1688 {
1691 }
1692 
1693 // +--------------------------------------------------------------------+
1694 
1695 void
1697 {
1698  title = Game::GetText("MapView.title.Galaxy");
1699  DrawGrid();
1700 
1701  double cx = rect.w/2;
1702  double cy = rect.h/2;
1703 
1704  c = (cx>cy) ? cx : cy;
1705  r = 10; // * zoom;
1706 
1707  Galaxy* g = Galaxy::GetInstance();
1708  if (g)
1709  r = g->Radius(); // * zoom;
1710 
1711  double scale = c/r;
1712  double ox = 0;
1713  double oy = 0;
1714 
1715  // compute offset:
1717  while (++iter) {
1718  StarSystem* s = iter.value();
1719 
1720  if (system == s) {
1721  if (fabs(s->Location().x) > 10 || fabs(s->Location().y) > 10) {
1722  int sx = (int) s->Location().x;
1723  int sy = (int) s->Location().y;
1724 
1725  sx -= sx % 10;
1726  sy -= sy % 10;
1727 
1728  ox = sx * -scale;
1729  oy = sy * -scale;
1730  }
1731  }
1732  }
1733 
1734  // draw the list of systems, and their connections:
1735  iter.reset();
1736  while (++iter) {
1737  StarSystem* s = iter.value();
1738 
1739  int sx = (int) (cx + ox + s->Location().x * scale);
1740  int sy = (int) (cy + oy + s->Location().y * scale);
1741 
1742  if (sx < 4 || sx > rect.w-4 || sy < 4 || sy > rect.h-4)
1743  continue;
1744 
1745  window->DrawEllipse(sx-7, sy-7, sx+7, sy+7, Ship::IFFColor(s->Affiliation()));
1746 
1747  if (s == system) {
1750  }
1751 
1753  while (++iter2) {
1754  StarSystem* s2 = iter2.value();
1755 
1756  if (s != s2 && s->HasLinkTo(s2)) {
1757  int ax = sx;
1758  int ay = sy;
1759 
1760  int bx = (int) (cx + ox + s2->Location().x * scale);
1761  int by = (int) (cy + oy + s2->Location().y * scale);
1762 
1763  if (ax == bx) {
1764  if (ay < by) {
1765  ay += 8; by -= 8;
1766  }
1767  else {
1768  ay -= 8; by += 8;
1769  }
1770  }
1771 
1772  else if (ay == by) {
1773  if (ax < bx) {
1774  ax += 8; bx -= 8;
1775  }
1776  else {
1777  ax -= 8; bx += 8;
1778  }
1779  }
1780 
1781  else {
1782  Point d = Point(bx, by, 0) - Point(ax, ay, 0);
1783  d.Normalize();
1784 
1785  ax += (int) (8 * d.x);
1786  ay += (int) (8 * d.y);
1787 
1788  bx -= (int) (8 * d.x);
1789  by -= (int) (8 * d.y);
1790  }
1791 
1792  window->DrawLine(ax, ay, bx, by, Color(120,120,120), Video::BLEND_ADDITIVE);
1793  }
1794  }
1795  }
1796 
1797  // finally draw all the stars in the galaxy:
1798  if (g) {
1799  ListIter<Star> iter = g->Stars();
1800  while (++iter) {
1801  Star* s = iter.value();
1802 
1803  int sx = (int) (cx + ox + s->Location().x * scale);
1804  int sy = (int) (cy + oy + s->Location().y * scale);
1805  int sr = s->GetSize();
1806 
1807  if (sx < 4 || sx > rect.w-4 || sy < 4 || sy > rect.h-4)
1808  continue;
1809 
1810  window->FillEllipse(sx-sr, sy-sr, sx+sr, sy+sr, s->GetColor());
1811 
1812  if (!strncmp(s->Name(), "GSC", 3))
1813  font->SetColor(Color(100,100,100));
1814  else
1816 
1817  Rect name_rect(sx-60, sy+8, 120, 20);
1819  active_window->DrawText(s->Name(), 0, name_rect, DT_SINGLELINE | DT_CENTER);
1820  }
1821  }
1822 
1824 }
1825 
1826 // +--------------------------------------------------------------------+
1827 
1828 void
1830 {
1831  Text caption = Game::GetText("MapView.title.Starsystem");
1832  caption += " ";
1833  caption += system->Name();
1834 
1835  if (current_ship) {
1836  caption += "\n";
1837  caption += Game::GetText("MapView.title.Ship");
1838  caption += " ";
1839  caption += current_ship->Name();
1840  }
1841  else if (current_elem) {
1842  caption += "\n";
1843  caption += Game::GetText("MapView.title.Ship");
1844  caption += " ";
1845  caption += current_elem->Name();
1846  }
1847 
1848  title = caption;
1849 
1851  while (++star) {
1852  int p_orb = 1;
1853 
1854  ListIter<OrbitalBody> planet = star->Satellites();
1855  while (++planet) {
1856  DrawOrbital(*planet, p_orb++);
1857 
1858  int m_orb = 1;
1859 
1860  ListIter<OrbitalBody> moon = planet->Satellites();
1861  while (++moon) {
1862  DrawOrbital(*moon, m_orb++);
1863 
1864  ListIter<OrbitalRegion> region = moon->Regions();
1865  while (++region) {
1866  DrawOrbital(*region, 1);
1867  }
1868  }
1869 
1870  ListIter<OrbitalRegion> region = planet->Regions();
1871  while (++region) {
1872  DrawOrbital(*region, 1);
1873  }
1874  }
1875 
1876  ListIter<OrbitalRegion> region = star->Regions();
1877  while (++region) {
1878  DrawOrbital(*region, 1);
1879  }
1880 
1881  DrawOrbital(*star, 0);
1882  }
1883 
1884  char r_txt[32];
1885  FormatNumber(r_txt, system->Radius() * zoom);
1886  char resolution[64];
1887  sprintf_s(resolution, "%s: %s", Game::GetText("MapView.info.Resolution").data(), r_txt);
1888 
1890  active_window->DrawText(resolution, -1, Rect(4, 4, rect.w-8, 24), DT_SINGLELINE|DT_RIGHT);
1891 }
1892 
1893 // +--------------------------------------------------------------------+
1894 
1895 void
1897 {
1899 
1900  Text caption = Game::GetText("MapView.title.Sector");
1901  caption += " ";
1902  caption += rgn->Name();
1903 
1904  if (current_ship) {
1905  caption += "\n";
1906  caption += Game::GetText("MapView.title.Ship");
1907  caption += " ";
1908  caption += current_ship->Name();
1909  }
1910  else if (current_elem) {
1911  caption += "\n";
1912  caption += Game::GetText("MapView.title.Ship");
1913  caption += " ";
1914  caption += current_elem->Name();
1915  }
1916 
1917  title = caption;
1918 
1919  double cx = rect.w/2;
1920  double cy = rect.h/2;
1921 
1922  int size = (int) rgn->Radius();
1923  int step = (int) rgn->GridSpace();
1924 
1925  c = (cx<cy) ? cx : cy;
1926  r = rgn->Radius() * zoom;
1927  double scale = c/r;
1928 
1929  double ox = offset_x * scale;
1930  double oy = offset_y * scale;
1931 
1932  int left = (int) (-size * scale + ox + cx);
1933  int right = (int) ( size * scale + ox + cx);
1934  int top = (int) (-size * scale + oy + cy);
1935  int bottom = (int) ( size * scale + oy + cy);
1936 
1937  Color major(48,48,48);
1938  Color minor(24,24,24);
1939 
1940  int x,y;
1941  int tick = 0;
1942 
1943  for (x = 0; x <= size; x += step) {
1944  int lx = (int) (x * scale + ox + cx);
1945  if (!tick)
1946  window->DrawLine(lx, top, lx, bottom, major, Video::BLEND_ADDITIVE);
1947  else
1948  window->DrawLine(lx, top, lx, bottom, minor, Video::BLEND_ADDITIVE);
1949 
1950  lx = (int) (-x * scale + ox + cx);
1951  if (!tick)
1952  window->DrawLine(lx, top, lx, bottom, major, Video::BLEND_ADDITIVE);
1953  else
1954  window->DrawLine(lx, top, lx, bottom, minor, Video::BLEND_ADDITIVE);
1955 
1956  if (++tick > 3) tick = 0;
1957  }
1958 
1959  tick = 0;
1960 
1961  for (y = 0; y <= size; y += step) {
1962  int ly = (int) (y * scale + oy + cy);
1963  if (!tick)
1964  window->DrawLine(left, ly, right, ly, major, Video::BLEND_ADDITIVE);
1965  else
1966  window->DrawLine(left, ly, right, ly, minor, Video::BLEND_ADDITIVE);
1967 
1968  ly = (int) (-y * scale + oy + cy);
1969  if (!tick)
1970  window->DrawLine(left, ly, right, ly, major, Video::BLEND_ADDITIVE);
1971  else
1972  window->DrawLine(left, ly, right, ly, minor, Video::BLEND_ADDITIVE);
1973 
1974  if (++tick > 3) tick = 0;
1975  }
1976 
1977  int rep = 3;
1978  if (r > 70e3) rep = 2;
1979  if (r > 250e3) rep = 1;
1980 
1981  if (campaign && rgn) {
1982  // draw the combatants in this region:
1984  while (++iter) {
1985  Combatant* combatant = iter.value();
1986  DrawCombatGroup(combatant->GetForce(), rep);
1987  }
1988  }
1989 
1990  else if (mission && rgn) {
1991  // draw the elements in this region:
1993  while (++elem)
1994  if (!elem->IsSquadron())
1995  DrawElem(*elem, (elem.value() == current_elem), rep);
1996  }
1997 
1998  else if (ship) {
1999  // draw the ships in this region:
2000  Sim* sim = Sim::GetSim();
2001  SimRegion* simrgn = 0;
2002 
2003  if (sim && rgn)
2004  simrgn = sim->FindRegion(rgn->Name());
2005 
2006  // this algorithm uses the allied track list for the region,
2007  // even if this ship is in a different region. a previous
2008  // version used the ship's own contact list, which only shows
2009  // ships in the player's region. this way is less "realistic"
2010  // but more fun for managing large battles.
2011 
2012  if (simrgn) {
2013  ListIter<Contact> c = simrgn->TrackList(ship->GetIFF());
2014  while (++c) {
2015  Contact* contact = c.value();
2016  Ship* s = contact->GetShip();
2017 
2018  if (s && (s->Class() & ship_filter) && !IsClutter(*s) && s != ship)
2019  DrawShip(*s, (s == current_ship), rep);
2020  }
2021 
2022  ListIter<Ship> s_iter = simrgn->Ships();
2023  while (++s_iter) {
2024  Ship* s = s_iter.value();
2025 
2026  if (s && (s->IsStatic()) && !IsClutter(*s) &&
2027  (s->GetIFF() == ship->GetIFF() || s->GetIFF() == 0))
2028  DrawShip(*s, (s == current_ship), rep);
2029  }
2030 
2031  // draw nav routes for allied ships not in the region:
2032  ListIter<SimRegion> r_iter = sim->GetRegions();
2033  while (++r_iter) {
2034  SimRegion* r = r_iter.value();
2035 
2036  if (r != simrgn) {
2037  ListIter<Ship> s_iter = r->Ships();
2038  while (++s_iter) {
2039  Ship* s = s_iter.value();
2040 
2041  if (s && !s->IsStatic() && !IsClutter(*s) &&
2042  (s->GetIFF() == ship->GetIFF() || s->GetIFF() == 0)) {
2043  DrawNavRoute(simrgn->GetOrbitalRegion(),
2044  s->GetFlightPlan(),
2045  s->MarkerColor(),
2046  s, 0);
2047  }
2048  }
2049  }
2050  }
2051  }
2052 
2053  // draw our own ship:
2054  DrawShip(*ship, (ship == current_ship), rep);
2055  }
2056 
2057  char r_txt[32];
2058  FormatNumber(r_txt, r*2);
2059  char resolution[64];
2060  sprintf_s(resolution, "%s: %s", Game::GetText("MapView.info.Resolution").data(), r_txt);
2061 
2063  active_window->DrawText(resolution, -1, Rect(4, 4, rect.w-8, 24), DT_SINGLELINE|DT_RIGHT);
2064 }
2065 
2066 // +--------------------------------------------------------------------+
2067 
2068 void
2070 {
2071  int grid_step = rect.w/8;
2072  int cx = rect.w/2;
2073  int cy = rect.h/2;
2074 
2075  Color c(32,32,32);
2076 
2077  window->DrawLine(0, cy, rect.w, cy, c, Video::BLEND_ADDITIVE);
2078  window->DrawLine(cx, 0, cx, rect.h, c, Video::BLEND_ADDITIVE);
2079 
2080  for (int i = 1; i < 4; i++) {
2081  window->DrawLine(0, cy + (i*grid_step), rect.w, cy + (i*grid_step), c, Video::BLEND_ADDITIVE);
2082  window->DrawLine(0, cy - (i*grid_step), rect.w, cy - (i*grid_step), c, Video::BLEND_ADDITIVE);
2083  window->DrawLine(cx + (i*grid_step), 0, cx + (i*grid_step), rect.h, c, Video::BLEND_ADDITIVE);
2084  window->DrawLine(cx - (i*grid_step), 0, cx - (i*grid_step), rect.h, c, Video::BLEND_ADDITIVE);
2085  }
2086 }
2087 
2088 // +--------------------------------------------------------------------+
2089 
2090 void
2092 {
2093  int type = body.Type();
2094 
2095  if (type == Orbital::NOTHING)
2096  return;
2097 
2098  int x1, y1, x2, y2;
2099  Rect label_rect;
2100  int label_w = 64;
2101  int label_h = 18;
2102 
2103  double cx = rect.w/2;
2104  double cy = rect.h/2;
2105 
2106  c = (cx<cy) ? cx : cy;
2107  r = system->Radius() * zoom;
2108 
2109  if ((r > 300e9) && (type > Orbital::PLANET))
2110  return;
2111 
2112  double xscale = cx / r;
2113  double yscale = cy / r * 0.75;
2114 
2115  double ox = offset_x * xscale;
2116  double oy = offset_y * yscale;
2117 
2118  double bo_x = body.Orbit() * xscale;
2119  double bo_y = body.Orbit() * yscale;
2120  double br = body.Radius() * yscale;
2121  double bx = body.Location().x * xscale;
2122  double by = body.Location().y * yscale;
2123 
2124  double px = 0;
2125  double py = 0;
2126 
2127  if (body.Primary()) {
2128  double min_pr = GetMinRadius(body.Primary()->Type());
2129 
2130  if (index) {
2131  if (min_pr < 4)
2132  min_pr = 4;
2133 
2134  min_pr *= (index+1);
2135  }
2136 
2137  double min_x = min_pr * xscale / yscale;
2138  double min_y = min_pr;
2139 
2140  if (bo_x < min_x)
2141  bo_x = min_x;
2142 
2143  if (bo_y < min_y)
2144  bo_y = min_y;
2145 
2146  px = body.Primary()->Location().x * xscale;
2147  py = body.Primary()->Location().y * yscale;
2148  }
2149 
2150  if (type == Orbital::TERRAIN)
2151  bo_x = bo_y;
2152 
2153  int ipx = (int) (cx + px + ox);
2154  int ipy = (int) (cy + py + oy);
2155  int ibo_x = (int) bo_x;
2156  int ibo_y = (int) bo_y;
2157 
2158  x1 = ipx - ibo_x;
2159  y1 = ipy - ibo_y;
2160  x2 = ipx + ibo_x;
2161  y2 = ipy + ibo_y;
2162 
2163  if (type != Orbital::TERRAIN) {
2164  double a = x2-x1;
2165  double b = rect.w*32;
2166 
2167  if (a < b)
2168  window->DrawEllipse(x1, y1, x2, y2, Color(64,64,64), Video::BLEND_ADDITIVE);
2169  }
2170 
2171  // show body's location on possibly magnified orbit
2172  bx = px + bo_x * cos(body.Phase());
2173  by = py + bo_y * sin(body.Phase());
2174 
2175  double min_br = GetMinRadius(type);
2176  if (br < min_br) br = min_br;
2177 
2178  Color color;
2179 
2180  switch (type) {
2181  case Orbital::STAR: color = Color(248, 248, 128); break;
2182  case Orbital::PLANET: color = Color( 64, 64, 192); break;
2183  case Orbital::MOON: color = Color( 32, 192, 96); break;
2184  case Orbital::REGION: color = Color(255, 255, 255); break;
2185  case Orbital::TERRAIN: color = Color( 16, 128, 48); break;
2186  }
2187 
2188  int icx = (int) (cx + bx + ox);
2189  int icy = (int) (cy + by + oy);
2190  int ibr = (int) br;
2191 
2192  x1 = icx - ibr;
2193  y1 = icy - ibr;
2194  x2 = icx + ibr;
2195  y2 = icy + ibr;
2196 
2197  if (type < Orbital::REGION) {
2198  if (body.GetMapIcon().Width() > 64) {
2199  Bitmap* map_icon = (Bitmap*) &body.GetMapIcon();
2200 
2201  if (type == Orbital::STAR)
2202  window->DrawBitmap(x1,y1,x2,y2, map_icon, Video::BLEND_ADDITIVE);
2203  else
2204  window->DrawBitmap(x1,y1,x2,y2, map_icon, Video::BLEND_ALPHA);
2205  }
2206  else {
2207  window->FillEllipse(x1, y1, x2, y2, color);
2208  }
2209  }
2210  else {
2211  window->DrawRect(x1, y1, x2, y2, color);
2212 
2213  if (campaign) {
2215  while (++iter) {
2216  Combatant* combatant = iter.value();
2217 
2218  if (ibr >= 4 || combatant->GetIFF() == 1)
2219  DrawCombatantSystem(combatant, &body, icx, icy, ibr);
2220  }
2221  }
2222  }
2223 
2224  if (type == Orbital::STAR || bo_y > label_h) {
2225  label_rect.x = x1 - label_w + (int) br;
2226  label_rect.y = y1 - label_h;
2227  label_rect.w = label_w * 2;
2228  label_rect.h = label_h;
2229 
2231  active_window->DrawText(body.Name(), -1, label_rect, DT_SINGLELINE|DT_CENTER);
2232  }
2233 }
2234 
2235 // +--------------------------------------------------------------------+
2236 
2237 double
2239 {
2240  switch (type) {
2241  case Orbital::STAR: return 8;
2242  case Orbital::PLANET: return 4;
2243  case Orbital::MOON: return 2;
2244  case Orbital::REGION: return 2;
2245  }
2246 
2247  return 0;
2248 }
2249 
2250 // +--------------------------------------------------------------------+
2251 
2252 static void
2253 ColorizeBitmap(Bitmap& img, Color color)
2254 {
2255  int w = img.Width();
2256  int h = img.Height();
2257 
2258  for (int y = 0; y < h; y++) {
2259  for (int x = 0; x < w; x++) {
2260  Color c = img.GetColor(x, y);
2261 
2262  if (c != Color::Black && c != Color::White) {
2263  img.SetColor(x,y,color.ShadeColor(c.Blue()/2));
2264  }
2265  }
2266  }
2267 
2268  img.AutoMask();
2269 }
2270 
2271 static POINT shipshape1[] = { {6,0}, {-6,4}, {-6,-4} };
2272 static POINT shipshape2[] = { {8,0}, { 4,4}, {-8,4}, {-8,-4}, {4,-4} };
2273 static POINT shipshape3[] = { {8,8}, {-8,8}, {-8,-8}, {8,-8} };
2274 
2275 void
2276 MapView::DrawShip(Ship& s, bool current, int rep)
2277 {
2279  if (!rgn) return;
2280 
2281  int x1, y1, x2, y2;
2282  POINT shiploc;
2283  Point sloc = s.Location().OtherHand();
2284 
2285  double cx = rect.w/2;
2286  double cy = rect.h/2;
2287 
2288  c = (cx<cy) ? cx : cy;
2289  r = rgn->Radius() * zoom;
2290 
2291  double scale = c/r;
2292 
2293  double ox = offset_x * scale;
2294  double oy = offset_y * scale;
2295 
2296  double rlx = 0;
2297  double rly = 0;
2298 
2299  int sprite_width = 10;
2300 
2301  window->SetFont(font);
2302 
2303  // draw ship icon:
2304  if (rep && view_mode == VIEW_REGION && rgn == s.GetRegion()->GetOrbitalRegion()) {
2305  double sx = (sloc.x + rlx) * scale;
2306  double sy = (sloc.y + rly) * scale;
2307 
2308  shiploc.x = (int) (cx + sx + ox);
2309  shiploc.y = (int) (cy + sy + oy);
2310 
2311  bool ship_visible = shiploc.x >= 0 && shiploc.x < rect.w &&
2312  shiploc.y >= 0 && shiploc.y < rect.h;
2313 
2314  if (ship_visible) {
2315  if (rep < 3) {
2316  window->FillRect(shiploc.x-2, shiploc.y-2, shiploc.x+2, shiploc.y+2, s.MarkerColor());
2317  sprite_width = 2;
2318 
2319  if (&s == ship || !IsCrowded(s))
2320  window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, s.Name());
2321  }
2322  else {
2323  Point heading = s.Heading().OtherHand();
2324  heading.z = 0;
2325  heading.Normalize();
2326 
2327  double theta = 0;
2328 
2329  if (heading.y > 0)
2330  theta = acos(heading.x);
2331  else
2332  theta = -acos(heading.x);
2333 
2334  const double THETA_SLICE = 4 / PI;
2335  const double THETA_OFFSET = PI + THETA_SLICE/2;
2336 
2337  int sprite_index = (int) ((theta + THETA_OFFSET) * THETA_SLICE);
2338  int nsprites = s.Design()->map_sprites.size();
2339 
2340  if (nsprites) {
2341  if (sprite_index < 0 || sprite_index >= nsprites)
2342  sprite_index = sprite_index % nsprites;
2343 
2344  Bitmap* map_sprite = s.Design()->map_sprites[sprite_index];
2345 
2346  Bitmap bmp;
2347  bmp.CopyBitmap(*map_sprite);
2348  ColorizeBitmap(bmp, s.MarkerColor());
2349  sprite_width = bmp.Width()/2;
2350  int h = bmp.Height()/2;
2351 
2352  window->DrawBitmap(shiploc.x-sprite_width,
2353  shiploc.y-h,
2354  shiploc.x+sprite_width,
2355  shiploc.y+h,
2356  &bmp,
2358  }
2359 
2360  else {
2361  theta -= PI/2;
2362 
2363  if (s.IsStatic()) {
2364  window->FillRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, s.MarkerColor());
2365  window->DrawRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, Color::White);
2366  }
2367  else if (s.IsStarship()) {
2368  window->FillRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, s.MarkerColor());
2369  window->DrawRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, Color::White);
2370  }
2371  else {
2372  window->FillRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, s.MarkerColor());
2373  window->DrawRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, Color::White);
2374  }
2375  }
2376 
2377  window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, s.Name());
2378  }
2379  }
2380  }
2381 
2382  // draw nav route:
2383  // draw current ship marker:
2384  if (current && Text(s.GetRegion()->Name()) == regions[current_region]->Name()) {
2385  x1 = (int) (shiploc.x - sprite_width - 1);
2386  x2 = (int) (shiploc.x + sprite_width + 1);
2387  y1 = (int) (shiploc.y - sprite_width - 1);
2388  y2 = (int) (shiploc.y + sprite_width + 1);
2389 
2390  window->DrawRect(x1, y1, x2, y2, Color::White);
2391  }
2392 
2393  // only see routes for your own team:
2394  if (s.GetIFF() == 0 || ship && s.GetIFF() == ship->GetIFF()) {
2395  DrawNavRoute(rgn, s.GetFlightPlan(), s.MarkerColor(), &s, 0);
2396  }
2397 }
2398 
2399 void
2400 MapView::DrawElem(MissionElement& s, bool current, int rep)
2401 {
2402  if (!mission) return;
2403 
2404  bool visible = editor ||
2405  s.GetIFF() == 0 ||
2406  s.GetIFF() == mission->Team() ||
2407  s.IntelLevel() > Intel::KNOWN;
2408 
2409  if (!visible) return;
2410 
2412 
2413  if (!rgn) return;
2414 
2415  int x1, y1, x2, y2;
2416  POINT shiploc;
2417 
2418  double cx = rect.w/2;
2419  double cy = rect.h/2;
2420 
2421  c = (cx<cy) ? cx : cy;
2422  r = rgn->Radius() * zoom;
2423 
2424  double scale = c/r;
2425 
2426  double ox = offset_x * scale;
2427  double oy = offset_y * scale;
2428 
2429  double rlx = 0;
2430  double rly = 0;
2431 
2432  int sprite_width = 10;
2433 
2434  window->SetFont(font);
2435 
2436  // draw ship icon:
2437  if (!_stricmp(s.Region(), rgn->Name())) {
2438  double sx = (s.Location().x + rlx) * scale;
2439  double sy = (s.Location().y + rly) * scale;
2440 
2441  shiploc.x = (int) (cx + sx + ox);
2442  shiploc.y = (int) (cy + sy + oy);
2443 
2444  bool ship_visible = shiploc.x >= 0 && shiploc.x < rect.w &&
2445  shiploc.y >= 0 && shiploc.y < rect.h;
2446 
2447  if (ship_visible) {
2448  if (rep < 3) {
2449  window->FillRect(shiploc.x-2, shiploc.y-2, shiploc.x+2, shiploc.y+2, s.MarkerColor());
2450  sprite_width = 2;
2451 
2452  if (!IsCrowded(s))
2453  window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, s.Name());
2454  }
2455  else {
2456  double theta = s.Heading();
2457 
2458  const double THETA_SLICE = 4 / PI;
2459  const double THETA_OFFSET = PI / 2;
2460 
2461  int sprite_index = (int) ((theta + THETA_OFFSET) * THETA_SLICE);
2462  int nsprites = 0;
2463 
2464  if (s.GetDesign())
2465  nsprites = s.GetDesign()->map_sprites.size();
2466 
2467  if (nsprites > 0) {
2468  if (sprite_index < 0 || sprite_index >= nsprites)
2469  sprite_index = sprite_index % nsprites;
2470 
2471  Bitmap* map_sprite = s.GetDesign()->map_sprites[sprite_index];
2472 
2473  Bitmap bmp;
2474  bmp.CopyBitmap(*map_sprite);
2475  ColorizeBitmap(bmp, s.MarkerColor());
2476  sprite_width = bmp.Width()/2;
2477  int h = bmp.Height()/2;
2478 
2479  window->DrawBitmap(shiploc.x-sprite_width,
2480  shiploc.y-h,
2481  shiploc.x+sprite_width,
2482  shiploc.y+h,
2483  &bmp,
2485  }
2486 
2487  else {
2488  theta -= PI/2;
2489 
2490  if (s.IsStatic()) {
2491  window->FillRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, s.MarkerColor());
2492  window->DrawRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, Color::White);
2493  }
2494  else if (s.IsStarship()) {
2495  window->FillRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, s.MarkerColor());
2496  window->DrawRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, Color::White);
2497  }
2498  else {
2499  window->FillRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, s.MarkerColor());
2500  window->DrawRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, Color::White);
2501  }
2502  }
2503 
2504  char label[64];
2505 
2506  if (s.Count() > 1)
2507  sprintf_s(label, "%s x %d", (const char*) s.Name(), s.Count());
2508  else
2509  strcpy_s(label, (const char*) s.Name());
2510 
2511  window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, label);
2512  }
2513  }
2514  }
2515 
2516  // draw nav route:
2517  // draw current ship marker:
2518  if (current && s.Region() == regions[current_region]->Name()) {
2519  x1 = (int) (shiploc.x - sprite_width - 1);
2520  x2 = (int) (shiploc.x + sprite_width + 1);
2521  y1 = (int) (shiploc.y - sprite_width - 1);
2522  y2 = (int) (shiploc.y + sprite_width + 1);
2523 
2524  window->DrawRect(x1, y1, x2, y2, Color::White);
2525  }
2526 
2527  // only see routes for your own team:
2528  if (editor || s.GetIFF() == 0 || mission && s.GetIFF() == mission->Team()) {
2529  DrawNavRoute(rgn, s.NavList(), s.MarkerColor(), 0, &s);
2530  }
2531 }
2532 
2533 void
2535 List<Instruction>& s_route,
2536 Color s_marker,
2537 Ship* ship,
2538 MissionElement* elem)
2539 {
2540  int x1, y1, x2, y2;
2541  double cx = rect.w/2;
2542  double cy = rect.h/2;
2543 
2544  c = (cx<cy) ? cx : cy;
2545  r = system->Radius() * zoom;
2546 
2547  if (view_mode == VIEW_REGION) {
2548  if (!rgn) return;
2549  r = rgn->Radius() * zoom;
2550  }
2551 
2552  double scale = c/r;
2553  double ox = offset_x * scale;
2554  double oy = offset_y * scale;
2555 
2556  Point old_loc;
2557  double old_x = 0;
2558  double old_y = 0;
2559  bool old_in = false;
2560 
2561  Point first_loc;
2562  int first_x = 0;
2563  int first_y = 0;
2564  bool first_in = false;
2565 
2566  bool draw_route = true;
2567  bool draw_bold = false;
2568 
2569  if (ship && ship->GetElementIndex() > 1)
2570  draw_route = false;
2571 
2572  if (ship && ship == current_ship) {
2573  s_marker = s_marker * 1.5;
2574  draw_bold = true;
2575  }
2576 
2577  else if (elem && elem == current_elem) {
2578  s_marker = s_marker * 1.5;
2579  draw_bold = true;
2580  }
2581 
2582  for (int i = 0; i < s_route.size(); i++) {
2583  Instruction* navpt = s_route[i];
2584 
2585  if (!_stricmp(navpt->RegionName(), rgn->Name())) {
2586  double nav_x = navpt->Location().x * scale;
2587  double nav_y = navpt->Location().y * scale;
2588 
2589  int isx = (int) (cx + nav_x + ox);
2590  int isy = (int) (cy + nav_y + oy);
2591 
2592  if (old_in && draw_route) {
2593  int iox = (int) (cx + old_x + ox);
2594  int ioy = (int) (cy + old_y + oy);
2595  window->DrawLine(iox, ioy, isx, isy, s_marker);
2596 
2597  int x1 = (iox-isx);
2598  int y1 = (ioy-isy);
2599 
2600  if (draw_bold) {
2601  if (x1 > y1) {
2602  window->DrawLine(iox, ioy+1, isx, isy+1, s_marker);
2603  }
2604  else {
2605  window->DrawLine(iox+1, ioy, isx+1, isy, s_marker);
2606  }
2607  }
2608 
2609  if ((x1*x1 + y1*y1) > 2000) {
2610  double dist = Point(navpt->Location() - old_loc).length();
2611 
2612  int imx = (int) (cx + (old_x+nav_x)/2 + ox);
2613  int imy = (int) (cy + (old_y+nav_y)/2 + oy);
2614 
2615  char dist_txt[32];
2616  FormatNumber(dist_txt, dist);
2618  window->SetFont(font);
2619  window->Print(imx-20, imy-6, dist_txt);
2621  }
2622  }
2623 
2624  x1 = isx - 3;
2625  y1 = isy - 3;
2626  x2 = isx + 3;
2627  y2 = isy + 3;
2628 
2629  Color c = Color::White;
2630  if (navpt->Status() > Instruction::ACTIVE) {
2631  c = Color::Gray;
2632  }
2633  else if (!first_in) {
2634  first_in = true;
2635  first_loc = navpt->Location();
2636  first_x = isx;
2637  first_y = isy;
2638  }
2639 
2640  if (draw_route) {
2641  window->DrawLine(x1, y1, x2, y2, c);
2642  window->DrawLine(x1, y2, x2, y1, c);
2643 
2644  if (navpt == current_navpt)
2645  window->DrawRect(x1-2, y1-2, x2+2, y2+2, c);
2646 
2647  char buf[256];
2648  sprintf_s(buf, "%d", i+1);
2649  window->SetFont(font);
2650  window->Print(x2+3, y1, buf);
2651 
2652  if (navpt == current_navpt) {
2653  if (navpt->TargetName() && strlen(navpt->TargetName())) {
2654  sprintf_s(buf, "%s %s", Game::GetText(Text("MapView.item.") + Instruction::ActionName(navpt->Action())).data(), navpt->TargetName());
2655  window->Print(x2+3, y1+10, buf);
2656  }
2657  else {
2658  sprintf_s(buf, "%s", Game::GetText(Text("MapView.item.") + Instruction::ActionName(navpt->Action())).data());
2659  window->Print(x2+3, y1+10, buf);
2660  }
2661 
2662  sprintf_s(buf, "%s", Game::GetText(Text("MapView.item.") + Instruction::FormationName(navpt->Formation())).data());
2663  window->Print(x2+3, y1+20, buf);
2664 
2665  sprintf_s(buf, "%d", navpt->Speed());
2666  window->Print(x2+3, y1+30, buf);
2667 
2668  if (navpt->HoldTime()) {
2669  char hold_time[32];
2670  FormatTime(hold_time, navpt->HoldTime());
2671 
2672  sprintf_s(buf, "%s %s", Game::GetText("MapView.item.Hold").data(), hold_time);
2673  window->Print(x2+3, y1+40, buf);
2674  }
2675  }
2676  }
2677 
2678  old_loc = navpt->Location();
2679  old_x = nav_x;
2680  old_y = nav_y;
2681  old_in = true;
2682  }
2683 
2684  else {
2685  old_loc = navpt->Location();
2686  old_x = 0;
2687  old_y = 0;
2688  old_in = false;
2689  }
2690  }
2691 
2692  // if the ship and the first active navpoint are both in the region,
2693  // draw a line from the ship to the first active navpoint:
2694 
2695  if (first_in) {
2696  old_in = false;
2697 
2698  if (ship && ship->GetRegion()) {
2699  old_in = (ship->GetRegion()->GetOrbitalRegion() == rgn);
2700 
2701  if (old_in) {
2702  old_loc = ship->Location().OtherHand();
2703  old_x = old_loc.x * scale;
2704  old_y = old_loc.y * scale;
2705  }
2706  }
2707 
2708  else if (elem) {
2709  old_in = (elem->Region() == rgn->Name()) ? true : false;
2710 
2711  if (old_in) {
2712  old_loc = elem->Location();
2713  old_x = old_loc.x * scale;
2714  old_y = old_loc.y * scale;
2715  }
2716  }
2717 
2718  if (old_in) {
2719  int iox = (int) (cx + old_x + ox);
2720  int ioy = (int) (cy + old_y + oy);
2721  window->DrawLine(iox, ioy, first_x, first_y, s_marker);
2722 
2723  int x1 = (iox-first_x);
2724  int y1 = (ioy-first_y);
2725 
2726  if (draw_bold) {
2727  if (x1 > y1) {
2728  window->DrawLine(iox, ioy+1, first_x, first_y+1, s_marker);
2729  }
2730  else {
2731  window->DrawLine(iox+1, ioy, first_x+1, first_y, s_marker);
2732  }
2733  }
2734 
2735  if ((x1*x1 + y1*y1) > 2000) {
2736  double dist = Point(first_loc - old_loc).length();
2737  double nav_x = first_loc.x * scale;
2738  double nav_y = first_loc.y * scale;
2739 
2740  int imx = (int) (cx + (old_x+nav_x)/2 + ox);
2741  int imy = (int) (cy + (old_y+nav_y)/2 + oy);
2742 
2743  char dist_txt[32];
2744  FormatNumber(dist_txt, dist);
2746  window->SetFont(font);
2747  window->Print(imx-20, imy-6, dist_txt);
2749  }
2750  }
2751  }
2752 }
2753 
2754 // +--------------------------------------------------------------------+
2755 
2756 void
2757 MapView::DrawCombatantSystem(Combatant* c, Orbital* rgn, int x, int y, int r)
2758 {
2759  int team = c->GetIFF();
2760  int x1 = 0;
2761  int x2 = 0;
2762  int y1 = y - r;
2763  int a = 0;
2764 
2765  switch (team) {
2766  case 0: x1 = x - 64;
2767  x2 = x + 64;
2768  y1 = y + r + 4;
2769  a = DT_CENTER;
2770  break;
2771 
2772  case 1: x1 = x - 200;
2773  x2 = x - r - 4;
2774  a = DT_RIGHT;
2775  break;
2776 
2777  default: x1 = x + r + 4;
2778  x2 = x + 200;
2779  a = DT_LEFT;
2780  break;
2781  }
2782 
2783  DrawCombatGroupSystem(c->GetForce(), rgn, x1, x2, y1, a);
2784 }
2785 
2786 // +--------------------------------------------------------------------+
2787 
2788 void
2789 MapView::DrawCombatGroupSystem(CombatGroup* group, Orbital* rgn, int x1, int x2, int& y, int a)
2790 {
2791  if (!group || group->IsReserve() || group->CalcValue() < 1)
2792  return;
2793 
2794  char txt[80];
2795 
2796  if (group->GetRegion() == rgn->Name()) {
2797  switch (group->Type()) {
2801  sprintf_s(txt, "%s '%s'", group->GetShortDescription(), group->Name().data());
2803  active_window->DrawText(txt, 0, Rect(x1, y, x2-x1, 12), a);
2804  y += 10;
2805  break;
2806 
2808  case CombatGroup::STATION:
2809  case CombatGroup::STARBASE:
2810 
2812  case CombatGroup::BATTERY:
2813  case CombatGroup::MISSILE:
2814 
2816  active_window->DrawText(group->GetShortDescription(), 0, Rect(x1, y, x2-x1, 12), a);
2817  y += 10;
2818  break;
2819 
2820  default:
2821  break;
2822  }
2823  }
2824 
2825  ListIter<CombatGroup> iter = group->GetComponents();
2826  while (++iter) {
2827  CombatGroup* g = iter.value();
2828  DrawCombatGroupSystem(g, rgn, x1, x2, y, a);
2829  }
2830 }
2831 
2832 // +--------------------------------------------------------------------+
2833 
2834 void
2836 {
2837  // does group even exist yet?
2838  if (!group || group->IsReserve() || group->CalcValue() < 1)
2839  return;
2840 
2841  // is group a squadron? don't draw squadrons on map:
2842  if (group->Type() >= CombatGroup::WING && group->Type() < CombatGroup::FLEET)
2843  return;
2844 
2845  // has group been discovered yet?
2846  CombatGroup* player_group = campaign->GetPlayerGroup();
2847  if (group->GetIFF() && player_group && player_group->GetIFF() != group->GetIFF())
2848  if (group->IntelLevel() <= Intel::KNOWN)
2849  return;
2850 
2851  // has group been destroyed already?
2852  if (group->CalcValue() < 1)
2853  return;
2854 
2856  if (!rgn) return;
2857 
2858  POINT shiploc;
2859 
2860  double cx = rect.w/2;
2861  double cy = rect.h/2;
2862 
2863  c = (cx<cy) ? cx : cy;
2864  r = rgn->Radius() * zoom;
2865 
2866  double scale = c/r;
2867 
2868  double ox = offset_x * scale;
2869  double oy = offset_y * scale;
2870 
2871  double rlx = 0;
2872  double rly = 0;
2873 
2874  int sprite_width = 10;
2875 
2876  if (group->GetUnits().size() > 0) {
2877  CombatUnit* unit = 0;
2878 
2879  for (int i = 0; i < group->GetUnits().size(); i++) {
2880  unit = group->GetUnits().at(i);
2881 
2882  if (unit->Count() - unit->DeadCount() > 0)
2883  break;
2884  }
2885 
2886  // draw unit icon:
2887  if (unit->GetRegion() == rgn->Name() && unit->Type() > Ship::LCA && unit->Count() > 0) {
2888  double sx = (unit->Location().x + rlx) * scale;
2889  double sy = (unit->Location().y + rly) * scale;
2890 
2891  shiploc.x = (int) (cx + sx + ox);
2892  shiploc.y = (int) (cy + sy + oy);
2893 
2894  bool ship_visible = shiploc.x >= 0 && shiploc.x < rect.w &&
2895  shiploc.y >= 0 && shiploc.y < rect.h;
2896 
2897  if (ship_visible) {
2898  if (rep < 3) {
2899  window->FillRect(shiploc.x-2, shiploc.y-2, shiploc.x+2, shiploc.y+2, unit->MarkerColor());
2900  sprite_width = 2;
2901 
2902  char buf[256];
2903  sprintf_s(buf, "%s", unit->Name().data());
2904  window->SetFont(font);
2905  window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, buf);
2906  }
2907  else {
2908  int sprite_index = 2;
2909  int nsprites = 0;
2910 
2911  if (unit->GetDesign())
2912  nsprites = unit->GetDesign()->map_sprites.size();
2913 
2914  if (nsprites) {
2915  if (sprite_index < 0 || sprite_index >= nsprites)
2916  sprite_index = sprite_index % nsprites;
2917 
2918  Bitmap* map_sprite = unit->GetDesign()->map_sprites[sprite_index];
2919 
2920  Bitmap bmp;
2921  bmp.CopyBitmap(*map_sprite);
2922  ColorizeBitmap(bmp, unit->MarkerColor());
2923  sprite_width = bmp.Width()/2;
2924  int h = bmp.Height()/2;
2925 
2926  window->DrawBitmap(shiploc.x-sprite_width,
2927  shiploc.y-h,
2928  shiploc.x+sprite_width,
2929  shiploc.y+h,
2930  &bmp,
2932  }
2933 
2934  else {
2935  if (unit->IsStatic()) {
2936  window->FillRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, unit->MarkerColor());
2937  window->DrawRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, Color::White);
2938  }
2939  else if (unit->IsStarship()) {
2940  window->FillRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, unit->MarkerColor());
2941  window->DrawRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, Color::White);
2942  }
2943  else {
2944  window->FillRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, unit->MarkerColor());
2945  window->DrawRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, Color::White);
2946  }
2947  }
2948 
2949  char label[128];
2950  strcpy_s(label, unit->GetDescription());
2951  window->SetFont(font);
2952  window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, label);
2953  }
2954  }
2955  }
2956  }
2957 
2958  // recurse
2959  ListIter<CombatGroup> iter = group->GetComponents();
2960  while (++iter) {
2961  CombatGroup* g = iter.value();
2962  DrawCombatGroup(g, rep);
2963  }
2964 }
2965 
2966 // +--------------------------------------------------------------------+
2967 
2968 bool
2970 {
2971  // get leader:
2972  Ship* lead = test.GetLeader();
2973 
2974  if (lead == &test) // this is the leader:
2975  return false;
2976 
2977  // too close?
2978  if (lead) {
2979  POINT testloc, leadloc;
2980 
2981  GetShipLoc(test, testloc);
2982  GetShipLoc(*lead, leadloc);
2983 
2984  double dx = testloc.x - leadloc.x;
2985  double dy = testloc.y - leadloc.y;
2986  double d = dx*dx + dy*dy;
2987 
2988  if (d <= 64)
2989  return true;
2990  }
2991 
2992  return false;
2993 }
2994 
2995 // +--------------------------------------------------------------------+
2996 
2997 bool
2999 {
3000  POINT testloc, refloc;
3001  Sim* sim = Sim::GetSim();
3002  Orbital* rgn = regions[current_region];
3003  SimRegion* simrgn = sim->FindRegion(rgn->Name());
3004 
3005  if (simrgn) {
3006  GetShipLoc(test, testloc);
3007 
3008  ListIter<Ship> s = simrgn->Ships();
3009  while (++s) {
3010  Ship* ref = s.value();
3011 
3012  // too close?
3013  if (ref && ref != &test) {
3014  GetShipLoc(*ref, refloc);
3015 
3016  double dx = testloc.x - refloc.x;
3017  double dy = testloc.y - refloc.y;
3018  double d = dx*dx + dy*dy;
3019 
3020  if (d <= 64)
3021  return true;
3022  }
3023  }
3024  }
3025 
3026  return false;
3027 }
3028 
3029 void
3030 MapView::GetShipLoc(Ship& s, POINT& shiploc)
3031 {
3032  double cx = rect.w/2;
3033  double cy = rect.h/2;
3034 
3035  c = (cx<cy) ? cx : cy;
3036  r = system->Radius() * zoom;
3037 
3039 
3040  if (view_mode == VIEW_REGION) {
3041  if (!rgn) return;
3042  r = rgn->Radius() * zoom;
3043  }
3044 
3045  double scale = c/r;
3046 
3047  double ox = offset_x * scale;
3048  double oy = offset_y * scale;
3049 
3050  double rlx = 0;
3051  double rly = 0;
3052 
3053  if (view_mode == VIEW_SYSTEM) {
3054  rgn = system->ActiveRegion();
3055 
3056  if (rgn) {
3057  rlx = rgn->Location().x;
3058  rly = rgn->Location().y;
3059  }
3060  }
3061 
3062  if (view_mode == VIEW_SYSTEM ||
3063  (view_mode == VIEW_REGION && rgn == s.GetRegion()->GetOrbitalRegion())) {
3064  double sx = (s.Location().x + rlx) * scale;
3065  double sy = (s.Location().y + rly) * scale;
3066 
3067  shiploc.x = (int) (cx + sx + ox);
3068  shiploc.y = (int) (cy + sy + oy);
3069  }
3070  else {
3071  shiploc.x = -1;
3072  shiploc.y = -1;
3073  }
3074 }
3075 
3076 // +--------------------------------------------------------------------+
3077 
3078 bool
3080 {
3081  POINT testloc, refloc;
3082  Sim* sim = Sim::GetSim();
3083  Orbital* rgn = regions[current_region];
3084 
3085  if (mission) {
3086  GetElemLoc(test, testloc);
3087 
3089  while (++s) {
3090  MissionElement* ref = s.value();
3091 
3092  if (ref && ref != &test && !_stricmp(ref->Region(), rgn->Name())) {
3093  GetElemLoc(*ref, refloc);
3094 
3095  double dx = testloc.x - refloc.x;
3096  double dy = testloc.y - refloc.y;
3097  double d = dx*dx + dy*dy;
3098 
3099  if (d <= 64)
3100  return true;
3101  }
3102  }
3103  }
3104 
3105  return false;
3106 }
3107 
3108 void
3110 {
3111  double cx = rect.w/2;
3112  double cy = rect.h/2;
3113 
3114  c = (cx<cy) ? cx : cy;
3115  r = system->Radius() * zoom;
3116 
3118 
3119  if (view_mode == VIEW_REGION) {
3120  if (!rgn) return;
3121  r = rgn->Radius() * zoom;
3122  }
3123 
3124  double scale = c/r;
3125 
3126  double ox = offset_x * scale;
3127  double oy = offset_y * scale;
3128 
3129  double rlx = 0;
3130  double rly = 0;
3131 
3132  if (view_mode == VIEW_SYSTEM) {
3133  rgn = system->ActiveRegion();
3134 
3135  if (rgn) {
3136  rlx = rgn->Location().x;
3137  rly = rgn->Location().y;
3138  }
3139  }
3140 
3141  if (view_mode == VIEW_SYSTEM ||
3142  (view_mode == VIEW_REGION && !_stricmp(s.Region(), rgn->Name()))) {
3143  double sx = (s.Location().x + rlx) * scale;
3144  double sy = (s.Location().y + rly) * scale;
3145 
3146  shiploc.x = (int) (cx + sx + ox);
3147  shiploc.y = (int) (cy + sy + oy);
3148  }
3149  else {
3150  shiploc.x = -1;
3151  shiploc.y = -1;
3152  }
3153 }
3154 
3155 // +--------------------------------------------------------------------+
3156 
3159 {
3160  OrbitalRegion* result = 0;
3161 
3162  if (current_region < regions.size())
3163  result = (OrbitalRegion*) regions[current_region];
3164 
3165  return result;
3166 }
3167 
3168 // +--------------------------------------------------------------------+
3169 
3170 void
3172 {
3173  zoom *= 0.9;
3174 
3175  if (view_mode == VIEW_SYSTEM) {
3176  if (system && zoom * system->Radius() < 2e6) {
3177  zoom = 2e6 / system->Radius();
3178  }
3179  }
3180  else if (view_mode == VIEW_REGION) {
3181  OrbitalRegion* rgn = GetRegion();
3182  if (rgn && zoom * rgn->Radius() < 1e3) {
3183  zoom = 1e3 / rgn->Radius();
3184  }
3185  }
3186 }
3187 
3188 void
3190 {
3191  zoom *= 1.1;
3192 
3193  if (view_mode == VIEW_SYSTEM) {
3194  if (system && zoom * system->Radius() > 500e9) {
3195  zoom = 500e9 / system->Radius();
3196  }
3197  }
3198  else if (view_mode == VIEW_REGION) {
3199  OrbitalRegion* rgn = GetRegion();
3200  if (rgn && zoom * rgn->Radius() > 1e6) {
3201  zoom = 1e6 / rgn->Radius();
3202  }
3203  }
3204 }
3205 
3206 // +--------------------------------------------------------------------+
3207 
3208 void
3210 {
3212  if (dispatch)
3213  dispatch->Register(this);
3214 }
3215 
3216 void
3218 {
3220  if (dispatch)
3221  dispatch->Unregister(this);
3222 
3223  if (captured) {
3224  ReleaseCapture();
3225  captured = false;
3226  Mouse::Show(true);
3227  }
3228 
3229  dragging = false;
3230 }
3231 
3232 // +--------------------------------------------------------------------+
3233 
3234 bool
3236 {
3237  if (active_window)
3238  return active_window->IsEnabled();
3239 
3240  return false;
3241 }
3242 
3243 bool
3245 {
3246  if (active_window)
3247  return active_window->IsVisible();
3248 
3249  return false;
3250 }
3251 
3252 bool
3254 {
3255  if (active_window)
3256  return active_window->IsFormActive();
3257 
3258  return false;
3259 }
3260 
3261 Rect
3263 {
3264  if (active_window)
3265  return active_window->TargetRect();
3266 
3267  return Rect();
3268 }
3269 
3270 // +--------------------------------------------------------------------+
3271 
3272 int
3274 {
3275  if (captured) {
3276  EventTarget* test = 0;
3278  if (dispatch)
3279  test = dispatch->GetCapture();
3280 
3281  if (test != this) {
3282  captured = false;
3283  Mouse::Show(true);
3284  }
3285 
3286  else {
3287  if (dragging) {
3288  int delta_x = x - mouse_x;
3289  int delta_y = y - mouse_y;
3290 
3291  offset_x += delta_x * r / c;
3292  offset_y += delta_y * r / c;
3293 
3294  Mouse::SetCursorPos(mouse_x, mouse_y);
3295  }
3296 
3297  else if (view_mode == VIEW_REGION) {
3298  double scale = r/c;
3299  click_x = (x - rect.x - rect.w/2) * scale - offset_x;
3300  click_y = (y - rect.y - rect.h/2) * scale - offset_y;
3301 
3302  if ((adding_navpt || moving_navpt) && current_navpt) {
3303  Point loc = current_navpt->Location();
3304  loc.x = click_x;
3305  loc.y = click_y;
3306  current_navpt->SetLocation(loc);
3308  }
3309 
3310  else if (editor && moving_elem && current_elem) {
3311  Point loc = current_elem->Location();
3312  loc.x = click_x;
3313  loc.y = click_y;
3314  current_elem->SetLocation(loc);
3315  }
3316  }
3317  }
3318  }
3319 
3320  return active_window->OnMouseMove(x,y);
3321 }
3322 
3323 // +--------------------------------------------------------------------+
3324 
3325 int
3327 {
3328  if (!captured)
3329  captured = SetCapture();
3330 
3331  if (captured) {
3332  dragging = true;
3333  mouse_x = x;
3334  mouse_y = y;
3335  Mouse::Show(false);
3336  }
3337 
3338  return active_window->OnRButtonDown(x, y);
3339 }
3340 
3341 // +--------------------------------------------------------------------+
3342 
3343 int
3345 {
3346  if (captured) {
3347  ReleaseCapture();
3348  captured = false;
3349  Mouse::Show(true);
3350  }
3351 
3352  dragging = false;
3353 
3354  return active_window->OnRButtonUp(x, y);
3355 }
3356 
3357 // +--------------------------------------------------------------------+
3358 
3360 {
3361  return active_window->OnClick();
3362 }
3363 
3364 int MapView::OnLButtonDown(int x, int y)
3365 {
3366  if (menu_view && menu_view->IsShown()) {
3367  // ignore this event...
3368  }
3369  else {
3370  if (!captured)
3371  captured = SetCapture();
3372 
3373  if (view_mode == VIEW_REGION) {
3374  double scale = r/c;
3375  click_x = (x - rect.x - rect.w/2) * scale - offset_x;
3376  click_y = (y - rect.y - rect.h/2) * scale - offset_y;
3377 
3378  if (current_navpt) {
3379  Point nloc = current_navpt->Location();
3380  double dx = nloc.x - click_x;
3381  double dy = nloc.y - click_y;
3382  double d = sqrt(dx*dx + dy*dy);
3383 
3384  if (d < 5e3) {
3385  moving_navpt = true;
3386 
3387  if (ship && current_ship && ship != current_ship) {
3388  if (ship->GetElement() && current_ship->GetElement()) {
3390  moving_navpt = false;
3391  }
3392  }
3393  }
3394  else if (current_elem && NetLobby::GetInstance()) {
3395  moving_navpt = false;
3396  }
3397  }
3398  }
3399 
3400  else if (editor && current_elem) {
3401  Point nloc = current_elem->Location();
3402  double dx = nloc.x - click_x;
3403  double dy = nloc.y - click_y;
3404  double d = sqrt(dx*dx + dy*dy);
3405 
3406  if (d < 5e3) {
3407  moving_elem = true;
3408 
3410  moving_elem = false;
3411  }
3412  }
3413  }
3414  }
3415  }
3416 
3417  return active_window->OnLButtonDown(x,y);
3418 }
3419 
3420 int MapView::OnLButtonUp(int x, int y)
3421 {
3422  bool process_event = false;
3423 
3424  if (captured) {
3425  process_event = true;
3426  ReleaseCapture();
3427  captured = false;
3428  Mouse::Show(true);
3429  }
3430 
3431  if (process_event && !adding_navpt) {
3432  if (!moving_navpt && !moving_elem) {
3434  }
3435 
3436  if (view_mode == VIEW_REGION) {
3437  double scale = r/c;
3438  click_x = (x - rect.x - rect.w/2) * scale - offset_x;
3439  click_y = (y - rect.y - rect.h/2) * scale - offset_y;
3440 
3441  if (!scrolling)
3442  SelectAt(x,y);
3443 
3445  }
3446 
3447  else if (!scrolling) {
3448  SelectAt(x,y);
3449 
3451  }
3452  }
3453 
3454  if ((adding_navpt || moving_navpt) && current_navpt) {
3456 
3457  Sim* sim = Sim::GetSim();
3458  if (sim) {
3459  Ship* s = current_ship;
3460 
3461  if (s && s->GetElement()) {
3462  Element* elem = s->GetElement();
3463  int index = elem->GetNavIndex(current_navpt);
3464 
3465  if (index >= 0)
3466  NetUtil::SendNavData(false, elem, index-1, current_navpt);
3467  }
3468  }
3469  }
3470 
3471  adding_navpt = false;
3472  moving_navpt = false;
3473  moving_elem = false;
3474 
3475  return active_window->OnLButtonUp(x,y);
3476 }
3477 
3478