silentradios wrote: ↑Sun, 27. Mar 22, 14:51
Edit 3/27: Apparently Avarice V and IV were swapped (I got the friendly name mapping from reddit - not sure where a real source is) -- I confirmed in my save and two others did as well
Edit 6/2/23: Thanks jojorne for catching an issue related to the GUI for compressed saves
Here is a bat file that runs the powershell inside it (sneaky.. but effective) :
https://anechoic.space/erlkinggui.bat
It has a few features over the previous script including:
- A File selection dialog
- Support for gz / compressed saves
- GUI output of the positions
Here is the same script that you can copy and past and save into a .bat file (use notepad and save as UTF-8 or ANSI (do not select the with BOM ones) and run to avoid the prompts that you get from windows about it being safe or not..
Code: Select all
@findstr/v "^@f.*&" "%~f0"|powershell -noprofile -executionpolicy bypass -&goto:eof
#Fist line stolen from https://stackoverflow.com/a/2611394
#This uses a fair amount of memory - if you have limited ram exit X4 first...
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Messagebox]::Show("This uses a fair amount of memory - if you have limited ram exit X4 first...")
#stolen from https://4sysops.com/archives/how-to-create-an-open-file-folder-dialog-box-with-powershell/
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{
InitialDirectory = [Environment]::GetFolderPath('MyDocuments') + "\Egosoft\X4"
Filter = 'Save file (*.xml; *.xml.gz)|*.xml;*.xml.gz'
Title = "Select savegame file"
}
while([string]::IsNullOrWhiteSpace($FileBrowser.FileName)){
$null = $FileBrowser.ShowDialog()
sleep 1
}
#from https://social.technet.microsoft.com/Forums/windowsserver/en-US/5aa53fef-5229-4313-a035-8b3a38ab93f5/unzip-gz-files-using-powershell?forum=winserverpowershell
Function Expand-GZip{
Param(
$infile,
$outfile = ($infile -replace '\.gz$','')
)
$input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
$output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
$gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)
$buffer = New-Object byte[](1024)
while($true){
$read = $gzipstream.Read($buffer, 0, 1024)
if ($read -le 0){break}
$output.Write($buffer, 0, $read)
}
$gzipStream.Close()
$output.Close()
$input.Close()
}
$gzip = $false
if($FileBrowser.FileName -match "\.gz$"){
Write-Host "Extracting compressed save, this may take a while"
$gzip = $true
Expand-GZip -infile $FileBrowser.FileName
}
if($gzip) {
$file = ($FileBrowser.FileName -replace '\.gz$','')
} else {
$file = $FileBrowser.FileName
}
Write-Host "Loading XML, this may take a while and will use lots of ram"
$Xml=New-Object Xml
#unzip .gz file with 7-zip or gunzip first or use uncompressed saves
$Xml.Load($file)
Write-Host "Finding Erlking Data Vaults"
$components=Select-Xml -Xml $Xml -XPath "/savegame/universe//component"
$erl=$components | ?{$_.Node.macro -and $_.Node.macro.Contains("erlking")}
$vaults = $erl | ?{$_.Node.macro -and $_.Node.macro.Contains("landmarks_erlking_vault")}
#From hatevampire at https://www.reddit.com/r/X4Foundations/comments/thjbik/how_to_read_save_file/
#Not sure where the real source of friendlyname is..
$locationtoname = @{
cluster_500_sector001_macro="Avarice I"
cluster_500_sector002_macro="Avarice V"
cluster_500_sector003_macro="Avarice IV"
cluster_501_macro="Windfall I"
cluster_502_macro="Windfall III"
cluster_503_macro="Windfall IV"
}
$macrotocoords=@{
"Zone004_Cluster_503_Sector001_macro"="139680,0,-3215.59"
"Zone003_Cluster_500_Sector003_macro"="-115796.9,0,-96109.38"
"Zone002_Cluster_503_Sector001_macro"="-2269.199,0,165758.4"
"Zone006_Cluster_500_Sector002_macro"="-184409.83,0,-3343.0"
"Zone003_Cluster_501_Sector001_macro"="-97898.44,0,-23632.81"
"Zone003_Cluster_500_Sector001_macro"="-97898.44,0,-23632.81"
"Zone005_Cluster_501_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_504_Sector001_macro"="157616.8,0,-84263.63"
"tzoneCluster_500_Sector002SHCon9_GateZone_macro"="-39827.2,0,200000"
"tzoneCluster_500_Sector002SHCon5_GateZone_macro"="-50000,0,200000"
"Zone001_Cluster_500_Sector003_macro"="-117046.9,0,82593.75"
"Zone001_Cluster_501_Sector001_macro"="-127062.5,0,133718.8"
"Zone005_Cluster_504_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_500_Sector001_macro"="103164.1,0,-32492.19"
"Zone002_Cluster_500_Sector001_macro"="-10960.94,0,112070.3"
"Zone003_Cluster_500_Sector002_macro"="-7132.69,0,531.25"
"Zone002_Cluster_500_Sector002_macro"="-118489.4,0,-131687.5"
"tzoneCluster_500_Sector003SHCon9_GateZone_macro"="50000,0,200000"
"Zone005_Cluster_500_Sector002_macro"="98694.83,0,-126406.3"
"tzoneCluster_500_Sector001SHCon2_GateZone_macro"="66960.9,0,-207957"
"tzoneCluster_500_Sector003SHCon5_GateZone_macro"="40054.7,0,200000"
"tzoneCluster_500_Sector001SHCon10_GateZone_macro"="-45738.28,0,-200000"
"Zone005_Cluster_500_Sector003_macro"="34671.88,0,-152515.6"
"Zone001_Cluster_504_Sector001_macro"="-127062.5,0,133718.8"
"Zone003_Cluster_502_Sector001_macro"="-97898.44,0,-23632.81"
"Zone002_Cluster_504_Sector001_macro"="137904.1,0,135199.3"
"Zone005_Cluster_503_Sector001_macro"="-23023.44,0,-160132.8"
"Zone001_Cluster_500_Sector001_macro"="-127062.5,0,133718.8"
"Zone004_Cluster_501_Sector001_macro"="103164.1,0,-32492.19"
"tzoneCluster_500_Sector001SHCon4_GateZone_macro"="76886.7,0,-207957"
"Zone006_Cluster_502_Sector001_macro"="47000.0,0,172000.0"
"Zone002_Cluster_500_Sector003_macro"="44015.63,0,158125"
"tzoneCluster_500_Sector001SHCon6_GateZone_macro"="-55785.2,0,-200000"
"Zone002_Cluster_501_Sector001_macro"="-10960.94,0,112070.3"
"Zone001_Cluster_500_Sector002_macro"="-78593.63,0,157937.5"
"Zone003_Cluster_503_Sector001_macro"="-199365.3,0,-55454.45"
"Zone001_Cluster_502_Sector001_macro"="-127062.5,0,133718.8"
"Zone003_Cluster_504_Sector001_macro"="-226443.3,0,-97194.67"
"Zone005_Cluster_500_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_500_Sector003_macro"="110359.4,0,7250"
"Zone001_Cluster_503_Sector001_macro"="-190039.3,0,180073.9"
"Zone005_Cluster_502_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_500_Sector002_macro"="101721.7,0,100656.3"
"Zone002_Cluster_502_Sector001_macro"="108009.3,0,115933.7"
"Zone004_Cluster_502_Sector001_macro"="103164.1,0,-32492.19"
}
#Get offsets up the tree
function Recurse-Offsets($node){
if($node.class -and $node.class -eq "galaxy"){
return @()
}
if($node.offset -ne $null){
if($node.offset.position){
$x=$node.offset.position.x
$y=$node.offset.position.y
$z=$node.offset.position.z
} else {
$x,$y,$z=0,0,0
}
if($node.offset.rotation){
if($node.offset.rotation.yaw){$yaw=$node.offset.rotation.yaw} else {$yaw=0}
if($node.offset.rotation.pitch){$pitch=$node.offset.rotation.pitch} else {$pitch=0}
if($node.offset.rotation.roll){$roll=$node.offset.rotation.roll} else {$roll=0}
} else {
$pitch,$roll,$yaw=0,0,0
}
if($macrotocoords[$node.macro]){
$x,$y,$z=$macrotocoords[$node.macro].Split(",")
}
$obj = [pscustomobject]@{
x=$x
y=$y
z=$z
pitch=$pitch
roll=$roll
yaw=$yaw
code=$node.code
macro=$node.macro
class=$node.class
}
return @($obj) + (Recurse-Offsets -node $node.ParentNode)
} else {
return Recurse-Offsets -node $node.ParentNode
}
}
$data=. {
foreach($vault in $vaults){
$data=Recurse-Offsets $vault.Node
$sums = $data | Measure-Object -Sum -Property x,y,z
$location = $data |?{$_.class -eq "sector"} | select -ExpandProperty macro
if([string]::IsNullOrWhiteSpace($location)){
$location = $data |?{$_.class -eq "cluster"} | select -ExpandProperty macro
}
[pscustomobject]@{
location=$locationtoname[$location]
Xkm=($sums |?{$_.property -eq "x"}).sum/1000
Ykm=($sums |?{$_.property -eq "y"}).sum/1000
Zkm=($sums |?{$_.property -eq "z"}).sum/1000
blueprint=$vault.Node.connections.connection.component.blueprints |?{$_ -ne $null}
vault=$vault.Node.macro
code=$vault.Node.code
}
}
}
$data | ft -AutoSize
$data | Out-GridView
if($gzip){
if([System.Windows.Forms.MessageBox]::Show("Remove the extracted save $file" , "Remove Save?" , 4, 64) -eq "Yes"){
Remove-Item -Path $file
}
}
[System.Windows.Forms.Messagebox]::Show("Done, you can copy out of the cmd window or grid view before closing this if you want.")
<#
#Some other useful snippets
#detailed output
. {
foreach($vault in $vaults){
Recurse-Offsets $vault.Node
"-----"
}
} | ft -AutoSize
#parse out zone info
$zoneinfo = [xml](gc c:\path\to\dlc_pirate_sectors.xml)
$hash = @{}
$zoneinfo.macros.macro | %{
$_.connections.connection | %{
$hash += @{$_.macro.ref = $_.offset.position }
}
}
# Generate a powershell hash for the above xml and put it on the clipboard
"@{`n" + ($hash.GetEnumerator() |%{" `"$($_.key)`"=`"$(@($_.value.x,$_.value.y,$_.value.z) -join ",")`"`n"}) + "}" | clip
$components=Select-Xml -Xml $Xml -XPath "/savegame/universe//component"
# Get all classes
$components.Node.class | select -Unique | sort
order of map related:
galaxy
cluster
sector
zone
#>
So I really wanted an easier way to display this
Code: Select all
@findstr/v "^@f.*&" "%~f0"|powershell -noprofile -executionpolicy bypass -&goto:eof
#Fist line stolen from https://stackoverflow.com/a/2611394
#This uses a fair amount of memory - if you have limited ram exit X4 first...
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Messagebox]::Show("This uses a fair amount of memory - if you have limited ram exit X4 first...")
#stolen from https://4sysops.com/archives/how-to-create-an-open-file-folder-dialog-box-with-powershell/
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{
InitialDirectory = [Environment]::GetFolderPath('MyDocuments') + "\Egosoft\X4"
Filter = 'Save file (*.xml; *.xml.gz)|*.xml;*.xml.gz'
Title = "Select savegame file"
}
while([string]::IsNullOrWhiteSpace($FileBrowser.FileName)){
$null = $FileBrowser.ShowDialog()
sleep 1
}
#from https://social.technet.microsoft.com/Forums/windowsserver/en-US/5aa53fef-5229-4313-a035-8b3a38ab93f5/unzip-gz-files-using-powershell?forum=winserverpowershell
Function Expand-GZip{
Param(
$infile,
$outfile = ($infile -replace '\.gz$','')
)
$input = New-Object System.IO.FileStream $inFile, ([IO.FileMode]::Open), ([IO.FileAccess]::Read), ([IO.FileShare]::Read)
$output = New-Object System.IO.FileStream $outFile, ([IO.FileMode]::Create), ([IO.FileAccess]::Write), ([IO.FileShare]::None)
$gzipStream = New-Object System.IO.Compression.GzipStream $input, ([IO.Compression.CompressionMode]::Decompress)
$buffer = New-Object byte[](1024)
while($true){
$read = $gzipstream.Read($buffer, 0, 1024)
if ($read -le 0){break}
$output.Write($buffer, 0, $read)
}
$gzipStream.Close()
$output.Close()
$input.Close()
}
$gzip = $false
if($FileBrowser.FileName -match "\.gz$"){
Write-Host "Extracting compressed save, this may take a while"
$gzip = $true
Expand-GZip -infile $FileBrowser.FileName
}
if($gzip) {
$file = ($FileBrowser.FileName -replace '\.gz$','')
} else {
$file = $FileBrowser.FileName
}
Write-Host "Loading XML, this may take a while and will use lots of ram"
$Xml=New-Object Xml
#unzip .gz file with 7-zip or gunzip first or use uncompressed saves
$Xml.Load($file)
Write-Host "Finding Erlking Data Vaults"
$components=Select-Xml -Xml $Xml -XPath "/savegame/universe//component"
$erl=$components | ?{$_.Node.macro -and $_.Node.macro.Contains("erlking")}
$vaults = $erl | ?{$_.Node.macro -and $_.Node.macro.Contains("landmarks_erlking_vault")}
#From hatevampire at https://www.reddit.com/r/X4Foundations/comments/thjbik/how_to_read_save_file/
#Not sure where the real source of friendlyname is..
$locationtoname = @{
cluster_500_sector001_macro="Avarice I"
cluster_500_sector002_macro="Avarice V"
cluster_500_sector003_macro="Avarice IV"
cluster_501_macro="Windfall I"
cluster_502_macro="Windfall III"
cluster_503_macro="Windfall IV"
}
$macrotocoords=@{
"Zone004_Cluster_503_Sector001_macro"="139680,0,-3215.59"
"Zone003_Cluster_500_Sector003_macro"="-115796.9,0,-96109.38"
"Zone002_Cluster_503_Sector001_macro"="-2269.199,0,165758.4"
"Zone006_Cluster_500_Sector002_macro"="-184409.83,0,-3343.0"
"Zone003_Cluster_501_Sector001_macro"="-97898.44,0,-23632.81"
"Zone003_Cluster_500_Sector001_macro"="-97898.44,0,-23632.81"
"Zone005_Cluster_501_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_504_Sector001_macro"="157616.8,0,-84263.63"
"tzoneCluster_500_Sector002SHCon9_GateZone_macro"="-39827.2,0,200000"
"tzoneCluster_500_Sector002SHCon5_GateZone_macro"="-50000,0,200000"
"Zone001_Cluster_500_Sector003_macro"="-117046.9,0,82593.75"
"Zone001_Cluster_501_Sector001_macro"="-127062.5,0,133718.8"
"Zone005_Cluster_504_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_500_Sector001_macro"="103164.1,0,-32492.19"
"Zone002_Cluster_500_Sector001_macro"="-10960.94,0,112070.3"
"Zone003_Cluster_500_Sector002_macro"="-7132.69,0,531.25"
"Zone002_Cluster_500_Sector002_macro"="-118489.4,0,-131687.5"
"tzoneCluster_500_Sector003SHCon9_GateZone_macro"="50000,0,200000"
"Zone005_Cluster_500_Sector002_macro"="98694.83,0,-126406.3"
"tzoneCluster_500_Sector001SHCon2_GateZone_macro"="66960.9,0,-207957"
"tzoneCluster_500_Sector003SHCon5_GateZone_macro"="40054.7,0,200000"
"tzoneCluster_500_Sector001SHCon10_GateZone_macro"="-45738.28,0,-200000"
"Zone005_Cluster_500_Sector003_macro"="34671.88,0,-152515.6"
"Zone001_Cluster_504_Sector001_macro"="-127062.5,0,133718.8"
"Zone003_Cluster_502_Sector001_macro"="-97898.44,0,-23632.81"
"Zone002_Cluster_504_Sector001_macro"="137904.1,0,135199.3"
"Zone005_Cluster_503_Sector001_macro"="-23023.44,0,-160132.8"
"Zone001_Cluster_500_Sector001_macro"="-127062.5,0,133718.8"
"Zone004_Cluster_501_Sector001_macro"="103164.1,0,-32492.19"
"tzoneCluster_500_Sector001SHCon4_GateZone_macro"="76886.7,0,-207957"
"Zone006_Cluster_502_Sector001_macro"="47000.0,0,172000.0"
"Zone002_Cluster_500_Sector003_macro"="44015.63,0,158125"
"tzoneCluster_500_Sector001SHCon6_GateZone_macro"="-55785.2,0,-200000"
"Zone002_Cluster_501_Sector001_macro"="-10960.94,0,112070.3"
"Zone001_Cluster_500_Sector002_macro"="-78593.63,0,157937.5"
"Zone003_Cluster_503_Sector001_macro"="-199365.3,0,-55454.45"
"Zone001_Cluster_502_Sector001_macro"="-127062.5,0,133718.8"
"Zone003_Cluster_504_Sector001_macro"="-226443.3,0,-97194.67"
"Zone005_Cluster_500_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_500_Sector003_macro"="110359.4,0,7250"
"Zone001_Cluster_503_Sector001_macro"="-190039.3,0,180073.9"
"Zone005_Cluster_502_Sector001_macro"="-23023.44,0,-160132.8"
"Zone004_Cluster_500_Sector002_macro"="101721.7,0,100656.3"
"Zone002_Cluster_502_Sector001_macro"="108009.3,0,115933.7"
"Zone004_Cluster_502_Sector001_macro"="103164.1,0,-32492.19"
}
#Get offsets up the tree
function Recurse-Offsets($node){
if($node.class -and $node.class -eq "galaxy"){
return @()
}
if($node.offset -ne $null){
if($node.offset.position){
$x=$node.offset.position.x
$y=$node.offset.position.y
$z=$node.offset.position.z
} else {
$x,$y,$z=0,0,0
}
if($node.offset.rotation){
if($node.offset.rotation.yaw){$yaw=$node.offset.rotation.yaw} else {$yaw=0}
if($node.offset.rotation.pitch){$pitch=$node.offset.rotation.pitch} else {$pitch=0}
if($node.offset.rotation.roll){$roll=$node.offset.rotation.roll} else {$roll=0}
} else {
$pitch,$roll,$yaw=0,0,0
}
if($macrotocoords[$node.macro]){
$x,$y,$z=$macrotocoords[$node.macro].Split(",")
}
$obj = [pscustomobject]@{
x=$x
y=$y
z=$z
pitch=$pitch
roll=$roll
yaw=$yaw
code=$node.code
macro=$node.macro
class=$node.class
}
return @($obj) + (Recurse-Offsets -node $node.ParentNode)
} else {
return Recurse-Offsets -node $node.ParentNode
}
}
$data=. {
foreach($vault in $vaults){
$data=Recurse-Offsets $vault.Node
$sums = $data | Measure-Object -Sum -Property x,y,z
$location = $data |?{$_.class -eq "sector"} | select -ExpandProperty macro
if([string]::IsNullOrWhiteSpace($location)){
$location = $data |?{$_.class -eq "cluster"} | select -ExpandProperty macro
}
[pscustomobject]@{
location=$locationtoname[$location]
Xkm=($sums |?{$_.property -eq "x"}).sum/1000
Ykm=($sums |?{$_.property -eq "y"}).sum/1000
Zkm=($sums |?{$_.property -eq "z"}).sum/1000
blueprint=$vault.Node.connections.connection.component.blueprints |?{$_ -ne $null}
vault=$vault.Node.macro
code=$vault.Node.code
}
}
}
$data | ft -AutoSize
$data | Out-GridView
if($gzip){
if([System.Windows.Forms.MessageBox]::Show("Remove the extracted save $file" , "Remove Save?" , 4, 64) -eq "Yes"){
Remove-Item -Path $file
}
}
# === DISPLAY GRID CONFIGURATION ===
$GridSize = 21 # Must be odd to center (e.g., 21 = -10 to 10)
$CellSize = 10 # km per grid cell
$Half = [math]::Floor($GridSize / 2)
# === INIT GRID === (correct 2D char array)
$grid = @()
for ($y = 0; $y -lt $GridSize; $y++) {
$row = @()
for ($x = 0; $x -lt $GridSize; $x++) {
$row += '.'
}
$grid += ,$row
}
$legend = @()
## === DISPLAY INDIVIDUAL MAPS PER VAULT ===
$GridSize = 21 # Must be odd to center (e.g., 21 = -10 to 10)
$CellSize = 10 # km per grid cell
$Half = [math]::Floor($GridSize / 2)
function Get-BlueprintName($bp) {
if (-not $bp) { return "(None)" }
if ($bp -match "turret_pir_m_battleship_01_gatling") { return "Erlking Medium Turret Gatling" }
elseif ($bp -match "engine_pir") { return "XL Engines Erlking" }
elseif ($bp -match "turret_pir_l") { return "Erlking L Laser Turret" }
elseif ($bp -match "shield_pir_xl") { return "XL Shield Erlking" }
elseif ($bp -match "weapon_pir_xl") { return "Erlking Primary Weapon" }
else { return $bp }
}
foreach ($v in $data) {
Write-Host ""
Write-Host "Vault XY Map Grid (X axis, Y axis) each 'cell' = ${CellSize}km" -ForegroundColor Cyan
Write-Host "Origin (0,0) at center. 'V' = Vault: $($v.Location)" -ForegroundColor DarkGray
Write-Host ""
# Init grid
$grid = @()
for ($y = 0; $y -lt $GridSize; $y++) {
$row = @()
for ($x = 0; $x -lt $GridSize; $x++) {
$row += '.'
}
$grid += ,$row
}
# Convert vault pos to grid index
$gx = [math]::Round($v.Xkm / $CellSize)
$gy = [math]::Round($v.Ykm / $CellSize)
$ix = $Half + $gx
$iy = $Half - $gy # Flip Y for screen coords
$marker = 'V'
$clipped = $false
# Handle edge clipping
if ($ix -lt 0) { $ix = 0; $marker = 'X'; $clipped = $true }
elseif ($ix -ge $GridSize) { $ix = $GridSize - 1; $marker = 'X'; $clipped = $true }
if ($iy -lt 0) { $iy = 0; $marker = 'X'; $clipped = $true }
elseif ($iy -ge $GridSize) { $iy = $GridSize - 1; $marker = 'X'; $clipped = $true }
$grid[$iy][$ix] = $marker
# Print grid
for ($y = 0; $y -lt $GridSize; $y++) {
$realY = ($Half - $y) * $CellSize
$rowStr = ""
for ($x = 0; $x -lt $GridSize; $x++) {
$rowStr += "$($grid[$y][$x]) "
}
Write-Host ("Y=$realY".PadRight(8)) -NoNewline
Write-Host $rowStr
}
############ SOMEONE PLEASE FIX THE LABEL PADDING IT LOOKS CRAP and i hate UI
#############
# X-Axis Markers
$xAxisLabel = " "
$xCoordLabel = " "
for ($x = 0; $x -lt $GridSize; $x++) {
$realX = ($x - $Half) * $CellSize
$xAxisLabel += if ($realX % 50 -eq 0) { "^ " } else { " " }
$xCoordLabel += if ($realX % 50 -eq 0) { $realX.ToString().PadLeft(3) + " " } else { " " }
}
Write-Host $xAxisLabel
Write-Host (" " * 9) + ("".PadRight($GridSize * 2, "-"))
Write-Host $xCoordLabel
# Z-axis color logic
$zVal = [math]::Round($v.Zkm, 2)
if ($zVal -gt 0) { $zColor = "Yellow" }
elseif ($zVal -lt 0) { $zColor = "Red" }
else { $zColor = "Gray" }
# Blueprint pretty name
$bpName = Get-BlueprintName ($v.blueprint -join ", ")
# Vault Info Display
Write-Host "`nVault Info:" -ForegroundColor Cyan
Write-Host " Location: $($v.Location), $bpName"
Write-Host " Position: X=$([math]::Round($v.Xkm,2))km, Y=$([math]::Round($v.Ykm,2))km, Z=" -NoNewline
Write-Host "$zVal" -ForegroundColor $zColor -NoNewline
Write-Host "km"
if ($clipped) {
Write-Host " Grid Cell: [$gx,$gy]" -ForegroundColor DarkRed
Write-Host " Note: Vault outside visible map they are marked with 'X'" -ForegroundColor DarkRed
} else {
Write-Host " Grid Cell: [$gx,$gy]" -ForegroundColor Gray
}
Write-Host ""
}
[System.Windows.Forms.Messagebox]::Show("Done, you can copy out of the cmd window or grid view before closing this if you want.")
<#
#Some other useful snippets
#detailed output
. {
foreach($vault in $vaults){
Recurse-Offsets $vault.Node
"-----"
}
} | ft -AutoSize
#parse out zone info
$zoneinfo = [xml](gc c:\path\to\dlc_pirate_sectors.xml)
$hash = @{}
$zoneinfo.macros.macro | %{
$_.connections.connection | %{
$hash += @{$_.macro.ref = $_.offset.position }
}
}
# Generate a powershell hash for the above xml and put it on the clipboard
"@{`n" + ($hash.GetEnumerator() |%{" `"$($_.key)`"=`"$(@($_.value.x,$_.value.y,$_.value.z) -join ",")`"`n"}) + "}" | clip
$components=Select-Xml -Xml $Xml -XPath "/savegame/universe//component"
# Get all classes
$components.Node.class | select -Unique | sort
order of map related:
galaxy
cluster
sector
zone
#>
Thats the complete save scanner code - throw it in a .bat and off you go.
this is my additional code
Code: Select all
# === DISPLAY GRID CONFIGURATION ===
$GridSize = 21 # Must be odd to center (e.g., 21 = -10 to 10)
$CellSize = 10 # km per grid cell
$Half = [math]::Floor($GridSize / 2)
# === INIT GRID === (correct 2D char array)
$grid = @()
for ($y = 0; $y -lt $GridSize; $y++) {
$row = @()
for ($x = 0; $x -lt $GridSize; $x++) {
$row += '.'
}
$grid += ,$row
}
$legend = @()
## === DISPLAY INDIVIDUAL MAPS PER VAULT ===
$GridSize = 21 # Must be odd to center (e.g., 21 = -10 to 10)
$CellSize = 10 # km per grid cell
$Half = [math]::Floor($GridSize / 2)
function Get-BlueprintName($bp) {
if (-not $bp) { return "(None)" }
if ($bp -match "turret_pir_m_battleship_01_gatling") { return "Erlking Medium Turret Gatling" }
elseif ($bp -match "engine_pir") { return "XL Engines Erlking" }
elseif ($bp -match "turret_pir_l") { return "Erlking L Laser Turret" }
elseif ($bp -match "shield_pir_xl") { return "XL Shield Erlking" }
elseif ($bp -match "weapon_pir_xl") { return "Erlking Primary Weapon" }
else { return $bp }
}
foreach ($v in $data) {
Write-Host ""
Write-Host "Vault XY Map Grid (X axis, Y axis) each 'cell' = ${CellSize}km" -ForegroundColor Cyan
Write-Host "Origin (0,0) at center. 'V' = Vault: $($v.Location)" -ForegroundColor DarkGray
Write-Host ""
# Init grid
$grid = @()
for ($y = 0; $y -lt $GridSize; $y++) {
$row = @()
for ($x = 0; $x -lt $GridSize; $x++) {
$row += '.'
}
$grid += ,$row
}
# Convert vault pos to grid index
$gx = [math]::Round($v.Xkm / $CellSize)
$gy = [math]::Round($v.Ykm / $CellSize)
$ix = $Half + $gx
$iy = $Half - $gy # Flip Y for screen coords
$marker = 'V'
$clipped = $false
# Handle edge clipping
if ($ix -lt 0) { $ix = 0; $marker = 'X'; $clipped = $true }
elseif ($ix -ge $GridSize) { $ix = $GridSize - 1; $marker = 'X'; $clipped = $true }
if ($iy -lt 0) { $iy = 0; $marker = 'X'; $clipped = $true }
elseif ($iy -ge $GridSize) { $iy = $GridSize - 1; $marker = 'X'; $clipped = $true }
$grid[$iy][$ix] = $marker
# Print grid
for ($y = 0; $y -lt $GridSize; $y++) {
$realY = ($Half - $y) * $CellSize
$rowStr = ""
for ($x = 0; $x -lt $GridSize; $x++) {
$rowStr += "$($grid[$y][$x]) "
}
Write-Host ("Y=$realY".PadRight(8)) -NoNewline
Write-Host $rowStr
}
############ SOMEONE PLEASE FIX THE LABEL PADDING IT LOOKS CRAP and i hate UI
#############
# X-Axis Markers
$xAxisLabel = " "
$xCoordLabel = " "
for ($x = 0; $x -lt $GridSize; $x++) {
$realX = ($x - $Half) * $CellSize
$xAxisLabel += if ($realX % 50 -eq 0) { "^ " } else { " " }
$xCoordLabel += if ($realX % 50 -eq 0) { $realX.ToString().PadLeft(3) + " " } else { " " }
}
Write-Host $xAxisLabel
Write-Host (" " * 9) + ("".PadRight($GridSize * 2, "-"))
Write-Host $xCoordLabel
# Z-axis color logic
$zVal = [math]::Round($v.Zkm, 2)
if ($zVal -gt 0) { $zColor = "Yellow" }
elseif ($zVal -lt 0) { $zColor = "Red" }
else { $zColor = "Gray" }
# Blueprint pretty name
$bpName = Get-BlueprintName ($v.blueprint -join ", ")
# Vault Info Display
Write-Host "`nVault Info:" -ForegroundColor Cyan
Write-Host " Location: $($v.Location), $bpName"
Write-Host " Position: X=$([math]::Round($v.Xkm,2))km, Y=$([math]::Round($v.Ykm,2))km, Z=" -NoNewline
Write-Host "$zVal" -ForegroundColor $zColor -NoNewline
Write-Host "km"
if ($clipped) {
Write-Host " Grid Cell: [$gx,$gy]" -ForegroundColor DarkRed
Write-Host " Note: Vault outside visible map they are marked with 'X'" -ForegroundColor DarkRed
} else {
Write-Host " Grid Cell: [$gx,$gy]" -ForegroundColor Gray
}
Write-Host ""
}
and this is an example of what it should spit out on the CMD line.
Vault XY Map Grid (X axis, Y axis) each 'cell' = 10km
Origin (0,0) at center. 'V' = Vault: Windfall I
Y=100 . . . . . . . . . . . . . . . . . . . . .
Y=90 . . . . . . . . . . . . . . . . . . . . .
Y=80 . . . . . . . . . . . . . . . . . . . . .
Y=70 . . . . . . . . . . . . . . . . . . . . .
Y=60 . . . . . . . . . . . . . . . . . . . . .
Y=50 . . . . . . . . . . . . . . . . . . . . .
Y=40 . . . . . . . . . . . . . . . . . . . . .
Y=30 . . . . . . . . . . . . . . . . . . . . .
Y=20 . . . . . . . . . . . . . . . . . . . . .
Y=10 . . . . . . . . . . . . . . . . . . . . .
Y=0 . . . . . . . . . . . . V . . . . . . . .
Y=-10 . . . . . . . . . . . . . . . . . . . . .
Y=-20 . . . . . . . . . . . . . . . . . . . . .
Y=-30 . . . . . . . . . . . . . . . . . . . . .
Y=-40 . . . . . . . . . . . . . . . . . . . . .
Y=-50 . . . . . . . . . . . . . . . . . . . . .
Y=-60 . . . . . . . . . . . . . . . . . . . . .
Y=-70 . . . . . . . . . . . . . . . . . . . . .
Y=-80 . . . . . . . . . . . . . . . . . . . . .
Y=-90 . . . . . . . . . . . . . . . . . . . . .
Y=-100 . . . . . . . . . . . . . . . . . . . . .
^ ^ ^ ^ ^
+ ------------------------------------------
-100 -50 0 50 100
Vault Info:
Location: Windfall I, Erlking Primary Weapon
Position: X=17.79km, Y=-0.97km, Z=90.56km (with some colour here to denote up or down Z direction, yellow up red down)
Grid Cell: [2,0]
hope that helps ya'll