Add HyperJump Planner to Sector Map
Hyperjump Planner also includes an 'auto-route' feature that selects the shortest duration route based on Dijkstra's algorithm. Changes in addition to the hyperjump planner: Reduced font size (declutters the sector map) Expose ui.isItemClicked Added a yellow line to the sector map for the selected route Reduced the squares in the 'far' sector map to 0.25 size Reduced alpha of the squares in the 'far' sector mapmaster
parent
d1aff68405
commit
9d09681980
|
@ -4,14 +4,14 @@
|
|||
"faces" : [
|
||||
{
|
||||
"fontFile" : "PionilliumText22L-Medium.ttf",
|
||||
"pixelWidth" : 14,
|
||||
"pixelHeight" : 14,
|
||||
"pixelWidth" : 11,
|
||||
"pixelHeight" : 11,
|
||||
"advanceXAdjustment" : -1
|
||||
},
|
||||
{
|
||||
"fontFile" : "DejaVuSans.ttf",
|
||||
"pixelWidth" : 14,
|
||||
"pixelHeight" : 14,
|
||||
"pixelWidth" : 11,
|
||||
"pixelHeight" : 11,
|
||||
"advanceXAdjustment" : -1,
|
||||
"ranges" : [
|
||||
[ "0x0400", "0x04FF" ],
|
||||
|
@ -24,8 +24,8 @@
|
|||
},
|
||||
{
|
||||
"fontFile" : "wqy-microhei.ttc",
|
||||
"pixelWidth" : 14,
|
||||
"pixelHeight" : 14,
|
||||
"pixelWidth" : 11,
|
||||
"pixelHeight" : 11,
|
||||
"ranges" : [
|
||||
[ "0x4E00", "0x9FFF" ],
|
||||
[ "0x3400", "0x4DFF" ],
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
local Engine = import('Engine')
|
||||
local Game = import('Game')
|
||||
local ui = import('pigui/pigui.lua')
|
||||
local Vector = import('Vector')
|
||||
local Event = import('Event')
|
||||
local Lang = import("Lang")
|
||||
local lc = Lang.GetResource("core")
|
||||
local Equipment = import("Equipment")
|
||||
|
||||
local player = nil
|
||||
local colors = ui.theme.colors
|
||||
local icons = ui.theme.icons
|
||||
|
||||
local mainButtonSize = Vector(24,24) * (ui.screenHeight / 1200)
|
||||
local mainButtonFramePadding = 3
|
||||
|
||||
-- hyperjump route stuff
|
||||
local hyperjump_route = {}
|
||||
local route_jumps = 0
|
||||
local auto_route_min_jump = 2 -- minimum jump distance when auto routing
|
||||
local current_system
|
||||
local current_path
|
||||
local map_selected_path
|
||||
local selected_jump
|
||||
local current_fuel
|
||||
local remove_first_if_current = true
|
||||
|
||||
local function showSettings()
|
||||
if ui.collapsingHeader("Settings", {"DefaultOpen"}) then
|
||||
local changed
|
||||
changed, remove_first_if_current = ui.checkbox("Remove jump when completed", remove_first_if_current)
|
||||
end
|
||||
end -- showSettings
|
||||
|
||||
local function showJumpData(start, target, status, distance, fuel, duration, short)
|
||||
--local color = status == "OK" and colors.white or colors.alertRed -- TODO: dedicated colors?
|
||||
local color = colors.white
|
||||
if short then
|
||||
ui.withStyleColors({["Text"] = color}, function()
|
||||
|
||||
ui.text(target:GetStarSystem().name)
|
||||
ui.sameLine()
|
||||
ui.text("("..fuel .. lc.UNIT_TONNES..")")
|
||||
end)
|
||||
else
|
||||
ui.withStyleColors({["Text"] = color}, function()
|
||||
ui.text(start:GetStarSystem().name)
|
||||
ui.sameLine()
|
||||
ui.text("->")
|
||||
ui.sameLine()
|
||||
ui.text(target:GetStarSystem().name)
|
||||
ui.sameLine()
|
||||
ui.text(":")
|
||||
ui.sameLine()
|
||||
ui.text(string.format("%.2f", distance) .. lc.UNIT_LY)
|
||||
ui.sameLine()
|
||||
ui.text(fuel .. lc.UNIT_TONNES)
|
||||
ui.sameLine()
|
||||
ui.text(ui.Format.Duration(duration, 2))
|
||||
end)
|
||||
end
|
||||
end -- showJumpData
|
||||
|
||||
local function showInfo()
|
||||
if ui.collapsingHeader("Route Info",{"DefaultOpen"}) then
|
||||
local total_fuel = 0
|
||||
local total_duration = 0
|
||||
local total_distance = 0
|
||||
|
||||
local start = current_path
|
||||
-- Tally up totals for the entire jump plan
|
||||
for _,jump in pairs(hyperjump_route) do
|
||||
local status, distance, fuel, duration = player:GetHyperspaceDetails(start, jump)
|
||||
|
||||
total_fuel = total_fuel + fuel
|
||||
total_duration = total_duration + duration
|
||||
total_distance = total_distance + distance
|
||||
|
||||
start = jump
|
||||
end
|
||||
|
||||
ui.text("Current System: " .. current_system.name .. " (" .. current_path.sectorX .. "," .. current_path.sectorY .. "," .. current_path.sectorZ ..")")
|
||||
ui.text("Final Target:")
|
||||
|
||||
if route_jumps > 0 then
|
||||
local final_path = hyperjump_route[route_jumps]
|
||||
local final_sys = final_path:GetStarSystem()
|
||||
ui.sameLine()
|
||||
ui.text(final_sys.name .. " (" .. final_path.sectorX .. "," .. final_path.sectorY .. "," .. final_path.sectorZ .. ")")
|
||||
end
|
||||
ui.text("Current Fuel: " .. current_fuel .. lc.UNIT_TONNES)
|
||||
ui.sameLine()
|
||||
ui.text("Required Fuel: " .. total_fuel .. lc.UNIT_TONNES)
|
||||
|
||||
ui.text("Total Duration: "..ui.Format.Duration(total_duration, 2))
|
||||
ui.sameLine()
|
||||
ui.text("Total Distance: " ..string.format("%.2f", total_distance) .. lc.UNIT_LY)
|
||||
end
|
||||
end -- showInfo
|
||||
|
||||
local function mainButton(icon, tooltip, callback)
|
||||
local button = ui.coloredSelectedIconButton(icon, mainButtonSize, false, mainButtonFramePadding, colors.buttonBlue, colors.white, tooltip)
|
||||
if button then
|
||||
callback()
|
||||
end
|
||||
return button
|
||||
end --mainButton
|
||||
|
||||
local function showJumpRoute()
|
||||
if ui.collapsingHeader("Route Jumps", {"DefaultOpen"}) then
|
||||
mainButton(icons.forward, "Add Jump",
|
||||
function()
|
||||
Engine.SectorMapAddToRoute(map_selected_path)
|
||||
end)
|
||||
ui.sameLine()
|
||||
|
||||
mainButton(icons.current_line, "Remove Jump",
|
||||
function()
|
||||
local new_route = {}
|
||||
local new_count = 0
|
||||
if selected_jump then
|
||||
Engine.SectorMapRemoveRouteItem(selected_jump)
|
||||
end
|
||||
end)
|
||||
ui.sameLine()
|
||||
|
||||
mainButton(icons.current_periapsis, "Move Up",
|
||||
function()
|
||||
if selected_jump then
|
||||
if Engine.SectorMapMoveRouteItemUp(selected_jump) then
|
||||
selected_jump = selected_jump - 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
ui.sameLine()
|
||||
|
||||
mainButton(icons.current_apoapsis, "Move Down",
|
||||
function()
|
||||
if selected_jump then
|
||||
if Engine.SectorMapMoveRouteItemDown(selected_jump) then
|
||||
selected_jump = selected_jump + 1
|
||||
end
|
||||
end
|
||||
end)
|
||||
ui.sameLine()
|
||||
|
||||
mainButton(icons.retrograde_thin, "Clear Route",
|
||||
function()
|
||||
Engine.SectorMapClearRoute()
|
||||
selected_jump = nil
|
||||
end)
|
||||
ui.sameLine()
|
||||
|
||||
mainButton(icons.hyperspace, "Auto Route",
|
||||
function()
|
||||
Engine.SectorMapAutoRoute()
|
||||
|
||||
end)
|
||||
ui.sameLine()
|
||||
|
||||
mainButton(icons.search_lens, "Zoom to System",
|
||||
function()
|
||||
if selected_jump then
|
||||
Engine.SectorMapGotoSystemPath(hyperjump_route[selected_jump])
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
ui.separator()
|
||||
|
||||
local start = current_path
|
||||
local clicked
|
||||
local running_fuel = 0
|
||||
for jumpIndex, jump in pairs(hyperjump_route) do
|
||||
local jump_sys = jump:GetStarSystem()
|
||||
local status, distance, fuel, duration = player:GetHyperspaceDetails(start, jump)
|
||||
local color
|
||||
local remaining_fuel = current_fuel - running_fuel - fuel
|
||||
|
||||
if remaining_fuel == 0 then
|
||||
color = colors.alertYellow
|
||||
else
|
||||
if remaining_fuel < 0 then
|
||||
color = colors.alertRed
|
||||
else
|
||||
color = colors.white
|
||||
end
|
||||
end
|
||||
|
||||
ui.withStyleColors({["Text"] = color},
|
||||
function()
|
||||
if ui.selectable(jumpIndex..": ".. jump_sys.name .. " (" .. string.format("%.2f", distance) .. lc.UNIT_LY .. " - " .. fuel .. lc.UNIT_TONNES..")", jumpIndex == selected_jump, {}) then
|
||||
clicked = jumpIndex
|
||||
end
|
||||
end)
|
||||
running_fuel = fuel + running_fuel
|
||||
start = jump
|
||||
end
|
||||
|
||||
if clicked then
|
||||
selected_jump = clicked
|
||||
end
|
||||
end
|
||||
end -- showJumpPlan
|
||||
|
||||
|
||||
|
||||
local function showHyperJumpPlannerWindow()
|
||||
ui.setNextWindowSize(Vector(ui.screenWidth / 5, (ui.screenHeight / 5) * 2), "Always")
|
||||
ui.setNextWindowPos(Vector(ui.screenWidth - ui.screenWidth / 5 - 10, ui.screenHeight - ((ui.screenHeight / 5) * 2) - 10), "Always")
|
||||
ui.withStyleColors({["WindowBg"] = colors.lightBlackBackground}, function()
|
||||
ui.window("MapSectorViewHyperJumpPlanner", {"NoTitleBar", "NoResize", "NoFocusOnAppearing", "NoBringToFrontOnFocus"},
|
||||
function()
|
||||
ui.text("HyperJump Route")
|
||||
ui.separator()
|
||||
showInfo()
|
||||
ui.separator()
|
||||
showJumpRoute()
|
||||
ui.separator()
|
||||
showSettings()
|
||||
end)
|
||||
end)
|
||||
end -- showHyperJumpPlannerWindow
|
||||
|
||||
|
||||
local function displayHyperJumpPlanner()
|
||||
player = Game.player
|
||||
current_system = Game.system
|
||||
current_path = current_system.path
|
||||
|
||||
current_fuel = player:CountEquip(Equipment.cargo.hydrogen,"cargo")
|
||||
|
||||
local current_view = Game.CurrentView()
|
||||
|
||||
if current_view == "sector" then
|
||||
map_selected_path = Engine.GetSectorMapSelectedSystemPath()
|
||||
hyperjump_route = Engine.SectorMapGetRoute()
|
||||
route_jumps = Engine.SectorMapGetRouteSize()
|
||||
showHyperJumpPlannerWindow()
|
||||
end
|
||||
end -- displayHyperJumpPlanner
|
||||
|
||||
ui.registerModule("game", displayHyperJumpPlanner)
|
||||
|
||||
Event.Register("onEnterSystem",
|
||||
function(ship)
|
||||
-- remove the first jump if it's the current system (and enabled to do so)
|
||||
-- this should be the case if you are following a route and want the route to be
|
||||
-- updated as you make multiple jumps
|
||||
if ship:IsPlayer() and remove_first_if_current then
|
||||
if route_jumps > 0 and hyperjump_route[1]:IsSameSystem(Game.system.path) then
|
||||
Engine.SectorMapRemoveRouteItem(1)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Event.Register("onGameEnd",
|
||||
function(ship)
|
||||
-- clear the route out so it doesn't show up if the user starts a new game
|
||||
Engine.SectorMapClearRoute()
|
||||
end)
|
||||
return {}
|
|
@ -522,6 +522,7 @@ ui.isKeyReleased = pigui.IsKeyReleased
|
|||
ui.playSfx = pigui.PlaySfx
|
||||
ui.isItemHovered = pigui.IsItemHovered
|
||||
ui.isItemActive = pigui.IsItemActive
|
||||
ui.isItemClicked = pigui.IsItemClicked
|
||||
ui.ctrlHeld = function() return pigui.key_ctrl end
|
||||
ui.altHeld = function() return pigui.key_alt end
|
||||
ui.shiftHeld = function() return pigui.key_shift end
|
||||
|
|
|
@ -1041,6 +1041,21 @@ static int l_engine_get_model(lua_State *l)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_clear_route(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
sv->ClearRoute();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_add_to_route(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
SystemPath *path = LuaObject<SystemPath>::CheckFromLua(1);
|
||||
sv->AddToRoute(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int l_engine_get_sector_map_zoom_level(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
|
@ -1062,21 +1077,21 @@ static int l_engine_get_sector_map_center_sector(lua_State *l)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_get_sector_map_current_system_path(lua_State *l)
|
||||
static int l_engine_get_sector_map_current_system_path(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
LuaObject<SystemPath>::PushToLua(sv->GetCurrent());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_get_sector_map_selected_system_path(lua_State *l)
|
||||
static int l_engine_get_sector_map_selected_system_path(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
LuaObject<SystemPath>::PushToLua(sv->GetSelected());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_get_sector_map_hyperspace_target_system_path(lua_State *l)
|
||||
static int l_engine_get_sector_map_hyperspace_target_system_path(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
LuaObject<SystemPath>::PushToLua(sv->GetHyperspaceTarget());
|
||||
|
@ -1123,6 +1138,79 @@ static int l_engine_set_sector_map_automatic_system_selection(lua_State *l)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_get_route(lua_State *l) {
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
std::vector<SystemPath> route = sv->GetRoute();
|
||||
|
||||
lua_newtable(l);
|
||||
int i = 1;
|
||||
for (const SystemPath j : route) {
|
||||
lua_pushnumber(l, i++);
|
||||
LuaObject<SystemPath>::PushToLua(j);
|
||||
lua_settable(l, -3);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_get_route_size(lua_State *l) {
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
std::vector<SystemPath> route = sv->GetRoute();
|
||||
const int size = route.size();
|
||||
LuaPush(l, size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_auto_route(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
SystemPath current_path = sv->GetCurrent();
|
||||
SystemPath target_path = sv->GetSelected();
|
||||
|
||||
std::vector<SystemPath> route = sv->AutoRoute(current_path, target_path);
|
||||
sv->ClearRoute();
|
||||
for (auto it = route.begin(); it != route.end(); it++) {
|
||||
sv->AddToRoute(*it);
|
||||
}
|
||||
|
||||
return l_engine_sector_map_get_route(l);
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_move_route_item_up(lua_State *l) {
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
int element = LuaPull<int>(l, 1);
|
||||
|
||||
// lua indexes start at 1
|
||||
element -= 1;
|
||||
|
||||
bool r = sv->MoveRouteItemUp(element);
|
||||
LuaPush<bool>(l, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_move_route_item_down(lua_State *l) {
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
int element = LuaPull<int>(l, 1);
|
||||
|
||||
// lua indexes start at 1
|
||||
element -= 1;
|
||||
|
||||
bool r = sv->MoveRouteItemDown(element);
|
||||
LuaPush<bool>(l, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_sector_map_remove_route_item(lua_State *l) {
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
int element = LuaPull<int>(l, 1);
|
||||
|
||||
// lua indexes start at 1
|
||||
element -= 1;
|
||||
|
||||
bool r = sv->RemoveRouteItem(element);
|
||||
LuaPush<bool>(l, r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int l_engine_set_sector_map_selected(lua_State *l)
|
||||
{
|
||||
SectorView *sv = Pi::game->GetSectorView();
|
||||
|
@ -1307,6 +1395,15 @@ void LuaEngine::Register()
|
|||
{ "SectorMapGotoSystemPath", l_engine_sector_map_goto_system_path },
|
||||
{ "GetSectorMapFactions", l_engine_get_sector_map_factions },
|
||||
{ "SetSectorMapFactionVisible", l_engine_set_sector_map_faction_visible },
|
||||
{ "SectorMapAutoRoute", l_engine_sector_map_auto_route },
|
||||
{ "SectorMapGetRoute", l_engine_sector_map_get_route },
|
||||
{ "SectorMapGetRouteSize", l_engine_sector_map_get_route_size },
|
||||
{ "SectorMapMoveRouteItemUp", l_engine_sector_map_move_route_item_up },
|
||||
{ "SectorMapMoveRouteItemDown", l_engine_sector_map_move_route_item_down },
|
||||
{ "SectorMapRemoveRouteItem", l_engine_sector_map_remove_route_item },
|
||||
|
||||
{"SectorMapClearRoute", l_engine_sector_map_clear_route },
|
||||
{"SectorMapAddToRoute", l_engine_sector_map_add_to_route },
|
||||
|
||||
{ "SearchNearbyStarSystemsByName", l_engine_search_nearby_star_systems_by_name },
|
||||
|
||||
|
|
|
@ -135,6 +135,9 @@ void SectorView::InitDefaults()
|
|||
m_cacheYMax = 0;
|
||||
|
||||
m_sectorCache = m_galaxy->NewSectorSlaveCache();
|
||||
|
||||
m_drawRouteLines = true; // where should this go?!
|
||||
m_route = std::vector<SystemPath>();
|
||||
}
|
||||
|
||||
void SectorView::InitObject()
|
||||
|
@ -239,6 +242,10 @@ void SectorView::Draw3D()
|
|||
modelview.Translate(-FFRAC(m_pos.x)*Sector::SIZE, -FFRAC(m_pos.y)*Sector::SIZE, -FFRAC(m_pos.z)*Sector::SIZE);
|
||||
m_renderer->SetTransform(modelview);
|
||||
|
||||
RefCountedPtr<const Sector> playerSec = GetCached(m_current);
|
||||
const vector3f playerPos = Sector::SIZE * vector3f(float(m_current.sectorX), float(m_current.sectorY), float(m_current.sectorZ)) + playerSec->m_systems[m_current.systemIndex].GetPosition();
|
||||
|
||||
|
||||
if (m_zoomClamped <= FAR_THRESHOLD)
|
||||
DrawNearSectors(modelview);
|
||||
else
|
||||
|
@ -261,6 +268,15 @@ void SectorView::Draw3D()
|
|||
m_sectorlines.Draw(m_renderer, m_alphaBlendState);
|
||||
}
|
||||
|
||||
// not quite the same as modelview
|
||||
matrix4x4f trans = matrix4x4f::Identity();
|
||||
trans.Translate(0.f, 0.f, -10.f - 10.f*m_zoom);
|
||||
trans.Rotate(DEG2RAD(m_rotX), 1.f, 0.f, 0.f);
|
||||
trans.Rotate(DEG2RAD(m_rotZ), 0.f, 0.f, 1.f);
|
||||
trans.Translate(-(m_pos.x)*Sector::SIZE, -(m_pos.y)*Sector::SIZE, -(m_pos.z)*Sector::SIZE);
|
||||
|
||||
DrawRouteLines(playerPos, trans);
|
||||
|
||||
UIView::Draw3D();
|
||||
}
|
||||
|
||||
|
@ -507,6 +523,7 @@ void SectorView::DrawNearSectors(const matrix4x4f& modelview)
|
|||
RefCountedPtr<const Sector> playerSec = GetCached(m_current);
|
||||
const vector3f playerPos = Sector::SIZE * vector3f(float(m_current.sectorX), float(m_current.sectorY), float(m_current.sectorZ)) + playerSec->m_systems[m_current.systemIndex].GetPosition();
|
||||
|
||||
|
||||
for (int sx = -DRAW_RAD; sx <= DRAW_RAD; sx++) {
|
||||
for (int sy = -DRAW_RAD; sy <= DRAW_RAD; sy++) {
|
||||
for (int sz = -DRAW_RAD; sz <= DRAW_RAD; sz++) {
|
||||
|
@ -532,6 +549,185 @@ void SectorView::DrawNearSectors(const matrix4x4f& modelview)
|
|||
Gui::Screen::LeaveOrtho();
|
||||
}
|
||||
|
||||
bool SectorView::MoveRouteItemUp(const std::vector<SystemPath>::size_type element) {
|
||||
if (element <= 0 || element >= m_route.size()) return false;
|
||||
|
||||
std::swap(m_route[element - 1], m_route[element]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SectorView::MoveRouteItemDown(const std::vector<SystemPath>::size_type element) {
|
||||
if (element < 0 || element >= m_route.size() - 1) return false;
|
||||
|
||||
std::swap(m_route[element + 1], m_route[element]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SectorView::AddToRoute(const SystemPath &path)
|
||||
{
|
||||
m_route.push_back(path);
|
||||
}
|
||||
|
||||
bool SectorView::RemoveRouteItem(const std::vector<SystemPath>::size_type element) {
|
||||
m_route.erase(m_route.begin() + element);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SectorView::ClearRoute()
|
||||
{
|
||||
m_route.clear();
|
||||
}
|
||||
|
||||
std::vector<SystemPath> SectorView::GetRoute()
|
||||
{
|
||||
return m_route;
|
||||
}
|
||||
|
||||
std::vector<SystemPath> SectorView::AutoRoute(const SystemPath &start, const SystemPath &target)
|
||||
{
|
||||
RefCountedPtr<const Sector> start_sec = m_galaxy->GetSector(start);
|
||||
RefCountedPtr<const Sector> target_sec = m_galaxy->GetSector(target);
|
||||
|
||||
// Get the player's hyperdrive from Lua, later used to calculate the duration between systems
|
||||
ScopedTable hyperdrive = ScopedTable(LuaObject<Player>::CallMethod<LuaRef>(Pi::player, "GetEquip", "engine", 1));
|
||||
// Cache max range so it doesn't get recalculated every time we call GetDuration
|
||||
float max_range = hyperdrive.CallMethod<float>("GetMaximumRange", Pi::player);
|
||||
|
||||
float dist = Sector::DistanceBetween(start_sec, start.systemIndex, target_sec, target.systemIndex);
|
||||
|
||||
int sec_dist = ceilf(dist / Sector::SIZE);
|
||||
|
||||
std::vector<SystemPath> nodes;
|
||||
std::set<std::vector<SystemPath>::size_type> unvisited;
|
||||
|
||||
std::vector<float> path_dist; // distance from source to node
|
||||
std::vector<std::vector<SystemPath>::size_type> path_prev; // previous node in optimal path
|
||||
|
||||
// nodes[0] is always start
|
||||
nodes.push_back(start);
|
||||
|
||||
// go sector by sector for sec_dist sectors and add systems
|
||||
// if they are within 110% of dist of both start and target
|
||||
for (Sint32 sx = -sec_dist; sx <= sec_dist; sx++) {
|
||||
for (Sint32 sy = -sec_dist; sy <= sec_dist; sy++) {
|
||||
for (Sint32 sz = -sec_dist; sz < sec_dist; sz++) {
|
||||
SystemPath sec_path = SystemPath(start.sectorX + sx, start.sectorY + sy, start.sectorZ + sz);
|
||||
RefCountedPtr<const Sector> sec = m_galaxy->GetSector(sec_path);
|
||||
for (std::vector<Sector::System>::size_type s = 0; s < sec->m_systems.size(); s++) {
|
||||
if (start.IsSameSystem(sec->m_systems[s].GetPath())) continue; // start is already nodes[0]
|
||||
if (Sector::DistanceBetween(start_sec, start.systemIndex, sec, sec->m_systems[s].idx) <= dist * 1.10 &&
|
||||
Sector::DistanceBetween(target_sec, target.systemIndex, sec, sec->m_systems[s].idx) <= dist * 1.10) {
|
||||
nodes.push_back(sec->m_systems[s].GetPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup inital values and set everything as unvisited
|
||||
for (std::vector<SystemPath>::size_type i = 0; i < nodes.size(); i++) {
|
||||
path_dist.push_back(INFINITY);
|
||||
path_prev.push_back(0);
|
||||
unvisited.insert(i);
|
||||
}
|
||||
|
||||
// distance to the start is 0
|
||||
path_dist[0] = 0.f;
|
||||
|
||||
while (unvisited.size() > 0) {
|
||||
// find the closest node (for the first loop this will be start)
|
||||
std::vector<SystemPath>::size_type closest_i = *unvisited.begin();
|
||||
for (auto it = unvisited.begin(); it != unvisited.end(); it++) {
|
||||
if (path_dist[*it] < path_dist[closest_i]) closest_i = *it;
|
||||
}
|
||||
SystemPath closest = nodes[closest_i];
|
||||
RefCountedPtr<const Sector> closest_sec = m_galaxy->GetSector(closest);
|
||||
|
||||
// mark it as visited
|
||||
unvisited.erase(closest_i);
|
||||
|
||||
// if this is the target then we have found the route
|
||||
if (closest.IsSameSystem(target)) break;
|
||||
|
||||
// if not, loop through all unvisited nodes
|
||||
// since every system is technically reachable from every other system
|
||||
// everything is a neighbor :)
|
||||
for (auto it = unvisited.begin(); it != unvisited.end(); it++) {
|
||||
SystemPath v = nodes[*it];
|
||||
RefCountedPtr<const Sector> v_sec = m_galaxy->GetSector(v);
|
||||
|
||||
float v_dist_ly = 0;
|
||||
v_dist_ly = Sector::DistanceBetween(closest_sec, closest.systemIndex, v_sec, v.systemIndex);
|
||||
|
||||
// in this case, duration is used for the distance since that's what we are optimizing
|
||||
float v_dist = hyperdrive.CallMethod<float>("GetDuration", Pi::player, v_dist_ly, max_range);
|
||||
|
||||
v_dist += path_dist[closest_i]; // we want the total duration from start to this node
|
||||
if (v_dist < path_dist[*it]) {
|
||||
// if our calculated duration is less than a previous value, this path is more efficent
|
||||
// so store/override it
|
||||
path_dist[*it] = v_dist;
|
||||
path_prev[*it] = closest_i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SystemPath> route;
|
||||
std::vector<SystemPath>::size_type u;
|
||||
|
||||
// find the index of our target
|
||||
for (std::vector<SystemPath>::size_type i = 0; i < nodes.size(); i++) {
|
||||
if (target.IsSameSystem(nodes[i])) {
|
||||
u = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the route, in reverse starting with the target
|
||||
while (u != 0) {
|
||||
route.push_back(nodes[u]);
|
||||
u = path_prev[u];
|
||||
}
|
||||
|
||||
std::reverse(std::begin(route), std::end(route));
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
void SectorView::DrawRouteLines(const vector3f &playerAbsPos, const matrix4x4f &trans)
|
||||
{
|
||||
for (std::vector<SystemPath>::size_type i = 0; i < m_route.size(); ++i) {
|
||||
RefCountedPtr<const Sector> jumpSec = m_galaxy->GetSector(m_route[i]);
|
||||
const Sector::System& jumpSecSys = jumpSec->m_systems[m_route[i].systemIndex];
|
||||
const vector3f jumpAbsPos = Sector::SIZE*vector3f(float(jumpSec->sx), float(jumpSec->sy), float(jumpSec->sz)) + jumpSecSys.GetPosition();
|
||||
|
||||
vector3f startPos;
|
||||
if (i == 0) {
|
||||
startPos = playerAbsPos;
|
||||
} else {
|
||||
RefCountedPtr<const Sector> prevSec = m_galaxy->GetSector(m_route[i-1]);
|
||||
const Sector::System& prevSecSys = prevSec->m_systems[m_route[i-1].systemIndex];
|
||||
const vector3f prevAbsPos = Sector::SIZE*vector3f(float(prevSec->sx), float(prevSec->sy), float(prevSec->sz)) + prevSecSys.GetPosition();
|
||||
startPos = prevAbsPos;
|
||||
}
|
||||
std::unique_ptr<Graphics::VertexArray> verts;
|
||||
Graphics::Drawables::Lines lines;
|
||||
verts.reset(new Graphics::VertexArray(Graphics::ATTRIB_POSITION, 500));
|
||||
verts->Clear();
|
||||
|
||||
verts->position.reserve(2);
|
||||
verts->diffuse.reserve(2);
|
||||
|
||||
verts->Add(trans* startPos, Color(20, 20, 0, 127));
|
||||
verts->Add(trans* jumpAbsPos, Color(255, 255, 0, 255));
|
||||
|
||||
lines.SetData(verts->GetNumVerts(), &verts->position[0], &verts->diffuse[0]);
|
||||
lines.Draw(m_renderer, m_alphaBlendState);
|
||||
}
|
||||
}
|
||||
|
||||
void SectorView::DrawNearSector(const int sx, const int sy, const int sz, const vector3f &playerAbsPos,const matrix4x4f &trans)
|
||||
{
|
||||
PROFILE_SCOPED()
|
||||
|
@ -738,7 +934,7 @@ void SectorView::DrawFarSectors(const matrix4x4f& modelview)
|
|||
|
||||
// always draw the stars, slightly altering their size for different different resolutions, so they still look okay
|
||||
if (m_farstars.size() > 0) {
|
||||
m_farstarsPoints.SetData(m_renderer, m_farstars.size(), &m_farstars[0], &m_farstarsColor[0], modelview, 1.f * (Graphics::GetScreenHeight() / 720.f));
|
||||
m_farstarsPoints.SetData(m_renderer, m_farstars.size(), &m_farstars[0], &m_farstarsColor[0], modelview, 0.25f * (Graphics::GetScreenHeight() / 720.f));
|
||||
m_farstarsPoints.Draw(m_renderer, m_alphaBlendState);
|
||||
}
|
||||
|
||||
|
@ -769,7 +965,7 @@ void SectorView::BuildFarSector(RefCountedPtr<Sector> sec, const vector3f &origi
|
|||
// otherwise add the system's position (origin must be m_pos's *sector* or we get judder)
|
||||
// and faction color to the list to draw
|
||||
starColor = i->GetFaction()->colour;
|
||||
starColor.a = 191;
|
||||
starColor.a = 120;
|
||||
|
||||
points.push_back((*i).GetFullPosition() - origin);
|
||||
colors.push_back(starColor);
|
||||
|
@ -843,7 +1039,7 @@ void SectorView::Update()
|
|||
{
|
||||
PROFILE_SCOPED()
|
||||
SystemPath last_current = m_current;
|
||||
|
||||
|
||||
if (Pi::game->IsNormalSpace()) {
|
||||
m_inSystem = true;
|
||||
m_current = Pi::game->GetSpace()->GetStarSystem()->GetPath();
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
virtual void SaveToJson(Json::Value &jsonObj);
|
||||
|
||||
sigc::signal<void> onHyperspaceTargetChanged;
|
||||
|
||||
|
||||
double GetZoomLevel() const;
|
||||
void ZoomIn();
|
||||
void ZoomOut();
|
||||
|
@ -61,6 +61,18 @@ public:
|
|||
const std::set<const Faction *> &GetVisibleFactions() { return m_visibleFactions; }
|
||||
const std::set<const Faction *> &GetHiddenFactions() { return m_hiddenFactions; }
|
||||
void SetFactionVisible(const Faction *faction, bool visible);
|
||||
|
||||
// HyperJump Route Planner
|
||||
bool MoveRouteItemUp(const std::vector<SystemPath>::size_type element);
|
||||
bool MoveRouteItemDown(const std::vector<SystemPath>::size_type element);
|
||||
void AddToRoute(const SystemPath &path);
|
||||
bool RemoveRouteItem(const std::vector<SystemPath>::size_type element);
|
||||
void ClearRoute();
|
||||
std::vector<SystemPath> GetRoute();
|
||||
std::vector<SystemPath> AutoRoute(const SystemPath &start, const SystemPath &target);
|
||||
void SetDrawRouteLines(bool value) { m_drawRouteLines = value; }
|
||||
|
||||
|
||||
protected:
|
||||
virtual void OnSwitchTo();
|
||||
|
||||
|
@ -127,7 +139,7 @@ private:
|
|||
bool m_drawUninhabitedLabels;
|
||||
bool m_drawOutRangeLabels;
|
||||
bool m_drawVerticalLines;
|
||||
|
||||
|
||||
std::unique_ptr<Graphics::Drawables::Disk> m_disk;
|
||||
|
||||
Gui::LabelSet *m_clickableLabels;
|
||||
|
@ -150,6 +162,11 @@ private:
|
|||
Graphics::Drawables::Line3D m_secondLine;
|
||||
Graphics::Drawables::Line3D m_jumpLine;
|
||||
|
||||
// HyperJump Route Planner Stuff
|
||||
std::vector<SystemPath> m_route;
|
||||
bool m_drawRouteLines;
|
||||
void DrawRouteLines(const vector3f &playerAbsPos, const matrix4x4f &trans);
|
||||
|
||||
Graphics::RenderState *m_solidState;
|
||||
Graphics::RenderState *m_alphaBlendState;
|
||||
Graphics::RenderState *m_jumpSphereState;
|
||||
|
|
Loading…
Reference in New Issue