/* Starshatter OpenSource Distribution Copyright (c) 1997-2004, Destroyer Studios LLC. All Rights Reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name "Destroyer Studios" nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SUBSYSTEM: Stars.exe FILE: MapView.cpp AUTHOR: John DiCamillo OVERVIEW ======== Star Map class */ #include "MemDebug.h" #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 "DataLoader.h" #include "EventDispatch.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(__FILE__,__LINE__) 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(__FILE__,__LINE__) Menu(Game::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(__FILE__,__LINE__) Menu(Game::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(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.MAP")); map_menu->AddMenu("System", map_system_menu); map_menu->AddMenu("Sector", map_sector_menu); if (ship || mission) { ship_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.SHIP")); ship_menu->AddMenu(Game::GetText("MapView.item.Starsystem"), map_system_menu); ship_menu->AddMenu(Game::GetText("MapView.item.Sector"), map_sector_menu); ship_menu->AddItem("", 0); ship_menu->AddItem(Game::GetText("MapView.item.Add-Nav"), MAP_ADDNAV); ship_menu->AddItem(Game::GetText("MapView.item.Clear-All"), MAP_CLEAR); action_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.ACTION")); for (int i = 0; i < Instruction::NUM_ACTIONS; i++) { action_menu->AddItem(Game::GetText(Text("MapView.item.") + Instruction::ActionName(i)), MAP_ACTION + i); } formation_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.FORMATION")); for (int i = 0; i < Instruction::NUM_FORMATIONS; i++) { formation_menu->AddItem(Game::GetText(Text("MapView.item.") + Instruction::FormationName(i)), MAP_FORMATION + i); } speed_menu = new(__FILE__,__LINE__) Menu(Game::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(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.HOLD")); hold_menu->AddItem(Game::GetText("MapView.item.None"), MAP_HOLD + 0); hold_menu->AddItem(Game::GetText("MapView.item.1-Minute"), MAP_HOLD + 1); hold_menu->AddItem(Game::GetText("MapView.item.5-Minutes"), MAP_HOLD + 2); hold_menu->AddItem(Game::GetText("MapView.item.10-Minutes"), MAP_HOLD + 3); hold_menu->AddItem(Game::GetText("MapView.item.15-Minutes"), MAP_HOLD + 4); farcast_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.FARCAST")); farcast_menu->AddItem(Game::GetText("MapView.item.Use-Quantum"), MAP_FARCAST + 0); farcast_menu->AddItem(Game::GetText("MapView.item.Use-Farcast"), MAP_FARCAST + 1); objective_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.OBJECTIVE")); nav_menu = new(__FILE__,__LINE__) Menu(Game::GetText("MapView.menu.NAVPT")); nav_menu->AddMenu(Game::GetText("MapView.item.Action"), action_menu); nav_menu->AddMenu(Game::GetText("MapView.item.Objective"), objective_menu); nav_menu->AddMenu(Game::GetText("MapView.item.Formation"), formation_menu); nav_menu->AddMenu(Game::GetText("MapView.item.Speed"), speed_menu); nav_menu->AddMenu(Game::GetText("MapView.item.Hold"), hold_menu); nav_menu->AddMenu(Game::GetText("MapView.item.Farcast"), farcast_menu); nav_menu->AddItem("", 0); nav_menu->AddItem(Game::GetText("MapView.item.Add-Nav"), MAP_ADDNAV); nav_menu->AddItem(Game::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(__FILE__,__LINE__) Instruction(rgn, init_pt); } else { n = new(__FILE__,__LINE__) 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(__FILE__,__LINE__) 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() { EventDispatch* dispatch = EventDispatch::GetInstance(); if (dispatch) return dispatch->CaptureMouse(this) ? true : false; return 0; } // +--------------------------------------------------------------------+ bool MapView::ReleaseCapture() { EventDispatch* dispatch = EventDispatch::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(Game::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(Game::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(__FILE__,__LINE__) 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(__FILE__,__LINE__) 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, Game::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 = Game::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 = Game::GetText("MapView.title.Starsystem"); caption += " "; caption += system->Name(); if (current_ship) { caption += "\n"; caption += Game::GetText("MapView.title.Ship"); caption += " "; caption += current_ship->Name(); } else if (current_elem) { caption += "\n"; caption += Game::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", Game::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 = Game::GetText("MapView.title.Sector"); caption += " "; caption += rgn->Name(); if (current_ship) { caption += "\n"; caption += Game::GetText("MapView.title.Ship"); caption += " "; caption += current_ship->Name(); } else if (current_elem) { caption += "\n"; caption += Game::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", Game::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", Game::GetText(Text("MapView.item.") + Instruction::ActionName(navpt->Action())).data(), navpt->TargetName()); window->Print(x2+3, y1+10, buf); } else { sprintf_s(buf, "%s", Game::GetText(Text("MapView.item.") + Instruction::ActionName(navpt->Action())).data()); window->Print(x2+3, y1+10, buf); } sprintf_s(buf, "%s", Game::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", Game::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() { EventDispatch* dispatch = EventDispatch::GetInstance(); if (dispatch) dispatch->Register(this); } void MapView::OnHide() { EventDispatch* dispatch = EventDispatch::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) { EventTarget* test = 0; EventDispatch* dispatch = EventDispatch::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); }