/* Starshatter: The Open Source Project Copyright (c) 2021-2024, Starshatter: The Open Source Project Contributors Copyright (c) 2011-2012, Starshatter OpenSource Distribution Contributors Copyright (c) 1997-2006, Destroyer Studios LLC. AUTHOR: John DiCamillo OVERVIEW ======== Star Map class */ #include "MapView.h" #include "Galaxy.h" #include "StarSystem.h" #include "Ship.h" #include "ShipDesign.h" #include "Instruction.h" #include "Element.h" #include "NavAI.h" #include "Weapon.h" #include "Sim.h" #include "Mission.h" #include "Campaign.h" #include "Combatant.h" #include "CombatGroup.h" #include "CombatUnit.h" #include "Contact.h" #include "MenuView.h" #include "NetLobby.h" #include "NetUtil.h" #include "Game.h" #include "ContentBundle.h" #include "UIEventDispatch.h" #include "UIEventTarget.h" #include "Video.h" #include "Button.h" #include "Bitmap.h" #include "Font.h" #include "FontMgr.h" #include "Mouse.h" #include "FormatUtil.h" #include "Menu.h" // +--------------------------------------------------------------------+ // Supported Selection Modes: const int SELECT_NONE = -1; const int SELECT_SYSTEM = 0; const int SELECT_PLANET = 1; const int SELECT_REGION = 2; const int SELECT_STATION = 3; const int SELECT_STARSHIP = 4; const int SELECT_FIGHTER = 5; const int SELECT_NAVPT = 6; const int VIEW_GALAXY = 0; const int VIEW_SYSTEM = 1; const int VIEW_REGION = 2; // +--------------------------------------------------------------------+ MapView::MapView(Window* win) : View(win) , system(0), zoom(1.1), offset_x(0), offset_y(0), ship(0), campaign(0) , captured(false), dragging(false), adding_navpt(false) , moving_navpt(false), moving_elem(false) , view_mode(VIEW_SYSTEM), seln_mode(SELECT_REGION), ship_filter(0xffffffff) , current_star(0), current_planet(0), current_region(0) , current_ship(0), current_elem(0), current_navpt(0), mission(0) , scrolling(0), scroll_x(0), scroll_y(0), click_x(0), click_y(0) , active_menu(0), map_menu(0), map_system_menu(0), map_sector_menu(0) , ship_menu(0), editor(false) , nav_menu(0), action_menu(0), objective_menu(0), formation_menu(0), speed_menu(0) , hold_menu(0), farcast_menu(0), menu_view(0) { for (int i = 0; i < 3; i++) { view_zoom[i] = zoom; view_offset_x[i] = offset_x; view_offset_y[i] = offset_y; } menu_view = new MenuView(window); title_font = FontMgr::Find("Limerick12"); font = FontMgr::Find("Verdana"); active_window = (ActiveWindow*) window; if (active_window) active_window->AddView(this); } // +--------------------------------------------------------------------+ MapView::~MapView() { ClearMenu(); galaxy_image.ClearImage(); delete menu_view; } // +--------------------------------------------------------------------+ void MapView::OnWindowMove() { if (menu_view) menu_view->OnWindowMove(); } // +--------------------------------------------------------------------+ void MapView::SetGalaxy(List& g) { system_list.clear(); system_list.append(g); if (system_list.size() > 0) { SetSystem(system_list[0]); } } void MapView::SetSystem(StarSystem* s) { if (system != s) { system = s; // forget invalid selection: current_star = 0; current_planet = 0; current_region = 0; current_ship = 0; current_elem = 0; current_navpt = 0; // flush old object pointers: stars.clear(); planets.clear(); regions.clear(); // insert objects from star system: if (system) { ListIter star = system->Bodies(); while (++star) { switch (star->Type()) { case Orbital::STAR: stars.append(star.value()); break; case Orbital::PLANET: case Orbital::MOON: planets.append(star.value()); break; } } ListIter planet = star->Satellites(); while (++planet) { planets.append(planet.value()); ListIter moon = planet->Satellites(); while (++moon) { planets.append(moon.value()); } } ListIter rgn = system->AllRegions(); while (++rgn) regions.append(rgn.value()); // sort region list by distance from the star: regions.sort(); } BuildMenu(); } } // +--------------------------------------------------------------------+ void MapView::SetShip(Ship* s) { if (ship != s) { ship = s; // forget invalid selection: current_star = 0; current_planet = 0; current_region = 0; current_ship = 0; current_elem = 0; current_navpt = 0; if (ship && system_list.size() > 0) { SimRegion* rgn = ship->GetRegion(); if (rgn && rgn->System()) { system = 0; SetSystem(rgn->System()); } } BuildMenu(); } } // +--------------------------------------------------------------------+ void MapView::SetMission(Mission* m) { if (mission != m) { mission = m; // forget invalid selection: current_star = 0; current_planet = 0; current_region = 0; current_ship = 0; current_elem = 0; current_navpt = 0; if (mission && system_list.size() > 0) { system = 0; SetSystem(mission->GetStarSystem()); } BuildMenu(); } } // +--------------------------------------------------------------------+ void MapView::SetCampaign(Campaign* c) { if (campaign != c) { campaign = c; // forget invalid selection: current_star = 0; current_planet = 0; current_region = 0; current_ship = 0; current_elem = 0; current_navpt = 0; if (campaign) SetGalaxy(campaign->GetSystemList()); } } // +--------------------------------------------------------------------+ enum MapView_MENU { MAP_SYSTEM = 1000, MAP_SECTOR = 2000, MAP_SHIP = 3000, MAP_NAV = 4000, MAP_ADDNAV = 4001, MAP_DELETE = 4002, MAP_CLEAR = 4003, MAP_ACTION = 5000, MAP_FORMATION = 6000, MAP_SPEED = 7000, MAP_HOLD = 8000, MAP_FARCAST = 8500, MAP_OBJECTIVE = 9000 }; void MapView::BuildMenu() { ClearMenu(); map_system_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.STARSYSTEM")); if (system_list.size() > 0) { int i = 0; ListIter iter = system_list; while (++iter) { StarSystem* s = iter.value(); map_system_menu->AddItem(s->Name(), MAP_SYSTEM + i); i++; } } else if (system) { map_system_menu->AddItem(system->Name(), MAP_SYSTEM); } map_sector_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.SECTOR")); for (int i = 0; i < regions.size(); i++) { Orbital* rgn = regions[i]; map_sector_menu->AddItem(rgn->Name(), MAP_SECTOR + i); } map_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.MAP")); map_menu->AddMenu("System", map_system_menu); map_menu->AddMenu("Sector", map_sector_menu); if (ship || mission) { ship_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.SHIP")); ship_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Starsystem"), map_system_menu); ship_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Sector"), map_sector_menu); ship_menu->AddItem("", 0); ship_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.Add-Nav"), MAP_ADDNAV); ship_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.Clear-All"), MAP_CLEAR); action_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.ACTION")); for (int i = 0; i < Instruction::NUM_ACTIONS; i++) { action_menu->AddItem(ContentBundle::GetInstance()->GetText(Text("MapView.item.") + Instruction::ActionName(i)), MAP_ACTION + i); } formation_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.FORMATION")); for (int i = 0; i < Instruction::NUM_FORMATIONS; i++) { formation_menu->AddItem(ContentBundle::GetInstance()->GetText(Text("MapView.item.") + Instruction::FormationName(i)), MAP_FORMATION + i); } speed_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.SPEED")); speed_menu->AddItem("250", MAP_SPEED + 0); speed_menu->AddItem("500", MAP_SPEED + 1); speed_menu->AddItem("750", MAP_SPEED + 2); speed_menu->AddItem("1000", MAP_SPEED + 3); hold_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.HOLD")); hold_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.None"), MAP_HOLD + 0); hold_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.1-Minute"), MAP_HOLD + 1); hold_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.5-Minutes"), MAP_HOLD + 2); hold_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.10-Minutes"), MAP_HOLD + 3); hold_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.15-Minutes"), MAP_HOLD + 4); farcast_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.FARCAST")); farcast_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.Use-Quantum"), MAP_FARCAST + 0); farcast_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.Use-Farcast"), MAP_FARCAST + 1); objective_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.OBJECTIVE")); nav_menu = new Menu(ContentBundle::GetInstance()->GetText("MapView.menu.NAVPT")); nav_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Action"), action_menu); nav_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Objective"), objective_menu); nav_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Formation"), formation_menu); nav_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Speed"), speed_menu); nav_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Hold"), hold_menu); nav_menu->AddMenu(ContentBundle::GetInstance()->GetText("MapView.item.Farcast"), farcast_menu); nav_menu->AddItem("", 0); nav_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.Add-Nav"), MAP_ADDNAV); nav_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.Del-Nav"), MAP_DELETE); } else if (campaign) { ship_menu = 0; speed_menu = 0; hold_menu = 0; farcast_menu = 0; objective_menu = 0; formation_menu = 0; nav_menu = 0; } active_menu = map_menu; } // +--------------------------------------------------------------------+ void MapView::ClearMenu() { delete map_menu; delete map_system_menu; delete map_sector_menu; delete ship_menu; delete nav_menu; delete action_menu; delete objective_menu; delete formation_menu; delete speed_menu; delete hold_menu; delete farcast_menu; map_menu = 0; map_system_menu = 0; map_sector_menu = 0; ship_menu = 0; nav_menu = 0; action_menu = 0; objective_menu = 0; formation_menu = 0; speed_menu = 0; hold_menu = 0; farcast_menu = 0; } // +--------------------------------------------------------------------+ void MapView::ProcessMenuItem(int action) { bool send_nav_data = false; bool can_command = true; if (ship && current_ship && ship != current_ship) { if (ship->GetElement() && current_ship->GetElement()) { if (!ship->GetElement()->CanCommand(current_ship->GetElement())) { can_command = false; } } } else if (current_elem && NetLobby::GetInstance()) { can_command = false; } if (action >= MAP_OBJECTIVE) { int index = action - MAP_OBJECTIVE; if (current_navpt && can_command) { current_navpt->SetTarget(objective_menu->GetItem(index)->GetText()); send_nav_data = true; } } else if (action >= MAP_FARCAST) { if (current_navpt && can_command) { current_navpt->SetFarcast(action - MAP_FARCAST); send_nav_data = true; } } else if (action >= MAP_HOLD) { int hold_time = 0; switch (action) { default: case MAP_HOLD + 0: hold_time = 0; break; case MAP_HOLD + 1: hold_time = 60; break; case MAP_HOLD + 2: hold_time = 300; break; case MAP_HOLD + 3: hold_time = 600; break; case MAP_HOLD + 4: hold_time = 900; break; } if (current_navpt && can_command) { current_navpt->SetHoldTime(hold_time); send_nav_data = true; } } else if (action >= MAP_SPEED) { if (current_navpt && can_command) { current_navpt->SetSpeed((action - MAP_SPEED + 1) * 250); send_nav_data = true; } } else if (action >= MAP_FORMATION) { if (current_navpt && can_command) { current_navpt->SetFormation(action - MAP_FORMATION); send_nav_data = true; } } else if (action >= MAP_ACTION) { if (current_navpt && can_command) { current_navpt->SetAction(action - MAP_ACTION); SelectNavpt(current_navpt); send_nav_data = true; } } else if (action == MAP_ADDNAV) { Text rgn_name = regions[current_region]->Name(); Instruction* prior = current_navpt; Instruction* n = 0; if (current_ship && can_command) { Sim* sim = Sim::GetSim(); SimRegion* rgn = sim->FindRegion(rgn_name); Point init_pt; if (rgn) { if (rgn->IsAirSpace()) init_pt.z = 10e3; n = new Instruction(rgn, init_pt); } else { n = new Instruction(rgn_name, init_pt); } n->SetSpeed(500); if (prior) { n->SetAction(prior->Action()); n->SetFormation(prior->Formation()); n->SetSpeed(prior->Speed()); n->SetTarget(prior->GetTarget()); } current_ship->AddNavPoint(n, prior); } else if (current_elem && can_command) { Point init_pt; if (regions[current_region]->Type() == Orbital::TERRAIN) init_pt.z = 10e3; n = new Instruction(rgn_name, init_pt); n->SetSpeed(500); if (prior) { n->SetAction(prior->Action()); n->SetFormation(prior->Formation()); n->SetSpeed(prior->Speed()); n->SetTarget(prior->GetTarget()); } current_elem->AddNavPoint(n, prior); } if (can_command) { current_navpt = n; current_status = Instruction::PENDING; adding_navpt = true; captured = SetCapture(); } } else if (action == MAP_DELETE) { if (current_navpt && can_command) { if (current_ship) current_ship->DelNavPoint(current_navpt); else if (current_elem && can_command) current_elem->DelNavPoint(current_navpt); SelectNavpt(0); } } else if (action == MAP_CLEAR) { if (current_ship && can_command) current_ship->ClearFlightPlan(); else if (current_elem && can_command) current_elem->ClearFlightPlan(); SelectNavpt(0); } else if (action >= MAP_NAV) { } else if (action >= MAP_SHIP) { } else if (action >= MAP_SECTOR) { int index = action - MAP_SECTOR; if (index < regions.size()) current_region = index; if (view_mode == VIEW_SYSTEM) { Orbital* s = regions[current_region]; SetupScroll(s); } } else if (system_list.size() > 0 && action >= MAP_SYSTEM) { int index = action - MAP_SYSTEM; if (index < system_list.size()) SetSystem(system_list[index]); } else { } Sim* sim = Sim::GetSim(); if (send_nav_data && sim) { Ship* s = current_ship; if (s && s->GetElement()) { Element* elem = s->GetElement(); int index = elem->GetNavIndex(current_navpt); if (index >= 0) NetUtil::SendNavData(false, elem, index-1, current_navpt); } } } // +--------------------------------------------------------------------+ bool MapView::SetCapture() { UIEventDispatch* dispatch = UIEventDispatch::GetInstance(); if (dispatch) return dispatch->CaptureMouse(this) ? true : false; return 0; } // +--------------------------------------------------------------------+ bool MapView::ReleaseCapture() { UIEventDispatch* dispatch = UIEventDispatch::GetInstance(); if (dispatch) return dispatch->ReleaseMouse(this) ? true : false; return 0; } // +--------------------------------------------------------------------+ void MapView::SetViewMode(int mode) { if (mode >= 0 && mode < 3) { // save state: view_zoom[view_mode] = zoom; view_offset_x[view_mode] = offset_x; view_offset_y[view_mode] = offset_y; // switch mode: view_mode = mode; // restore state: if (view_mode == VIEW_GALAXY) { zoom = 1; offset_x = 0; offset_y = 0; } else { zoom = view_zoom[view_mode]; offset_x = view_offset_x[view_mode]; offset_y = view_offset_y[view_mode]; } scrolling = 0; scroll_x = 0; scroll_y = 0; } } // +--------------------------------------------------------------------+ bool MapView::Update(SimObject* obj) { if (obj == current_ship) { current_ship = 0; active_menu = map_menu; } return SimObserver::Update(obj); } // +--------------------------------------------------------------------+ void MapView::SelectShip(Ship* selship) { if (selship != current_ship) { current_ship = selship; if (current_ship) { if (current_ship->Life() == 0 || current_ship->IsDying() || current_ship->IsDead()) { current_ship = 0; } else { Observe(current_ship); } } } SelectNavpt(0); } // +--------------------------------------------------------------------+ void MapView::SelectElem(MissionElement* elem) { if (elem != current_elem) { current_elem = elem; if (current_elem) { if (current_elem->IsStarship()) { ship_menu->GetItem(3)->SetEnabled(true); } else if (current_elem->IsDropship()) { ship_menu->GetItem(3)->SetEnabled(true); } else { ship_menu->GetItem(3)->SetEnabled(false); } } } SelectNavpt(0); } // +--------------------------------------------------------------------+ void MapView::SelectNavpt(Instruction* navpt) { current_navpt = navpt; if (current_navpt) { current_status = current_navpt->Status(); List ships; objective_menu->ClearItems(); switch (current_navpt->Action()) { case Instruction::VECTOR: case Instruction::LAUNCH: case Instruction::PATROL: case Instruction::SWEEP: case Instruction::RECON: objective_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.not-available"), 0); objective_menu->GetItem(0)->SetEnabled(false); break; case Instruction::DOCK: FindShips(true, true, true, false, ships); break; case Instruction::DEFEND: FindShips(true, true, true, false, ships); break; case Instruction::ESCORT: FindShips(true, false, true, true, ships); break; case Instruction::INTERCEPT: FindShips(false, false, false, true, ships); break; case Instruction::ASSAULT: FindShips(false, false, true, false, ships); break; case Instruction::STRIKE: FindShips(false, true, false, false, ships); break; } for (int i = 0; i < ships.size(); i++) objective_menu->AddItem(ships[i]->data(), MAP_OBJECTIVE + i); ships.destroy(); } else { objective_menu->ClearItems(); objective_menu->AddItem(ContentBundle::GetInstance()->GetText("MapView.item.not-available"), 0); objective_menu->GetItem(0)->SetEnabled(false); } } // +--------------------------------------------------------------------+ void MapView::FindShips(bool friendly, bool station, bool starship, bool dropship, List& result) { if (mission) { for (int i = 0; i < mission->GetElements().size(); i++) { MissionElement* elem = mission->GetElements().at(i); if (elem->IsSquadron()) continue; if (!station && elem->IsStatic()) continue; if (!starship && elem->IsStarship()) continue; if (!dropship && elem->IsDropship()) continue; if (!editor && friendly && elem->GetIFF() > 0 && elem->GetIFF() != mission->Team()) continue; if (!editor && !friendly && (elem->GetIFF() == 0 || elem->GetIFF() == mission->Team())) continue; result.append(new Text(elem->Name())); } } else if (ship) { Sim* sim = Sim::GetSim(); if (sim) { for (int r = 0; r < sim->GetRegions().size(); r++) { SimRegion* rgn = sim->GetRegions().at(r); for (int i = 0; i < rgn->Ships().size(); i++) { Ship* s = rgn->Ships().at(i); if (!station && s->IsStatic()) continue; if (!starship && s->IsStarship()) continue; if (!dropship && s->IsDropship()) continue; if (friendly && s->GetIFF() > 0 && s->GetIFF() != ship->GetIFF()) continue; if (!friendly && (s->GetIFF() == 0 || s->GetIFF() == ship->GetIFF())) continue; result.append(new Text(s->Name())); } } } } } // +--------------------------------------------------------------------+ void MapView::SetSelectionMode(int mode) { if (mode <= SELECT_NONE) { seln_mode = SELECT_NONE; return; } if (mode != seln_mode && mode <= SELECT_FIGHTER) { seln_mode = mode; // when changing mode, // select the item closest to the current center: if (system && view_mode == VIEW_SYSTEM) SelectAt(rect.x + rect.w/2, rect.y + rect.h/2); } } void MapView::SetSelection(int index) { if (scrolling) return; Orbital* s = 0; switch (seln_mode) { case SELECT_SYSTEM: if (index < system_list.size()) SetSystem(system_list[index]); s = stars[current_star]; break; default: case SELECT_PLANET: if (index < planets.size()) current_planet = index; s = planets[current_planet]; break; case SELECT_REGION: if (index < regions.size()) current_region = index; s = regions[current_region]; break; case SELECT_STATION: { if (mission) { MissionElement* selected_elem = 0; ListIter elem = mission->GetElements(); while (++elem) { if (elem->IsStatic()) { if (elem->Identity() == index) { selected_elem = elem.value(); break; } } } SelectElem(selected_elem); if (selected_elem && regions.size()) { ListIter rgn = regions; while (++rgn) { if (!_stricmp(selected_elem->Region(), rgn->Name())) { Orbital* elem_region = rgn.value(); current_region = regions.index(elem_region); } } } } else { Ship* selship = 0; if (ship) { SimRegion* simrgn = ship->GetRegion(); if (simrgn) { ListIter s = simrgn->Ships(); while (++s) { if (s->IsStatic()) { if (s->Identity() == index) { selship = s.value(); break; } } } } } SelectShip(selship); if (selship) { s = selship->GetRegion()->GetOrbitalRegion(); current_region = regions.index(s); } } } break; case SELECT_STARSHIP: { if (mission) { MissionElement* selected_elem = 0; ListIter elem = mission->GetElements(); while (++elem) { if (elem->IsStarship()) { if (elem->Identity() == index) { selected_elem = elem.value(); break; } } } SelectElem(selected_elem); if (selected_elem && regions.size()) { ListIter rgn = regions; while (++rgn) { if (!_stricmp(selected_elem->Region(), rgn->Name())) { Orbital* elem_region = rgn.value(); current_region = regions.index(elem_region); } } } } else { Ship* selship = 0; if (ship) { SimRegion* simrgn = ship->GetRegion(); if (simrgn) { ListIter s = simrgn->Ships(); while (++s) { if (s->IsStarship()) { if (s->Identity() == index) { selship = s.value(); break; } } } } } SelectShip(selship); if (selship) { s = selship->GetRegion()->GetOrbitalRegion(); current_region = regions.index(s); } } } break; case SELECT_FIGHTER: { if (mission) { MissionElement* selected_elem = 0; ListIter elem = mission->GetElements(); while (++elem) { if (elem->IsDropship() && !elem->IsSquadron()) { if (elem->Identity() == index) { selected_elem = elem.value(); break; } } } SelectElem(selected_elem); if (selected_elem && regions.size()) { ListIter rgn = regions; while (++rgn) { if (!_stricmp(selected_elem->Region(), rgn->Name())) { Orbital* elem_region = rgn.value(); current_region = regions.index(elem_region); } } } } else { Ship* selship = 0; if (ship) { SimRegion* simrgn = ship->GetRegion(); if (simrgn) { ListIter s = simrgn->Ships(); while (++s) { if (s->IsDropship()) { if (s->Identity() == index) { selship = s.value(); break; } } } } } SelectShip(selship); if (selship) { s = selship->GetRegion()->GetOrbitalRegion(); current_region = regions.index(s); } } } break; } SetupScroll(s); } void MapView::SetSelectedShip(Ship* ship) { if (scrolling) return; Orbital* s = 0; Ship* selship = 0; switch (seln_mode) { case SELECT_SYSTEM: case SELECT_PLANET: case SELECT_REGION: default: break; case SELECT_STATION: case SELECT_STARSHIP: case SELECT_FIGHTER: { if (ship) { SimRegion* simrgn = ship->GetRegion(); if (simrgn && simrgn->NumShips()) { selship = simrgn->Ships().find(ship); } } SelectShip(selship); } break; } if (selship) SetupScroll(s); } void MapView::SetSelectedElem(MissionElement* elem) { if (scrolling) return; Orbital* s = 0; switch (seln_mode) { case SELECT_SYSTEM: case SELECT_PLANET: case SELECT_REGION: default: break; case SELECT_STATION: case SELECT_STARSHIP: case SELECT_FIGHTER: { SelectElem(elem); } break; } if (current_elem) SetupScroll(s); } void MapView::SetupScroll(Orbital* s) { switch (view_mode) { case VIEW_GALAXY: zoom = 1; offset_x = 0; offset_y = 0; scrolling = 0; break; case VIEW_SYSTEM: if (s == 0) { offset_x = 0; offset_y = 0; scrolling = 0; } else { scroll_x = (offset_x + s->Location().x) / 5.0; scroll_y = (offset_y + s->Location().y) / 5.0; scrolling = 5; } break; case VIEW_REGION: if (current_navpt) { // don't move the map scrolling = 0; } else if (current_ship) { Point sloc = current_ship->Location().OtherHand(); if (!IsVisible(sloc)) { scroll_x = (offset_x + sloc.x) / 5.0; scroll_y = (offset_y + sloc.y) / 5.0; scrolling = 5; } else { scroll_x = 0; scroll_y = 0; scrolling = 0; } } else if (current_elem) { Point sloc = current_elem->Location(); if (!IsVisible(sloc)) { scroll_x = (offset_x + sloc.x) / 5.0; scroll_y = (offset_y + sloc.y) / 5.0; scrolling = 5; } else { scroll_x = 0; scroll_y = 0; scrolling = 0; } } else { offset_x = 0; offset_y = 0; scrolling = 0; } break; } } bool MapView::IsVisible(const Point& loc) { if (view_mode == VIEW_REGION) { double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; double sx = loc.x * scale; double sy = loc.y * scale; double cx = rect.w/2; double cy = rect.h/2; int test_x = (int) (cx + sx + ox); int test_y = (int) (cy + sy + oy); bool visible = test_x >= 0 && test_x < rect.w && test_y >= 0 && test_y < rect.h; return visible; } return false; } // +--------------------------------------------------------------------+ void MapView::SetRegion(OrbitalRegion* rgn) { if (scrolling || rgn == 0) return; int index = regions.index(rgn); if (index < 0 || index == current_region || index >= regions.size()) return; current_region = index; Orbital* s = regions[current_region]; if (!s) return; switch (view_mode) { case VIEW_GALAXY: case VIEW_SYSTEM: scroll_x = (offset_x + s->Location().x) / 5.0; scroll_y = (offset_y + s->Location().y) / 5.0; scrolling = 5; break; case VIEW_REGION: offset_x = 0; offset_y = 0; scrolling = 0; break; } } // +--------------------------------------------------------------------+ void MapView::SetRegionByName(const char* rgn_name) { OrbitalRegion* rgn = 0; for (int i = 0; i < regions.size(); i++) { Orbital* r = regions[i]; if (!strcmp(rgn_name, r->Name())) { rgn = (OrbitalRegion*) r; break; } } SetRegion(rgn); } // +--------------------------------------------------------------------+ void MapView::SelectAt(int x, int y) { if (scrolling) return; if (c == 0) return; if (seln_mode < 0) return; Orbital* s = 0; double scale = r/c; double cx = rect.w/2; double cy = rect.h/2; double test_x = (x - rect.x - cx) * scale - offset_x; double test_y = (y - rect.y - cy) * scale - offset_y; double dist = 1.0e20; int closest = 0; if (view_mode == VIEW_GALAXY) { c = (cx>cy) ? cx : cy; r = 10; Galaxy* g = Galaxy::GetInstance(); if (g) r = g->Radius(); StarSystem* closest_system = 0; // draw the list of systems, and their connections: ListIter iter = system_list; while (++iter) { StarSystem* s = iter.value(); double dx = (s->Location().x - test_x); double dy = (s->Location().y - test_y); double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; closest_system = s; } } if (closest_system) SetSystem(closest_system); } else if (view_mode == VIEW_SYSTEM) { switch (seln_mode) { case SELECT_SYSTEM: { if (stars.isEmpty()) return; int index = 0; ListIter star = stars; while (++star) { double dx = (star->Location().x - test_x); double dy = (star->Location().y - test_y); double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; closest = index; } index++; } current_star = closest; } s = stars[current_star]; break; case SELECT_PLANET: { if (planets.isEmpty()) return; int index = 0; ListIter planet = planets; while (++planet) { double dx = (planet->Location().x - test_x); double dy = (planet->Location().y - test_y); double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; closest = index; } index++; } current_planet = closest; } s = planets[current_planet]; break; default: case SELECT_REGION: { if (regions.isEmpty()) return; int index = 0; ListIter region = regions; while (++region) { double dx = (region->Location().x - test_x); double dy = (region->Location().y - test_y); double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; closest = index; } index++; } current_region = closest; } s = regions[current_region]; break; } } else if (view_mode == VIEW_REGION) { dist = 5.0e3; if (mission) { Orbital* rgn = regions[current_region]; MissionElement* sel_elem = 0; Instruction* sel_nav = 0; if (!rgn) return; // check nav points: ListIter elem = mission->GetElements(); while (++elem) { MissionElement* e = elem.value(); if (!e->IsSquadron() && (editor || e->GetIFF() == mission->Team())) { ListIter navpt = e->NavList(); while (++navpt) { Instruction* n = navpt.value(); if (!_stricmp(n->RegionName(), rgn->Name())) { Point nloc = n->Location(); double dx = nloc.x - test_x; double dy = nloc.y - test_y; double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; sel_nav = n; sel_elem = e; } } } } } if (sel_nav) { SelectElem(sel_elem); SelectNavpt(sel_nav); } // check elements: else { elem.reset(); while (++elem) { MissionElement* e = elem.value(); if (e->Region() == rgn->Name() && !e->IsSquadron()) { Point sloc = e->Location(); double dx = sloc.x - test_x; double dy = sloc.y - test_y; double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; sel_elem = e; } } } SelectElem(sel_elem); if (sel_elem) s = rgn; } } else if (ship) { Sim* sim = Sim::GetSim(); Orbital* rgn = regions[current_region]; SimRegion* simrgn = 0; Ship* sel_ship = 0; Instruction* sel_nav = 0; if (sim && rgn) simrgn = sim->FindRegion(rgn->Name()); // check nav points: if (simrgn) { for (int r = 0; r < sim->GetRegions().size(); r++) { SimRegion* simrgn = sim->GetRegions().at(r); for (int i = 0; i < simrgn->Ships().size(); i++) { Ship* s = simrgn->Ships().at(i); if (s->GetIFF() == ship->GetIFF() && s->GetElementIndex() == 1) { ListIter navpt = s->GetFlightPlan(); while (++navpt) { Instruction* n = navpt.value(); if (!_stricmp(n->RegionName(), rgn->Name())) { Point nloc = n->Location(); double dx = nloc.x - test_x; double dy = nloc.y - test_y; double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; sel_nav = n; sel_ship = s; } } } } } } } if (sel_nav) { SelectShip(sel_ship); SelectNavpt(sel_nav); } // check ships: else if (simrgn->NumShips()) { ListIter ship = simrgn->Ships(); while (++ship) { Ship* s = ship.value(); if (!IsClutter(*s)) { Point sloc = s->Location().OtherHand(); double dx = sloc.x - test_x; double dy = sloc.y - test_y; double d = sqrt(dx*dx + dy*dy); if (d < dist) { dist = d; sel_ship = s; } } } SelectShip(sel_ship); } else { SelectShip(0); SelectNavpt(0); } } } if (s) SetupScroll(s); } // +--------------------------------------------------------------------+ Orbital* MapView::GetSelection() { Orbital* s = 0; switch (seln_mode) { case SELECT_SYSTEM: if (current_star < stars.size()) s = stars[current_star]; break; default: case SELECT_PLANET: if (current_planet < planets.size()) s = planets[current_planet]; break; case SELECT_REGION: if (current_region < regions.size()) s = regions[current_region]; break; case SELECT_STATION: case SELECT_STARSHIP: case SELECT_FIGHTER: break; } return s; } Ship* MapView::GetSelectedShip() { return current_ship; } MissionElement* MapView::GetSelectedElem() { return current_elem; } // +--------------------------------------------------------------------+ int MapView::GetSelectionIndex() { int s = 0; switch (seln_mode) { case SELECT_SYSTEM: s = current_star; break; default: case SELECT_PLANET: s = current_planet; break; case SELECT_REGION: s = current_region; break; case SELECT_STATION: case SELECT_STARSHIP: case SELECT_FIGHTER: { s = -1; Sim* sim = Sim::GetSim(); Orbital* rgn = regions[current_region]; SimRegion* simrgn = 0; if (sim && rgn) simrgn = sim->FindRegion(rgn->Name()); if (simrgn) { if (current_ship && simrgn->NumShips()) { s = simrgn->Ships().index(current_ship); } } } break; } return s; } void MapView::DrawTabbedText(Font* font, const char* text) { if (font && text && *text) { Rect label_rect; label_rect.w = rect.w; label_rect.h = rect.h; label_rect.Inset(8,8,8,8); DWORD text_flags = DT_WORDBREAK | DT_LEFT; active_window->SetFont(font); active_window->DrawText(text, 0, label_rect, text_flags); } } // +--------------------------------------------------------------------+ void MapView::Refresh() { rect = window->GetRect(); if (!system) { DrawGrid(); DrawTabbedText(title_font, ContentBundle::GetInstance()->GetText("MapView.item.no-system")); return; } if (font) font->SetColor(Color::White); if (scrolling) { offset_x -= scroll_x; offset_y -= scroll_y; scrolling--; } rect.w -= 2; rect.h -= 2; switch (view_mode) { case VIEW_GALAXY: DrawGalaxy(); break; case VIEW_SYSTEM: DrawSystem(); break; case VIEW_REGION: DrawRegion(); break; default: DrawGrid(); break; } rect.w += 2; rect.h += 2; if (menu_view) { if (current_navpt) { active_menu = nav_menu; } else if (current_ship) { if (current_ship->GetIFF() == ship->GetIFF()) active_menu = ship_menu; else active_menu = map_menu; } else if (current_elem) { if (editor || current_elem->GetIFF() == mission->Team()) active_menu = ship_menu; else active_menu = map_menu; } else { active_menu = map_menu; } menu_view->SetBackColor(Color::Gray); menu_view->SetTextColor(Color::White); menu_view->SetMenu(active_menu); menu_view->DoMouseFrame(); if (menu_view->GetAction()) { ProcessMenuItem(menu_view->GetAction()); } menu_view->Refresh(); } DrawTitle(); } // +--------------------------------------------------------------------+ void MapView::DrawTitle() { title_font->SetColor(active_window->GetForeColor()); DrawTabbedText(title_font, title); } // +--------------------------------------------------------------------+ void MapView::DrawGalaxy() { title = ContentBundle::GetInstance()->GetText("MapView.title.Galaxy"); DrawGrid(); double cx = rect.w/2; double cy = rect.h/2; c = (cx>cy) ? cx : cy; r = 10; // * zoom; Galaxy* g = Galaxy::GetInstance(); if (g) r = g->Radius(); // * zoom; double scale = c/r; double ox = 0; double oy = 0; // compute offset: ListIter iter = system_list; while (++iter) { StarSystem* s = iter.value(); if (system == s) { if (fabs(s->Location().x) > 10 || fabs(s->Location().y) > 10) { int sx = (int) s->Location().x; int sy = (int) s->Location().y; sx -= sx % 10; sy -= sy % 10; ox = sx * -scale; oy = sy * -scale; } } } // draw the list of systems, and their connections: iter.reset(); while (++iter) { StarSystem* s = iter.value(); int sx = (int) (cx + ox + s->Location().x * scale); int sy = (int) (cy + oy + s->Location().y * scale); if (sx < 4 || sx > rect.w-4 || sy < 4 || sy > rect.h-4) continue; window->DrawEllipse(sx-7, sy-7, sx+7, sy+7, Ship::IFFColor(s->Affiliation())); if (s == system) { window->DrawLine(0, sy, rect.w, sy, Color::Gray, Video::BLEND_ADDITIVE); window->DrawLine(sx, 0, sx, rect.h, Color::Gray, Video::BLEND_ADDITIVE); } ListIter iter2 = system_list; while (++iter2) { StarSystem* s2 = iter2.value(); if (s != s2 && s->HasLinkTo(s2)) { int ax = sx; int ay = sy; int bx = (int) (cx + ox + s2->Location().x * scale); int by = (int) (cy + oy + s2->Location().y * scale); if (ax == bx) { if (ay < by) { ay += 8; by -= 8; } else { ay -= 8; by += 8; } } else if (ay == by) { if (ax < bx) { ax += 8; bx -= 8; } else { ax -= 8; bx += 8; } } else { Point d = Point(bx, by, 0) - Point(ax, ay, 0); d.Normalize(); ax += (int) (8 * d.x); ay += (int) (8 * d.y); bx -= (int) (8 * d.x); by -= (int) (8 * d.y); } window->DrawLine(ax, ay, bx, by, Color(120,120,120), Video::BLEND_ADDITIVE); } } } // finally draw all the stars in the galaxy: if (g) { ListIter iter = g->Stars(); while (++iter) { Star* s = iter.value(); int sx = (int) (cx + ox + s->Location().x * scale); int sy = (int) (cy + oy + s->Location().y * scale); int sr = s->GetSize(); if (sx < 4 || sx > rect.w-4 || sy < 4 || sy > rect.h-4) continue; window->FillEllipse(sx-sr, sy-sr, sx+sr, sy+sr, s->GetColor()); if (!strncmp(s->Name(), "GSC", 3)) font->SetColor(Color(100,100,100)); else font->SetColor(Color::White); Rect name_rect(sx-60, sy+8, 120, 20); active_window->SetFont(font); active_window->DrawText(s->Name(), 0, name_rect, DT_SINGLELINE | DT_CENTER); } } font->SetColor(Color::White); } // +--------------------------------------------------------------------+ void MapView::DrawSystem() { Text caption = ContentBundle::GetInstance()->GetText("MapView.title.Starsystem"); caption += " "; caption += system->Name(); if (current_ship) { caption += "\n"; caption += ContentBundle::GetInstance()->GetText("MapView.title.Ship"); caption += " "; caption += current_ship->Name(); } else if (current_elem) { caption += "\n"; caption += ContentBundle::GetInstance()->GetText("MapView.title.Ship"); caption += " "; caption += current_elem->Name(); } title = caption; ListIter star = system->Bodies(); while (++star) { int p_orb = 1; ListIter planet = star->Satellites(); while (++planet) { DrawOrbital(*planet, p_orb++); int m_orb = 1; ListIter moon = planet->Satellites(); while (++moon) { DrawOrbital(*moon, m_orb++); ListIter region = moon->Regions(); while (++region) { DrawOrbital(*region, 1); } } ListIter region = planet->Regions(); while (++region) { DrawOrbital(*region, 1); } } ListIter region = star->Regions(); while (++region) { DrawOrbital(*region, 1); } DrawOrbital(*star, 0); } char r_txt[32]; FormatNumber(r_txt, system->Radius() * zoom); char resolution[64]; sprintf_s(resolution, "%s: %s", ContentBundle::GetInstance()->GetText("MapView.info.Resolution").data(), r_txt); active_window->SetFont(font); Rect text_rect(4, 4, rect.w - 8, 24); active_window->DrawText(resolution, -1, text_rect, DT_SINGLELINE|DT_RIGHT); } // +--------------------------------------------------------------------+ void MapView::DrawRegion() { OrbitalRegion* rgn = (OrbitalRegion*) regions[current_region]; Text caption = ContentBundle::GetInstance()->GetText("MapView.title.Sector"); caption += " "; caption += rgn->Name(); if (current_ship) { caption += "\n"; caption += ContentBundle::GetInstance()->GetText("MapView.title.Ship"); caption += " "; caption += current_ship->Name(); } else if (current_elem) { caption += "\n"; caption += ContentBundle::GetInstance()->GetText("MapView.title.Ship"); caption += " "; caption += current_elem->Name(); } title = caption; double cx = rect.w/2; double cy = rect.h/2; int size = (int) rgn->Radius(); int step = (int) rgn->GridSpace(); c = (cxRadius() * zoom; double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; int left = (int) (-size * scale + ox + cx); int right = (int) ( size * scale + ox + cx); int top = (int) (-size * scale + oy + cy); int bottom = (int) ( size * scale + oy + cy); Color major(48,48,48); Color minor(24,24,24); int x,y; int tick = 0; for (x = 0; x <= size; x += step) { int lx = (int) (x * scale + ox + cx); if (!tick) window->DrawLine(lx, top, lx, bottom, major, Video::BLEND_ADDITIVE); else window->DrawLine(lx, top, lx, bottom, minor, Video::BLEND_ADDITIVE); lx = (int) (-x * scale + ox + cx); if (!tick) window->DrawLine(lx, top, lx, bottom, major, Video::BLEND_ADDITIVE); else window->DrawLine(lx, top, lx, bottom, minor, Video::BLEND_ADDITIVE); if (++tick > 3) tick = 0; } tick = 0; for (y = 0; y <= size; y += step) { int ly = (int) (y * scale + oy + cy); if (!tick) window->DrawLine(left, ly, right, ly, major, Video::BLEND_ADDITIVE); else window->DrawLine(left, ly, right, ly, minor, Video::BLEND_ADDITIVE); ly = (int) (-y * scale + oy + cy); if (!tick) window->DrawLine(left, ly, right, ly, major, Video::BLEND_ADDITIVE); else window->DrawLine(left, ly, right, ly, minor, Video::BLEND_ADDITIVE); if (++tick > 3) tick = 0; } int rep = 3; if (r > 70e3) rep = 2; if (r > 250e3) rep = 1; if (campaign && rgn) { // draw the combatants in this region: ListIter iter = campaign->GetCombatants(); while (++iter) { Combatant* combatant = iter.value(); DrawCombatGroup(combatant->GetForce(), rep); } } else if (mission && rgn) { // draw the elements in this region: ListIter elem = mission->GetElements(); while (++elem) if (!elem->IsSquadron()) DrawElem(*elem, (elem.value() == current_elem), rep); } else if (ship) { // draw the ships in this region: Sim* sim = Sim::GetSim(); SimRegion* simrgn = 0; if (sim && rgn) simrgn = sim->FindRegion(rgn->Name()); // this algorithm uses the allied track list for the region, // even if this ship is in a different region. a previous // version used the ship's own contact list, which only shows // ships in the player's region. this way is less "realistic" // but more fun for managing large battles. if (simrgn) { ListIter c = simrgn->TrackList(ship->GetIFF()); while (++c) { Contact* contact = c.value(); Ship* s = contact->GetShip(); if (s && (s->Class() & ship_filter) && !IsClutter(*s) && s != ship) DrawShip(*s, (s == current_ship), rep); } ListIter s_iter = simrgn->Ships(); while (++s_iter) { Ship* s = s_iter.value(); if (s && (s->IsStatic()) && !IsClutter(*s) && (s->GetIFF() == ship->GetIFF() || s->GetIFF() == 0)) DrawShip(*s, (s == current_ship), rep); } // draw nav routes for allied ships not in the region: ListIter r_iter = sim->GetRegions(); while (++r_iter) { SimRegion* r = r_iter.value(); if (r != simrgn) { ListIter s_iter = r->Ships(); while (++s_iter) { Ship* s = s_iter.value(); if (s && !s->IsStatic() && !IsClutter(*s) && (s->GetIFF() == ship->GetIFF() || s->GetIFF() == 0)) { DrawNavRoute(simrgn->GetOrbitalRegion(), s->GetFlightPlan(), s->MarkerColor(), s, 0); } } } } } // draw our own ship: DrawShip(*ship, (ship == current_ship), rep); } char r_txt[32]; FormatNumber(r_txt, r*2); char resolution[64]; sprintf_s(resolution, "%s: %s", ContentBundle::GetInstance()->GetText("MapView.info.Resolution").data(), r_txt); active_window->SetFont(font); Rect text_rect(4, 4, rect.w - 8, 24); active_window->DrawText(resolution, -1, text_rect, DT_SINGLELINE|DT_RIGHT); } // +--------------------------------------------------------------------+ void MapView::DrawGrid() { int grid_step = rect.w/8; int cx = rect.w/2; int cy = rect.h/2; Color c(32,32,32); window->DrawLine(0, cy, rect.w, cy, c, Video::BLEND_ADDITIVE); window->DrawLine(cx, 0, cx, rect.h, c, Video::BLEND_ADDITIVE); for (int i = 1; i < 4; i++) { window->DrawLine(0, cy + (i*grid_step), rect.w, cy + (i*grid_step), c, Video::BLEND_ADDITIVE); window->DrawLine(0, cy - (i*grid_step), rect.w, cy - (i*grid_step), c, Video::BLEND_ADDITIVE); window->DrawLine(cx + (i*grid_step), 0, cx + (i*grid_step), rect.h, c, Video::BLEND_ADDITIVE); window->DrawLine(cx - (i*grid_step), 0, cx - (i*grid_step), rect.h, c, Video::BLEND_ADDITIVE); } } // +--------------------------------------------------------------------+ void MapView::DrawOrbital(Orbital& body, int index) { int type = body.Type(); if (type == Orbital::NOTHING) return; int x1, y1, x2, y2; Rect label_rect; int label_w = 64; int label_h = 18; double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; if ((r > 300e9) && (type > Orbital::PLANET)) return; double xscale = cx / r; double yscale = cy / r * 0.75; double ox = offset_x * xscale; double oy = offset_y * yscale; double bo_x = body.Orbit() * xscale; double bo_y = body.Orbit() * yscale; double br = body.Radius() * yscale; double bx = body.Location().x * xscale; double by = body.Location().y * yscale; double px = 0; double py = 0; if (body.Primary()) { double min_pr = GetMinRadius(body.Primary()->Type()); if (index) { if (min_pr < 4) min_pr = 4; min_pr *= (index+1); } double min_x = min_pr * xscale / yscale; double min_y = min_pr; if (bo_x < min_x) bo_x = min_x; if (bo_y < min_y) bo_y = min_y; px = body.Primary()->Location().x * xscale; py = body.Primary()->Location().y * yscale; } if (type == Orbital::TERRAIN) bo_x = bo_y; int ipx = (int) (cx + px + ox); int ipy = (int) (cy + py + oy); int ibo_x = (int) bo_x; int ibo_y = (int) bo_y; x1 = ipx - ibo_x; y1 = ipy - ibo_y; x2 = ipx + ibo_x; y2 = ipy + ibo_y; if (type != Orbital::TERRAIN) { double a = x2-x1; double b = rect.w*32; if (a < b) window->DrawEllipse(x1, y1, x2, y2, Color(64,64,64), Video::BLEND_ADDITIVE); } // show body's location on possibly magnified orbit bx = px + bo_x * cos(body.Phase()); by = py + bo_y * sin(body.Phase()); double min_br = GetMinRadius(type); if (br < min_br) br = min_br; Color color; switch (type) { case Orbital::STAR: color = Color(248, 248, 128); break; case Orbital::PLANET: color = Color( 64, 64, 192); break; case Orbital::MOON: color = Color( 32, 192, 96); break; case Orbital::REGION: color = Color(255, 255, 255); break; case Orbital::TERRAIN: color = Color( 16, 128, 48); break; } int icx = (int) (cx + bx + ox); int icy = (int) (cy + by + oy); int ibr = (int) br; x1 = icx - ibr; y1 = icy - ibr; x2 = icx + ibr; y2 = icy + ibr; if (type < Orbital::REGION) { if (body.GetMapIcon().Width() > 64) { Bitmap* map_icon = (Bitmap*) &body.GetMapIcon(); if (type == Orbital::STAR) window->DrawBitmap(x1,y1,x2,y2, map_icon, Video::BLEND_ADDITIVE); else window->DrawBitmap(x1,y1,x2,y2, map_icon, Video::BLEND_ALPHA); } else { window->FillEllipse(x1, y1, x2, y2, color); } } else { window->DrawRect(x1, y1, x2, y2, color); if (campaign) { ListIter iter = campaign->GetCombatants(); while (++iter) { Combatant* combatant = iter.value(); if (ibr >= 4 || combatant->GetIFF() == 1) DrawCombatantSystem(combatant, &body, icx, icy, ibr); } } } if (type == Orbital::STAR || bo_y > label_h) { label_rect.x = x1 - label_w + (int) br; label_rect.y = y1 - label_h; label_rect.w = label_w * 2; label_rect.h = label_h; active_window->SetFont(font); active_window->DrawText(body.Name(), -1, label_rect, DT_SINGLELINE|DT_CENTER); } } // +--------------------------------------------------------------------+ double MapView::GetMinRadius(int type) { switch (type) { case Orbital::STAR: return 8; case Orbital::PLANET: return 4; case Orbital::MOON: return 2; case Orbital::REGION: return 2; } return 0; } // +--------------------------------------------------------------------+ static void ColorizeBitmap(Bitmap& img, Color color) { int w = img.Width(); int h = img.Height(); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Color c = img.GetColor(x, y); if (c != Color::Black && c != Color::White) { img.SetColor(x,y,color.ShadeColor(c.Blue()/2)); } } } img.AutoMask(); } static POINT shipshape1[] = { {6,0}, {-6,4}, {-6,-4} }; static POINT shipshape2[] = { {8,0}, { 4,4}, {-8,4}, {-8,-4}, {4,-4} }; static POINT shipshape3[] = { {8,8}, {-8,8}, {-8,-8}, {8,-8} }; void MapView::DrawShip(Ship& s, bool current, int rep) { OrbitalRegion* rgn = (OrbitalRegion*) regions[current_region]; if (!rgn) return; int x1, y1, x2, y2; POINT shiploc; Point sloc = s.Location().OtherHand(); double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; double rlx = 0; double rly = 0; int sprite_width = 10; window->SetFont(font); // draw ship icon: if (rep && view_mode == VIEW_REGION && rgn == s.GetRegion()->GetOrbitalRegion()) { double sx = (sloc.x + rlx) * scale; double sy = (sloc.y + rly) * scale; shiploc.x = (int) (cx + sx + ox); shiploc.y = (int) (cy + sy + oy); bool ship_visible = shiploc.x >= 0 && shiploc.x < rect.w && shiploc.y >= 0 && shiploc.y < rect.h; if (ship_visible) { if (rep < 3) { window->FillRect(shiploc.x-2, shiploc.y-2, shiploc.x+2, shiploc.y+2, s.MarkerColor()); sprite_width = 2; if (&s == ship || !IsCrowded(s)) window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, s.Name()); } else { Point heading = s.Heading().OtherHand(); heading.z = 0; heading.Normalize(); double theta = 0; if (heading.y > 0) theta = acos(heading.x); else theta = -acos(heading.x); const double THETA_SLICE = 4 / PI; const double THETA_OFFSET = PI + THETA_SLICE/2; int sprite_index = (int) ((theta + THETA_OFFSET) * THETA_SLICE); int nsprites = s.Design()->map_sprites.size(); if (nsprites) { if (sprite_index < 0 || sprite_index >= nsprites) sprite_index = sprite_index % nsprites; Bitmap* map_sprite = s.Design()->map_sprites[sprite_index]; Bitmap bmp; bmp.CopyBitmap(*map_sprite); ColorizeBitmap(bmp, s.MarkerColor()); sprite_width = bmp.Width()/2; int h = bmp.Height()/2; window->DrawBitmap(shiploc.x-sprite_width, shiploc.y-h, shiploc.x+sprite_width, shiploc.y+h, &bmp, Video::BLEND_ALPHA); } else { theta -= PI/2; if (s.IsStatic()) { window->FillRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, s.MarkerColor()); window->DrawRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, Color::White); } else if (s.IsStarship()) { window->FillRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, s.MarkerColor()); window->DrawRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, Color::White); } else { window->FillRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, s.MarkerColor()); window->DrawRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, Color::White); } } window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, s.Name()); } } } // draw nav route: // draw current ship marker: if (current && Text(s.GetRegion()->Name()) == regions[current_region]->Name()) { x1 = (int) (shiploc.x - sprite_width - 1); x2 = (int) (shiploc.x + sprite_width + 1); y1 = (int) (shiploc.y - sprite_width - 1); y2 = (int) (shiploc.y + sprite_width + 1); window->DrawRect(x1, y1, x2, y2, Color::White); } // only see routes for your own team: if (s.GetIFF() == 0 || ship && s.GetIFF() == ship->GetIFF()) { DrawNavRoute(rgn, s.GetFlightPlan(), s.MarkerColor(), &s, 0); } } void MapView::DrawElem(MissionElement& s, bool current, int rep) { if (!mission) return; bool visible = editor || s.GetIFF() == 0 || s.GetIFF() == mission->Team() || s.IntelLevel() > Intel::KNOWN; if (!visible) return; OrbitalRegion* rgn = (OrbitalRegion*) regions[current_region]; if (!rgn) return; int x1, y1, x2, y2; POINT shiploc; double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; double rlx = 0; double rly = 0; int sprite_width = 10; window->SetFont(font); // draw ship icon: if (!_stricmp(s.Region(), rgn->Name())) { double sx = (s.Location().x + rlx) * scale; double sy = (s.Location().y + rly) * scale; shiploc.x = (int) (cx + sx + ox); shiploc.y = (int) (cy + sy + oy); bool ship_visible = shiploc.x >= 0 && shiploc.x < rect.w && shiploc.y >= 0 && shiploc.y < rect.h; if (ship_visible) { if (rep < 3) { window->FillRect(shiploc.x-2, shiploc.y-2, shiploc.x+2, shiploc.y+2, s.MarkerColor()); sprite_width = 2; if (!IsCrowded(s)) window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, s.Name()); } else { double theta = s.Heading(); const double THETA_SLICE = 4 / PI; const double THETA_OFFSET = PI / 2; int sprite_index = (int) ((theta + THETA_OFFSET) * THETA_SLICE); int nsprites = 0; if (s.GetDesign()) nsprites = s.GetDesign()->map_sprites.size(); if (nsprites > 0) { if (sprite_index < 0 || sprite_index >= nsprites) sprite_index = sprite_index % nsprites; Bitmap* map_sprite = s.GetDesign()->map_sprites[sprite_index]; Bitmap bmp; bmp.CopyBitmap(*map_sprite); ColorizeBitmap(bmp, s.MarkerColor()); sprite_width = bmp.Width()/2; int h = bmp.Height()/2; window->DrawBitmap(shiploc.x-sprite_width, shiploc.y-h, shiploc.x+sprite_width, shiploc.y+h, &bmp, Video::BLEND_ALPHA); } else { theta -= PI/2; if (s.IsStatic()) { window->FillRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, s.MarkerColor()); window->DrawRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, Color::White); } else if (s.IsStarship()) { window->FillRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, s.MarkerColor()); window->DrawRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, Color::White); } else { window->FillRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, s.MarkerColor()); window->DrawRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, Color::White); } } char label[64]; if (s.Count() > 1) sprintf_s(label, "%s x %d", (const char*) s.Name(), s.Count()); else strcpy_s(label, (const char*) s.Name()); window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, label); } } } // draw nav route: // draw current ship marker: if (current && s.Region() == regions[current_region]->Name()) { x1 = (int) (shiploc.x - sprite_width - 1); x2 = (int) (shiploc.x + sprite_width + 1); y1 = (int) (shiploc.y - sprite_width - 1); y2 = (int) (shiploc.y + sprite_width + 1); window->DrawRect(x1, y1, x2, y2, Color::White); } // only see routes for your own team: if (editor || s.GetIFF() == 0 || mission && s.GetIFF() == mission->Team()) { DrawNavRoute(rgn, s.NavList(), s.MarkerColor(), 0, &s); } } void MapView::DrawNavRoute(OrbitalRegion* rgn, List& s_route, Color s_marker, Ship* ship, MissionElement* elem) { int x1, y1, x2, y2; double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; if (view_mode == VIEW_REGION) { if (!rgn) return; r = rgn->Radius() * zoom; } double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; Point old_loc; double old_x = 0; double old_y = 0; bool old_in = false; Point first_loc; int first_x = 0; int first_y = 0; bool first_in = false; bool draw_route = true; bool draw_bold = false; if (ship && ship->GetElementIndex() > 1) draw_route = false; if (ship && ship == current_ship) { s_marker = s_marker * 1.5; draw_bold = true; } else if (elem && elem == current_elem) { s_marker = s_marker * 1.5; draw_bold = true; } for (int i = 0; i < s_route.size(); i++) { Instruction* navpt = s_route[i]; if (!_stricmp(navpt->RegionName(), rgn->Name())) { double nav_x = navpt->Location().x * scale; double nav_y = navpt->Location().y * scale; int isx = (int) (cx + nav_x + ox); int isy = (int) (cy + nav_y + oy); if (old_in && draw_route) { int iox = (int) (cx + old_x + ox); int ioy = (int) (cy + old_y + oy); window->DrawLine(iox, ioy, isx, isy, s_marker); int x1 = (iox-isx); int y1 = (ioy-isy); if (draw_bold) { if (x1 > y1) { window->DrawLine(iox, ioy+1, isx, isy+1, s_marker); } else { window->DrawLine(iox+1, ioy, isx+1, isy, s_marker); } } if ((x1*x1 + y1*y1) > 2000) { double dist = Point(navpt->Location() - old_loc).length(); int imx = (int) (cx + (old_x+nav_x)/2 + ox); int imy = (int) (cy + (old_y+nav_y)/2 + oy); char dist_txt[32]; FormatNumber(dist_txt, dist); font->SetColor(Color::Gray); window->SetFont(font); window->Print(imx-20, imy-6, dist_txt); font->SetColor(Color::White); } } x1 = isx - 3; y1 = isy - 3; x2 = isx + 3; y2 = isy + 3; Color c = Color::White; if (navpt->Status() > Instruction::ACTIVE) { c = Color::Gray; } else if (!first_in) { first_in = true; first_loc = navpt->Location(); first_x = isx; first_y = isy; } if (draw_route) { window->DrawLine(x1, y1, x2, y2, c); window->DrawLine(x1, y2, x2, y1, c); if (navpt == current_navpt) window->DrawRect(x1-2, y1-2, x2+2, y2+2, c); char buf[256]; sprintf_s(buf, "%d", i+1); window->SetFont(font); window->Print(x2+3, y1, buf); if (navpt == current_navpt) { if (navpt->TargetName() && strlen(navpt->TargetName())) { sprintf_s(buf, "%s %s", ContentBundle::GetInstance()->GetText(Text("MapView.item.") + Instruction::ActionName(navpt->Action())).data(), navpt->TargetName()); window->Print(x2+3, y1+10, buf); } else { sprintf_s(buf, "%s", ContentBundle::GetInstance()->GetText(Text("MapView.item.") + Instruction::ActionName(navpt->Action())).data()); window->Print(x2+3, y1+10, buf); } sprintf_s(buf, "%s", ContentBundle::GetInstance()->GetText(Text("MapView.item.") + Instruction::FormationName(navpt->Formation())).data()); window->Print(x2+3, y1+20, buf); sprintf_s(buf, "%d", navpt->Speed()); window->Print(x2+3, y1+30, buf); if (navpt->HoldTime()) { char hold_time[32]; FormatTime(hold_time, navpt->HoldTime()); sprintf_s(buf, "%s %s", ContentBundle::GetInstance()->GetText("MapView.item.Hold").data(), hold_time); window->Print(x2+3, y1+40, buf); } } } old_loc = navpt->Location(); old_x = nav_x; old_y = nav_y; old_in = true; } else { old_loc = navpt->Location(); old_x = 0; old_y = 0; old_in = false; } } // if the ship and the first active navpoint are both in the region, // draw a line from the ship to the first active navpoint: if (first_in) { old_in = false; if (ship && ship->GetRegion()) { old_in = (ship->GetRegion()->GetOrbitalRegion() == rgn); if (old_in) { old_loc = ship->Location().OtherHand(); old_x = old_loc.x * scale; old_y = old_loc.y * scale; } } else if (elem) { old_in = (elem->Region() == rgn->Name()) ? true : false; if (old_in) { old_loc = elem->Location(); old_x = old_loc.x * scale; old_y = old_loc.y * scale; } } if (old_in) { int iox = (int) (cx + old_x + ox); int ioy = (int) (cy + old_y + oy); window->DrawLine(iox, ioy, first_x, first_y, s_marker); int x1 = (iox-first_x); int y1 = (ioy-first_y); if (draw_bold) { if (x1 > y1) { window->DrawLine(iox, ioy+1, first_x, first_y+1, s_marker); } else { window->DrawLine(iox+1, ioy, first_x+1, first_y, s_marker); } } if ((x1*x1 + y1*y1) > 2000) { double dist = Point(first_loc - old_loc).length(); double nav_x = first_loc.x * scale; double nav_y = first_loc.y * scale; int imx = (int) (cx + (old_x+nav_x)/2 + ox); int imy = (int) (cy + (old_y+nav_y)/2 + oy); char dist_txt[32]; FormatNumber(dist_txt, dist); font->SetColor(Color::Gray); window->SetFont(font); window->Print(imx-20, imy-6, dist_txt); font->SetColor(Color::White); } } } } // +--------------------------------------------------------------------+ void MapView::DrawCombatantSystem(Combatant* c, Orbital* rgn, int x, int y, int r) { int team = c->GetIFF(); int x1 = 0; int x2 = 0; int y1 = y - r; int a = 0; switch (team) { case 0: x1 = x - 64; x2 = x + 64; y1 = y + r + 4; a = DT_CENTER; break; case 1: x1 = x - 200; x2 = x - r - 4; a = DT_RIGHT; break; default: x1 = x + r + 4; x2 = x + 200; a = DT_LEFT; break; } DrawCombatGroupSystem(c->GetForce(), rgn, x1, x2, y1, a); } // +--------------------------------------------------------------------+ void MapView::DrawCombatGroupSystem(CombatGroup* group, Orbital* rgn, int x1, int x2, int& y, int a) { if (!group || group->IsReserve() || group->CalcValue() < 1) return; char txt[80]; if (group->GetRegion() == rgn->Name()) { switch (group->Type()) { case CombatGroup::CARRIER_GROUP: case CombatGroup::BATTLE_GROUP: case CombatGroup::DESTROYER_SQUADRON: { sprintf_s(txt, "%s '%s'", group->GetShortDescription(), group->Name().data()); active_window->SetFont(font); Rect text_rect(x1, y, x2 - x1, 12); active_window->DrawText(txt, 0, text_rect, a); y += 10; break; } case CombatGroup::BATTALION: case CombatGroup::STATION: case CombatGroup::STARBASE: case CombatGroup::MINEFIELD: case CombatGroup::BATTERY: case CombatGroup::MISSILE: { active_window->SetFont(font); Rect text_rect(x1, y, x2 - x1, 12); active_window->DrawText(group->GetShortDescription(), 0, text_rect, a); y += 10; break; } default: break; } } ListIter iter = group->GetComponents(); while (++iter) { CombatGroup* g = iter.value(); DrawCombatGroupSystem(g, rgn, x1, x2, y, a); } } // +--------------------------------------------------------------------+ void MapView::DrawCombatGroup(CombatGroup* group, int rep) { // does group even exist yet? if (!group || group->IsReserve() || group->CalcValue() < 1) return; // is group a squadron? don't draw squadrons on map: if (group->Type() >= CombatGroup::WING && group->Type() < CombatGroup::FLEET) return; // has group been discovered yet? CombatGroup* player_group = campaign->GetPlayerGroup(); if (group->GetIFF() && player_group && player_group->GetIFF() != group->GetIFF()) if (group->IntelLevel() <= Intel::KNOWN) return; // has group been destroyed already? if (group->CalcValue() < 1) return; OrbitalRegion* rgn = (OrbitalRegion*) regions[current_region]; if (!rgn) return; POINT shiploc; double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; double rlx = 0; double rly = 0; int sprite_width = 10; if (group->GetUnits().size() > 0) { CombatUnit* unit = 0; for (int i = 0; i < group->GetUnits().size(); i++) { unit = group->GetUnits().at(i); if (unit->Count() - unit->DeadCount() > 0) break; } // draw unit icon: if (unit->GetRegion() == rgn->Name() && unit->Type() > Ship::LCA && unit->Count() > 0) { double sx = (unit->Location().x + rlx) * scale; double sy = (unit->Location().y + rly) * scale; shiploc.x = (int) (cx + sx + ox); shiploc.y = (int) (cy + sy + oy); bool ship_visible = shiploc.x >= 0 && shiploc.x < rect.w && shiploc.y >= 0 && shiploc.y < rect.h; if (ship_visible) { if (rep < 3) { window->FillRect(shiploc.x-2, shiploc.y-2, shiploc.x+2, shiploc.y+2, unit->MarkerColor()); sprite_width = 2; char buf[256]; sprintf_s(buf, "%s", unit->Name().data()); window->SetFont(font); window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, buf); } else { int sprite_index = 2; int nsprites = 0; if (unit->GetDesign()) nsprites = unit->GetDesign()->map_sprites.size(); if (nsprites) { if (sprite_index >= nsprites) sprite_index = sprite_index % nsprites; Bitmap* map_sprite = unit->GetDesign()->map_sprites[sprite_index]; Bitmap bmp; bmp.CopyBitmap(*map_sprite); ColorizeBitmap(bmp, unit->MarkerColor()); sprite_width = bmp.Width()/2; int h = bmp.Height()/2; window->DrawBitmap(shiploc.x-sprite_width, shiploc.y-h, shiploc.x+sprite_width, shiploc.y+h, &bmp, Video::BLEND_ALPHA); } else { if (unit->IsStatic()) { window->FillRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, unit->MarkerColor()); window->DrawRect(shiploc.x-6, shiploc.y-6, shiploc.x+6, shiploc.y+6, Color::White); } else if (unit->IsStarship()) { window->FillRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, unit->MarkerColor()); window->DrawRect(shiploc.x-4, shiploc.y-4, shiploc.x+4, shiploc.y+4, Color::White); } else { window->FillRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, unit->MarkerColor()); window->DrawRect(shiploc.x-3, shiploc.y-3, shiploc.x+3, shiploc.y+3, Color::White); } } char label[128]; strcpy_s(label, unit->GetDescription()); window->SetFont(font); window->Print(shiploc.x-sprite_width, shiploc.y+sprite_width+2, label); } } } } // recurse ListIter iter = group->GetComponents(); while (++iter) { CombatGroup* g = iter.value(); DrawCombatGroup(g, rep); } } // +--------------------------------------------------------------------+ bool MapView::IsClutter(Ship& test) { // get leader: Ship* lead = test.GetLeader(); if (lead == &test) // this is the leader: return false; // too close? if (lead) { POINT testloc, leadloc; GetShipLoc(test, testloc); GetShipLoc(*lead, leadloc); double dx = testloc.x - leadloc.x; double dy = testloc.y - leadloc.y; double d = dx*dx + dy*dy; if (d <= 64) return true; } return false; } // +--------------------------------------------------------------------+ bool MapView::IsCrowded(Ship& test) { POINT testloc, refloc; Sim* sim = Sim::GetSim(); Orbital* rgn = regions[current_region]; SimRegion* simrgn = sim->FindRegion(rgn->Name()); if (simrgn) { GetShipLoc(test, testloc); ListIter s = simrgn->Ships(); while (++s) { Ship* ref = s.value(); // too close? if (ref && ref != &test) { GetShipLoc(*ref, refloc); double dx = testloc.x - refloc.x; double dy = testloc.y - refloc.y; double d = dx*dx + dy*dy; if (d <= 64) return true; } } } return false; } void MapView::GetShipLoc(Ship& s, POINT& shiploc) { double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; OrbitalRegion* rgn = (OrbitalRegion*) regions[current_region]; if (view_mode == VIEW_REGION) { if (!rgn) return; r = rgn->Radius() * zoom; } double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; double rlx = 0; double rly = 0; if (view_mode == VIEW_SYSTEM) { rgn = system->ActiveRegion(); if (rgn) { rlx = rgn->Location().x; rly = rgn->Location().y; } } if (view_mode == VIEW_SYSTEM || (view_mode == VIEW_REGION && rgn == s.GetRegion()->GetOrbitalRegion())) { double sx = (s.Location().x + rlx) * scale; double sy = (s.Location().y + rly) * scale; shiploc.x = (int) (cx + sx + ox); shiploc.y = (int) (cy + sy + oy); } else { shiploc.x = -1; shiploc.y = -1; } } // +--------------------------------------------------------------------+ bool MapView::IsCrowded(MissionElement& test) { POINT testloc, refloc; Sim* sim = Sim::GetSim(); Orbital* rgn = regions[current_region]; if (mission) { GetElemLoc(test, testloc); ListIter s = mission->GetElements(); while (++s) { MissionElement* ref = s.value(); if (ref && ref != &test && !_stricmp(ref->Region(), rgn->Name())) { GetElemLoc(*ref, refloc); double dx = testloc.x - refloc.x; double dy = testloc.y - refloc.y; double d = dx*dx + dy*dy; if (d <= 64) return true; } } } return false; } void MapView::GetElemLoc(MissionElement& s, POINT& shiploc) { double cx = rect.w/2; double cy = rect.h/2; c = (cxRadius() * zoom; OrbitalRegion* rgn = (OrbitalRegion*) regions[current_region]; if (view_mode == VIEW_REGION) { if (!rgn) return; r = rgn->Radius() * zoom; } double scale = c/r; double ox = offset_x * scale; double oy = offset_y * scale; double rlx = 0; double rly = 0; if (view_mode == VIEW_SYSTEM) { rgn = system->ActiveRegion(); if (rgn) { rlx = rgn->Location().x; rly = rgn->Location().y; } } if (view_mode == VIEW_SYSTEM || (view_mode == VIEW_REGION && !_stricmp(s.Region(), rgn->Name()))) { double sx = (s.Location().x + rlx) * scale; double sy = (s.Location().y + rly) * scale; shiploc.x = (int) (cx + sx + ox); shiploc.y = (int) (cy + sy + oy); } else { shiploc.x = -1; shiploc.y = -1; } } // +--------------------------------------------------------------------+ OrbitalRegion* MapView::GetRegion() const { OrbitalRegion* result = 0; if (current_region < regions.size()) result = (OrbitalRegion*) regions[current_region]; return result; } // +--------------------------------------------------------------------+ void MapView::ZoomIn() { zoom *= 0.9; if (view_mode == VIEW_SYSTEM) { if (system && zoom * system->Radius() < 2e6) { zoom = 2e6 / system->Radius(); } } else if (view_mode == VIEW_REGION) { OrbitalRegion* rgn = GetRegion(); if (rgn && zoom * rgn->Radius() < 1e3) { zoom = 1e3 / rgn->Radius(); } } } void MapView::ZoomOut() { zoom *= 1.1; if (view_mode == VIEW_SYSTEM) { if (system && zoom * system->Radius() > 500e9) { zoom = 500e9 / system->Radius(); } } else if (view_mode == VIEW_REGION) { OrbitalRegion* rgn = GetRegion(); if (rgn && zoom * rgn->Radius() > 1e6) { zoom = 1e6 / rgn->Radius(); } } } // +--------------------------------------------------------------------+ void MapView::OnShow() { UIEventDispatch* dispatch = UIEventDispatch::GetInstance(); if (dispatch) dispatch->Register(this); } void MapView::OnHide() { UIEventDispatch* dispatch = UIEventDispatch::GetInstance(); if (dispatch) dispatch->Unregister(this); if (captured) { ReleaseCapture(); captured = false; Mouse::Show(true); } dragging = false; } // +--------------------------------------------------------------------+ bool MapView::IsEnabled() const { if (active_window) return active_window->IsEnabled(); return false; } bool MapView::IsVisible() const { if (active_window) return active_window->IsVisible(); return false; } bool MapView::IsFormActive() const { if (active_window) return active_window->IsFormActive(); return false; } Rect MapView::TargetRect() const { if (active_window) return active_window->TargetRect(); return Rect(); } // +--------------------------------------------------------------------+ int MapView::OnMouseMove(int x, int y) { if (captured) { UIEventTarget* test = 0; UIEventDispatch* dispatch = UIEventDispatch::GetInstance(); if (dispatch) test = dispatch->GetCapture(); if (test != this) { captured = false; Mouse::Show(true); } else { if (dragging) { int delta_x = x - mouse_x; int delta_y = y - mouse_y; offset_x += delta_x * r / c; offset_y += delta_y * r / c; Mouse::SetCursorPos(mouse_x, mouse_y); } else if (view_mode == VIEW_REGION) { double scale = r/c; click_x = (x - rect.x - rect.w/2) * scale - offset_x; click_y = (y - rect.y - rect.h/2) * scale - offset_y; if ((adding_navpt || moving_navpt) && current_navpt) { Point loc = current_navpt->Location(); loc.x = click_x; loc.y = click_y; current_navpt->SetLocation(loc); current_navpt->SetStatus(current_status); } else if (editor && moving_elem && current_elem) { Point loc = current_elem->Location(); loc.x = click_x; loc.y = click_y; current_elem->SetLocation(loc); } } } } return active_window->OnMouseMove(x,y); } // +--------------------------------------------------------------------+ int MapView::OnRButtonDown(int x, int y) { if (!captured) captured = SetCapture(); if (captured) { dragging = true; mouse_x = x; mouse_y = y; Mouse::Show(false); } return active_window->OnRButtonDown(x, y); } // +--------------------------------------------------------------------+ int MapView::OnRButtonUp(int x, int y) { if (captured) { ReleaseCapture(); captured = false; Mouse::Show(true); } dragging = false; return active_window->OnRButtonUp(x, y); } // +--------------------------------------------------------------------+ int MapView::OnClick() { return active_window->OnClick(); } int MapView::OnLButtonDown(int x, int y) { if (menu_view && menu_view->IsShown()) { // ignore this event... } else { if (!captured) captured = SetCapture(); if (view_mode == VIEW_REGION) { double scale = r/c; click_x = (x - rect.x - rect.w/2) * scale - offset_x; click_y = (y - rect.y - rect.h/2) * scale - offset_y; if (current_navpt) { Point nloc = current_navpt->Location(); double dx = nloc.x - click_x; double dy = nloc.y - click_y; double d = sqrt(dx*dx + dy*dy); if (d < 5e3) { moving_navpt = true; if (ship && current_ship && ship != current_ship) { if (ship->GetElement() && current_ship->GetElement()) { if (!ship->GetElement()->CanCommand(current_ship->GetElement())) { moving_navpt = false; } } } else if (current_elem && NetLobby::GetInstance()) { moving_navpt = false; } } } else if (editor && current_elem) { Point nloc = current_elem->Location(); double dx = nloc.x - click_x; double dy = nloc.y - click_y; double d = sqrt(dx*dx + dy*dy); if (d < 5e3) { moving_elem = true; if (current_elem && NetLobby::GetInstance()) { moving_elem = false; } } } } } return active_window->OnLButtonDown(x,y); } int MapView::OnLButtonUp(int x, int y) { bool process_event = false; if (captured) { process_event = true; ReleaseCapture(); captured = false; Mouse::Show(true); } if (process_event && !adding_navpt) { if (!moving_navpt && !moving_elem) { Button::PlaySound(); } if (view_mode == VIEW_REGION) { double scale = r/c; click_x = (x - rect.x - rect.w/2) * scale - offset_x; click_y = (y - rect.y - rect.h/2) * scale - offset_y; if (!scrolling) SelectAt(x,y); active_window->ClientEvent(EID_MAP_CLICK, x, y); } else if (!scrolling) { SelectAt(x,y); active_window->ClientEvent(EID_MAP_CLICK, x, y); } } if ((adding_navpt || moving_navpt) && current_navpt) { current_navpt->SetStatus(current_status); Sim* sim = Sim::GetSim(); if (sim) { Ship* s = current_ship; if (s && s->GetElement()) { Element* elem = s->GetElement(); int index = elem->GetNavIndex(current_navpt); if (index >= 0) NetUtil::SendNavData(false, elem, index-1, current_navpt); } } } adding_navpt = false; moving_navpt = false; moving_elem = false; return active_window->OnLButtonUp(x,y); }