From 3c487c5cd69c53d6fea948643c0a76df03516605 Mon Sep 17 00:00:00 2001 From: Aki Date: Fri, 1 Apr 2022 21:23:39 +0200 Subject: Moved Stars45 to StarsEx --- StarsEx/MapView.cpp | 3482 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3482 insertions(+) create mode 100644 StarsEx/MapView.cpp (limited to 'StarsEx/MapView.cpp') diff --git a/StarsEx/MapView.cpp b/StarsEx/MapView.cpp new file mode 100644 index 0000000..dc992d1 --- /dev/null +++ b/StarsEx/MapView.cpp @@ -0,0 +1,3482 @@ +/* Starshatter: The Open Source Project + Copyright (c) 2021-2022, 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 "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 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() +{ + 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(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() +{ + 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); +} + + -- cgit v1.1