diff --git a/SCANassets/Flags/Agents.cfg b/SCANassets/Flags/Agents.cfg new file mode 100644 index 000000000..577afbbb8 --- /dev/null +++ b/SCANassets/Flags/Agents.cfg @@ -0,0 +1,14 @@ + + +AGENT +{ + name = SCAN: Scientific Committee on Advanced Navigation + + description = The SCAN agency is dedicated to mapping and surveying every planet in the solar system. + + logoURL = SCANsat/Flags/SCANsat_Flag + logoScaledURL = SCANsat/Flags/SCANsat_Flag_Scaled + + mentality = Scientific + mentality = Pioneer +} \ No newline at end of file diff --git a/SCANassets/Flags/SCANsat_Flag_Scaled.dds b/SCANassets/Flags/SCANsat_Flag_Scaled.dds new file mode 100644 index 000000000..16c6a82ac Binary files /dev/null and b/SCANassets/Flags/SCANsat_Flag_Scaled.dds differ diff --git a/SCANassets/MM_Parts/MFDPatches.cfg b/SCANassets/MM_Parts/MFDPatches.cfg new file mode 100644 index 000000000..836c2e479 --- /dev/null +++ b/SCANassets/MM_Parts/MFDPatches.cfg @@ -0,0 +1,122 @@ +//These patches add additional functionality to the SCANsat pages in stock and ALCOR MFDs + + +@PROP[ALCORMFD60x30]:FOR[SCANsat]:NEEDS[RasterPropMonitor,ASET] +{ + @MODULE[RasterPropMonitor] + { + @PAGE[pALCOROrbitMap60x30] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + @buttonHome = 6 + buttonRight = 5 + buttonLeft = 1 + buttonR9 = 8 + buttonR10 = 7 + startLine = 120 + stopLine = 390 + mapDivider = 2 + resourceInterpolation = 4 + } + } + + @PAGE[pALCORClearMap60x30] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + @buttonHome = 6 + buttonRight = 5 + buttonLeft = 1 + buttonR9 = 8 + buttonR10 = 7 + mapDivider = 2 + resourceInterpolation = 4 + } + } + } +} + +@PROP[kOSTerminal]:FOR[SCANsat]:NEEDS[RasterPropMonitor,ASET] +{ + @MODULE[RasterPropMonitor] + { + @PAGE[pALCORMapOrbit50x18] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + buttonHome = 4 + buttonRight = 6 + buttonR9 = 5 + mapDivider = 2 + resourceInterpolation = 4 + } + } + + @PAGE[pALCORMapLanding50x18] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + buttonHome = 4 + buttonRight = 6 + buttonR9 = 5 + mapDivider = 2 + resourceInterpolation = 4 + } + } + } +} + + +@PROP[ALCORMFD40x20]:FOR[SCANsat]:NEEDS[RasterPropMonitor,ASET] +{ + @MODULE[RasterPropMonitor] + { + @PAGE[pALCORMapOrbit40x20] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + buttonHome = 4 + buttonRight = 5 + buttonLeft = 6 + buttonR9 = 7 + buttonR10 = 8 + mapDivider = 2 + resourceInterpolation = 4 + } + } + + @PAGE[pALCORMapLanding40x20] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + buttonHome = 4 + buttonRight = 5 + buttonLeft = 6 + buttonR9 = 7 + buttonR10 = 8 + mapDivider = 2 + resourceInterpolation = 4 + } + } + } +} + +@PROP[RasterPropMonitorBasicMFD]:FOR[SCANsat]:NEEDS[RasterPropMonitor] +{ + @MODULE[RasterPropMonitor] + { + @PAGE[map] + { + @BACKGROUNDHANDLER[JSISCANsatRPM] + { + buttonRight = 5 + buttonLeft = 6 + buttonR9 = 7 + buttonR10 = 8 + mapDivider = 2 + resourceInterpolation = 4 + } + } + } +} diff --git a/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg b/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg index 1031ade07..fa64165da 100644 --- a/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg +++ b/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg @@ -60,10 +60,10 @@ { name = ModuleSCANresourceScanner sensorType = 524288 - fov = 4 - min_alt = 20000 - max_alt = 750000 - best_alt = 200000 + fov = 5 + min_alt = 15000 + max_alt = 1000000 + best_alt = 150000 scanName = Resource Scan power = 0.5 } diff --git a/SCANassets/Parts/BTDT/BTDT.cfg b/SCANassets/Parts/BTDT/BTDT.cfg index a667db078..200f36321 100644 --- a/SCANassets/Parts/BTDT/BTDT.cfg +++ b/SCANassets/Parts/BTDT/BTDT.cfg @@ -7,17 +7,12 @@ author = damny MODEL { model = SCANsat/Parts/BTDT/BTDT - position = 0, 0, 0 - rotation = 0, 0, 0 - scale = 1, 1, 1 + scale = 0.5, 0.5, 0.5 } -scale = 1 -rescaleFactor = 0.5 - // attachment rules: [stack, srfAttach, allowStack, allowSrfAttach, allowCollision] attachRules = 0,1,0,0,0 -node_attach = 0.0, 0.1, 0.0, 0.0, -1.0, 0.0, 0 +node_attach = 0.0, 0.05, 0.0, 0.0, -1.0, 0.0, 0 TechRequired = fieldScience entryCost = 25000 @@ -25,15 +20,14 @@ cost = 13000 category = Science subcategory = 0 title = SCAN Been There Done That® -manufacturer = [SCAN]: Scientific Committee on Advanced Navigation +manufacturer = SCAN: Scientific Committee on Advanced Navigation description = This small sensor can automatically identify nearby anomalies. Since it only works over very short distances and at very low altitudes, it's primarily useful to track identified anomalies that have been visited. mass = 0.03 dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 angularDrag = 1 +bulkheadProfiles = srf crashTolerance = 12 maxTemp = 1200 emissiveConstant = 0.95 diff --git a/SCANassets/Parts/MULTI/MULTI.cfg b/SCANassets/Parts/MULTI/MULTI.cfg index 69aa4dd39..1f47f9cc8 100644 --- a/SCANassets/Parts/MULTI/MULTI.cfg +++ b/SCANassets/Parts/MULTI/MULTI.cfg @@ -7,17 +7,12 @@ author = damny MODEL { model = SCANsat/Parts/MULTI/MULTI - position = 0, 0, 0 - rotation = 0, 0, 0 - scale = 1, 1, 1 + scale = 0.2, 0.2, 0.2 } -scale = 1 -rescaleFactor = 0.25 - // attachment rules: [stack, srfAttach, allowStack, allowSrfAttach, allowCollision] attachRules = 0,1,0,0,0 -node_attach = 0.0, -0.09, 0.0, 0.0, -1.0, 0.0, 0 +node_attach = 0.0, -0.018, 0.0, 0.0, -1.0, 0.0, 0 TechRequired = advExploration entryCost = 20000 @@ -25,14 +20,13 @@ cost = 9000 category = Science subcategory = 0 title = SCAN Multispectral Sensor -manufacturer = [SCAN]: Scientific Committee on Advanced Navigation +manufacturer = SCAN: Scientific Committee on Advanced Navigation description = This multichannel sensor detects radiation across several infrared, visible light, and RADAR bands. This gives it the capability to differentiate between terrain types and biomes. It can also detect anomalies such as structures on the ground. mass = 0.03 dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 angularDrag = 2 +bulkheadProfiles = srf crashTolerance = 7 maxTemp = 1200 emissiveConstant = 0.95 @@ -46,7 +40,7 @@ MODULE min_alt = 5000 max_alt = 500000 best_alt = 250000 - power = 1.5 + power = 1 scanName = Multispectral Scan animationName = Multi_Antenna } diff --git a/SCANassets/Parts/MapTraq/MapTraq.cfg b/SCANassets/Parts/MapTraq/MapTraq.cfg index 866b98825..136c60886 100644 --- a/SCANassets/Parts/MapTraq/MapTraq.cfg +++ b/SCANassets/Parts/MapTraq/MapTraq.cfg @@ -26,7 +26,7 @@ cost = 2500 category = none subcategory = 0 title = SCAN MapTraq® -manufacturer = [SCAN]: Scientific Committee on Advanced Navigation +manufacturer = SCAN: Scientific Committee on Advanced Navigation description = Originally intended for the consumer market, this small device can communicate with a mapping satellite network and display a map and your position on it. Since nobody has actually built such a satellite network, these devices can currently be acquired very cheaply in bulk. mass = 0.03 diff --git a/SCANassets/Parts/RADAR/RADAR.cfg b/SCANassets/Parts/RADAR/RADAR.cfg index 19b321c07..a0196baea 100644 --- a/SCANassets/Parts/RADAR/RADAR.cfg +++ b/SCANassets/Parts/RADAR/RADAR.cfg @@ -7,19 +7,14 @@ author = damny MODEL { model = SCANsat/Parts/RADAR/RADAR - position = 0, 0, 0 - rotation = 0, 0, 0 - scale = 1, 1, 1 + scale = 2, 2, 2 } -scale = 1 -rescaleFactor = 2 - // attachment rules: [stack, srfAttach, allowStack, allowSrfAttach, allowCollision] attachRules = 0,1,0,0,0 // node_attach: [x, y, z, up x, up y, up z] -node_attach = 0.0, -0.055, 0.0, 0.0, -1.0, 0.0, 0 +node_attach = 0.0, -0.11, 0.0, 0.0, -1.0, 0.0, 0 TechRequired = basicScience entryCost = 10000 @@ -27,14 +22,13 @@ cost = 3500 category = Science subcategory = 0 title = SCAN RADAR Altimetry Sensor -manufacturer = [SCAN]: Scientific Committee on Advanced Navigation +manufacturer = SCAN: Scientific Committee on Advanced Navigation description = SCAN brings you this high performance RADAR altimetry sensor. This is the entry-level model in this sensor family, and commonly sold in a bundle with toy rockets and remote-controlled model planes. After focus group testing revealed that 95% of the target audience tried to duct tape it to the exhaust pipe of their rocket engines, this new and improved model has been made even easier to use. mass = 0.03 dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 angularDrag = 2 +bulkheadProfiles = srf crashTolerance = 7 maxTemp = 1200 emissiveConstant = 0.95 diff --git a/SCANassets/Parts/SAR/SAR.cfg b/SCANassets/Parts/SAR/SAR.cfg index cdb65f2bb..aeb940a1d 100644 --- a/SCANassets/Parts/SAR/SAR.cfg +++ b/SCANassets/Parts/SAR/SAR.cfg @@ -7,14 +7,9 @@ author = damny MODEL { model = SCANsat/Parts/SAR/SAR - position = 0, 0, 0 - rotation = 0, 0, 0 - scale = 1, 1, 1 + scale = 1.5, 1.5, 1.5 } -scale = 1 -rescaleFactor = 2 - // attachment rules: [stack, srfAttach, allowStack, allowSrfAttach, allowCollision] attachRules = 0,1,0,0,0 node_attach = 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0 @@ -25,14 +20,13 @@ cost = 25000 category = Science subcategory = 0 title = SCAN SAR Altimetry Sensor -manufacturer = [SCAN]: Scientific Committee on Advanced Navigation +manufacturer = SCAN: Scientific Committee on Advanced Navigation description = This Synthetic Aperture RADAR sensor uses its flight path to simulate a much larger antenna. This makes it possible to detect terrain elevation at much higher resolution. The downside is that its field of view is comparatively small, and it works better at higher altitudes. mass = 0.03 dragModelType = default -maximum_drag = 0.2 -minimum_drag = 0.2 angularDrag = 2 +bulkheadProfiles = srf crashTolerance = 7 maxTemp = 1200 emissiveConstant = 0.95 @@ -46,7 +40,7 @@ MODULE min_alt = 5000 max_alt = 800000 best_alt = 750000 - power = 1 + power = 1.5 scanName = SAR Scan animationName = Antenna } diff --git a/SCANassets/Resources/Contracts/Biome.cfg b/SCANassets/Resources/Contracts/Biome.cfg new file mode 100644 index 000000000..2b2ecbf50 --- /dev/null +++ b/SCANassets/Resources/Contracts/Biome.cfg @@ -0,0 +1,77 @@ +CONTRACT_TYPE +{ + name = SCAN_Biome + title = Do a Biome Scan of @/targetBody2 + group = ScanSatOfficial + agent = SCAN: Scientific Committee on Advanced Navigation + topic = Science + subject = Kerbal + motivation = Scanning + notes = Scanning can take place while the vessel is not loaded. + synopsis = Perform a MultiSpectral scan of @/targetBody2 + completedMessage = Stunning, through the advances with this scanner we have identified several different biomes for further study. + minExpiry = 1 + maxExpiry = 7 + deadline = Random(300, 500) * @/targetBody2.Multiplier() + cancellable = true + declinable = true + autoAccept = false + targetBody = @/targetBody2 + // Contract rewards + rewardScience = 0 + rewardReputation = 1 + rewardFunds = Random(40000, 60000.0) + failureReputation = 1 + failureFunds = Random(1000, 10000.0) + advanceFunds = Random(2000, 10000.0) + prestige = Trivial + prestige = Significant + + DATA + { + type = CelestialBody + requiredValue = true + uniqueValue = true + targetBody2 = Prestige() == Trivial ? @ScanSatOfficial:p1Bodies.Random() : @ScanSatOfficial:p2Bodies.Random() + } + + DATA + { + type = double + + diffModifier2 = Prestige() == Trivial ? 0 : 10 + scanRequired2 = 75 + @diffModifier2 + minScan2 = 70 + @diffModifier2 + } + + PARAMETER + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody2 + coverage = @/scanRequired2 + scanType = Biome + } + REQUIREMENT + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody2 + minCoverage = 0.0 + maxCoverage = @/minScan2 + scanType = Biome + } + REQUIREMENT + { + name = Orbit + type = Orbit + + targetBody = HomeWorld() + } + REQUIREMENT + { + name = PartUnlocked + type = PartUnlocked + part = SCANsat_Scanner24 + } +} \ No newline at end of file diff --git a/SCANassets/Resources/Contracts/ContractPackScanSatOfficial.cfg b/SCANassets/Resources/Contracts/ContractPackScanSatOfficial.cfg new file mode 100644 index 000000000..2454b8106 --- /dev/null +++ b/SCANassets/Resources/Contracts/ContractPackScanSatOfficial.cfg @@ -0,0 +1,18 @@ +CONTRACT_GROUP +{ + // Name of the contract group + name = ScanSatOfficial + + minVersion = 1.7.0 + + maxSimultaneous = 3 + + DATA + { + type = List + + p1Bodies = AllBodies().Where(cb => ((cb.IsHomeWorld() || cb.Parent().IsHomeWorld()) && cb.HasSurface())) + p2Bodies = OrbitedBodies().Where(cb => cb.HasSurface()) + p3Bodies = ReachedBodies().Where(cb => cb.HasSurface() && cb != HomeWorld() && cb.Parent() != HomeWorld()) + } +} \ No newline at end of file diff --git a/SCANassets/Resources/Contracts/HiRes.cfg b/SCANassets/Resources/Contracts/HiRes.cfg new file mode 100644 index 000000000..1c2161b67 --- /dev/null +++ b/SCANassets/Resources/Contracts/HiRes.cfg @@ -0,0 +1,78 @@ +CONTRACT_TYPE +{ + name = SCAN_HiRes + title = Do a High Resolution Scan of @/targetBody3 + group = ScanSatOfficial + agent = SCAN: Scientific Committee on Advanced Navigation + topic = Science + subject = Kerbal + motivation = Scanning + notes = Scanning can take place while the vessel is not loaded. + synopsis = Perform a SAR scan of @/targetBody3 + completedMessage = HD Imaging is a wonderful thing. We now have a detailed map of @/targetBody3 + minExpiry = 1 + maxExpiry = 7 + deadline = Random(400, 600) * @/targetBody3.Multiplier() + cancellable = true + declinable = true + autoAccept = false + targetBody = @/targetBody3 + // Contract rewards + rewardScience = 0 + rewardReputation = 1 + rewardFunds = Random(60000, 80000.0) + failureReputation = 1 + failureFunds = Random(1000, 10000.0) + advanceFunds = Random(5000, 15000.0) + + prestige = Significant + prestige = Exceptional + + DATA + { + type = CelestialBody + requiredValue = true + uniqueValue = true + targetBody3 = Prestige() == Significant ? @ScanSatOfficial:p2Bodies.Random() : @ScanSatOfficial:p3Bodies.Random() + } + + DATA + { + type = double + + diffModifier3 = Prestige() == Significant ? 0 : 10 + scanRequired3 = 85 + @diffModifier3 + minScan3 = 80 + @diffModifier3 + } + + PARAMETER + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody3 + coverage = @/scanRequired3 + scanType = AltimetryHiRes + } + REQUIREMENT + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody3 + minCoverage = 0.0 + maxCoverage = @/minScan3 + scanType = AltimetryHiRes + } + REQUIREMENT + { + name = Orbit + type = Orbit + + targetBody = HomeWorld() + } + REQUIREMENT + { + name = PartUnlocked + type = PartUnlocked + part = SCANsat_Scanner2 + } +} \ No newline at end of file diff --git a/SCANassets/Resources/Contracts/LoRes.cfg b/SCANassets/Resources/Contracts/LoRes.cfg new file mode 100644 index 000000000..ae3f3e119 --- /dev/null +++ b/SCANassets/Resources/Contracts/LoRes.cfg @@ -0,0 +1,78 @@ +CONTRACT_TYPE +{ + name = SCAN_LoRes + title = Do a Low Resolution Scan of @/targetBody1 + group = ScanSatOfficial + topic = Science + subject = Kerbal + motivation = Scanning + agent = SCAN: Scientific Committee on Advanced Navigation + notes = Scanning can take place while the vessel is not loaded. + synopsis = Perform a RADAR scan of @/targetBody1 + completedMessage = Excellent work, despite the grainy monochrome image we've recovered our experts are very excited to see what they can find. + minExpiry = 1 + maxExpiry = 7 + deadline = Random(300, 500) * @/targetBody1.Multiplier() + cancellable = true + declinable = true + autoAccept = false + targetBody = @/targetBody1 + + // Contract rewards + rewardScience = 0 + rewardReputation = 1 + rewardFunds = Random(40000, 60000.0) + failureReputation = 1 + failureFunds = Random(1000, 10000.0) + advanceFunds = Random(2000, 10000.0) + prestige = Trivial + prestige = Significant + + DATA + { + type = CelestialBody + requiredValue = true + uniqueValue = true + targetBody1 = Prestige() == Trivial ? @ScanSatOfficial:p1Bodies.Random() : @ScanSatOfficial:p2Bodies.Random() + } + + DATA + { + type = double + + diffModifier1 = Prestige() == Trivial ? 0 : 10 + scanRequired1 = 75 + @diffModifier1 + minScan1 = 70 + @diffModifier1 + } + + PARAMETER + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody1 + coverage = @/scanRequired1 + scanType = AltimetryLoRes + } + REQUIREMENT + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody1 + minCoverage = 0.0 + maxCoverage = @/minScan1 + scanType = AltimetryLoRes + } + REQUIREMENT + { + name = Orbit + type = Orbit + + targetBody = HomeWorld() + } + REQUIREMENT + { + name = PartUnlocked + type = PartUnlocked + part = SCANsat_Scanner + } +} \ No newline at end of file diff --git a/SCANassets/Resources/Contracts/M700.cfg b/SCANassets/Resources/Contracts/M700.cfg new file mode 100644 index 000000000..84e618797 --- /dev/null +++ b/SCANassets/Resources/Contracts/M700.cfg @@ -0,0 +1,77 @@ +CONTRACT_TYPE +{ + name = SCAN_M700 + title = Scan @/targetBody4 for resources + group = ScanSatOfficial + topic = Science + subject = Kerbal + motivation = Scanning + agent = SCAN: Scientific Committee on Advanced Navigation + notes = Scanning can take place while the vessel is not loaded. + synopsis = Scan @/targetBody4 with the M700 Scanner + completedMessage = Look at all those lovely resources. We'll have to get a survey team together! + minExpiry = 1 + maxExpiry = 7 + deadline = Random(300, 500) * @/targetBody4.Multiplier() + cancellable = true + declinable = true + autoAccept = false + targetBody = @/targetBody4 + // Contract rewards + rewardScience = 0 + rewardReputation = 1 + rewardFunds = Random(45000, 70000.0) + failureReputation = 1 + failureFunds = Random(1000, 10000.0) + advanceFunds = Random(2000, 10000.0) + prestige = Trivial + prestige = Significant + + DATA + { + type = CelestialBody + requiredValue = true + uniqueValue = true + targetBody4 = Prestige() == Trivial ? @ScanSatOfficial:p1Bodies.Random() : @ScanSatOfficial:p2Bodies.Random() + } + + DATA + { + type = double + + diffModifier4 = Prestige() == Trivial ? 0 : 10 + scanRequired4 = 75 + @diffModifier4 + minScan4 = 70 + @diffModifier4 + } + + PARAMETER + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody4 + coverage = @/scanRequired4 + scanType = FuzzyResources + } + REQUIREMENT + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody4 + minCoverage = 0.0 + maxCoverage = @/minScan4 + scanType = FuzzyResources + } + REQUIREMENT + { + name = Orbit + type = Orbit + + targetBody = HomeWorld() + } + REQUIREMENT + { + name = PartUnlocked + type = PartUnlocked + part = SurveyScanner + } +} \ No newline at end of file diff --git a/SCANassets/Resources/Contracts/NarrowBand.cfg b/SCANassets/Resources/Contracts/NarrowBand.cfg new file mode 100644 index 000000000..14eacced8 --- /dev/null +++ b/SCANassets/Resources/Contracts/NarrowBand.cfg @@ -0,0 +1,77 @@ +CONTRACT_TYPE +{ + name = SCAN_NarrowBand + title = Scan @/targetBody5 for Ore + group = ScanSatOfficial + topic = Science + subject = Kerbal + motivation = Scanning + agent = SCAN: Scientific Committee on Advanced Navigation + notes = Scanning can take place while the vessel is not loaded. + synopsis = Scan @/targetBody5 with the M4435 Narrow-Band Scanner + completedMessage = Look at all that lovely Ore. We'll have to get a survey team together! + minExpiry = 1 + maxExpiry = 7 + deadline = Random(400, 600) * @/targetBody5.Multiplier() + cancellable = true + declinable = true + autoAccept = false + targetBody = @/targetBody5 + // Contract rewards + rewardScience = 0 + rewardReputation = 1 + rewardFunds = Random(60000, 80000.0) + failureReputation = 1 + failureFunds = Random(1000, 10000.0) + advanceFunds = Random(5000, 15000.0) + + prestige = Significant + prestige = Exceptional + + DATA + { + type = CelestialBody + requiredValue = true + uniqueValue = true + targetBody5 = Prestige() == Significant ? @ScanSatOfficial:p2Bodies.Random() : @ScanSatOfficial:p3Bodies.Random() + } + + DATA + { + type = double + + diffModifier5 = Prestige() == Significant ? 0 : 10 + scanRequired5 = 85 + @diffModifier5 + minScan5 = 80 + @diffModifier5 + } + + PARAMETER + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody5 + coverage = @/scanRequired5 + scanType = Ore + } + REQUIREMENT + { + name = SCANsatCoverage + type = SCANsatCoverage + targetBody = @/targetBody5 + minCoverage = @/minScan5 + scanType = FuzzyResources + } + REQUIREMENT + { + name = Orbit + type = Orbit + + targetBody = HomeWorld() + } + REQUIREMENT + { + name = PartUnlocked + type = PartUnlocked + part = OrbitalScanner + } +} \ No newline at end of file diff --git a/SCANassets/Resources/SCANresource.cfg b/SCANassets/Resources/SCANresource.cfg index bd968211b..23491e592 100644 --- a/SCANassets/Resources/SCANresource.cfg +++ b/SCANassets/Resources/SCANresource.cfg @@ -7,6 +7,9 @@ //SCANtype values below 64 are reserved for SCANsat //sensors and can't be assigned +//SCANtype 524288 (2^19) is reserved for the M700 (clamshell) stock resource scanner +//It is used for the low resolution scan of all valid resource types + SCANSAT_SENSOR { name = Kethane diff --git a/SCANassets/SCANsat.version b/SCANassets/SCANsat.version index 1bbebdcff..0bded6139 100644 --- a/SCANassets/SCANsat.version +++ b/SCANassets/SCANsat.version @@ -11,7 +11,7 @@ "MAJOR":1, "MINOR":1, "PATCH":4, - "BUILD":1 + "BUILD":2 }, "KSP_VERSION":{ "MAJOR":1, diff --git a/SCANmechjeb/Properties/AssemblyInfo.cs b/SCANmechjeb/Properties/AssemblyInfo.cs index 159677fec..5ef8b46f7 100644 --- a/SCANmechjeb/Properties/AssemblyInfo.cs +++ b/SCANmechjeb/Properties/AssemblyInfo.cs @@ -32,9 +32,9 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.4.0.1")] -[assembly: AssemblyFileVersion("1.4.0.1")] -[assembly: AssemblyInformationalVersion ("v14.1")] +[assembly: AssemblyVersion("1.4.0.2")] +[assembly: AssemblyFileVersion("1.4.0.2")] +[assembly: AssemblyInformationalVersion ("v14.2")] [assembly: KSPAssembly ("SCANmechjeb", 0, 3)] [assembly: KSPAssemblyDependency ("SCANsat", 1, 4)] diff --git a/SCANsat/CHANGELOG.txt b/SCANsat/CHANGELOG.txt index b115da941..18afc3114 100644 --- a/SCANsat/CHANGELOG.txt +++ b/SCANsat/CHANGELOG.txt @@ -1,3 +1,58 @@ +Version 14.2 - 2015-8-29 +------------------------ + +- Performance and RAM usage improvements + - Storage modules for each planet use less RAM + - Planetary overlays use less RAM + - Biome overlay texture size can be changed independently of resource size + - Planetary overlays generated on a different thread when possible + - This reduces or prevents the slight freeze or hiccup when generating a new overlay + +- Raster Prop Monitor + - Additional functions added to RPM panels + - The standard MFDs use the four buttons on the left for resource and anomaly/waypoint overlays + - ALCOR pods also have additional functions where possible + - Increased map rendering performance by reducing map texture size + - Map texture size and resource overlay quality can be adjusted in the RPM configs + - Prevent the non full-screen panels from drawing maps underneath opaque sections of the display (ie the left hand ALCOR panel) + - A Module Manager patch is required for full ALCOR MFD functionality + +- Parts + - Slight reduction in size of SAR and MultiSpectral scanners + - Proper use of MODEL node scaling; fixes KIS inventory size problems (thanks Kerbas_ad_astra) + - Slightly increased scanning width and altitude parameters for M700 (clamshell) resource scanner + +- Contract Configurator Contracts included + - Based on a slightly modified version of severedsolo's SCANsatLite pack + +- SCAN agency and manufacturers group added + +- Big map and KSC map + - Resource overlays now use the same quality settings as the planetary overlays + - Resource mouse-over info now follows the same narrow-band scanner restrictions as planetary overlay tooltips + - Slope added to mouse-over info for terrain scanned with high-resolution terrain scanner + +- Small map + - Biome maps available on the small map + - The vessel info readout will display the current biome (if scanned) for each vessel + - The altitude readout for each vessel is now dependent on scanning coverage + +- Instruments UI + - New rules for the altitude and slope readout + - Below 1000m full height-above-terrain and slope info is given regardless of scanning coverage + - Above 1000m altitude the readout is based on low or high resolution terrain scanning; slope is only given for high resolution scans + +- Color Management Window + - Planet selection boxes available for terrain and resource color configs + - Fix possible bugs created by adding and deleting mod planets + +- Misc and bug fixes + - Resource overlay colors properly use the assigned abundance ranges + - Added a resource overlay control window toolbar button + - Update the active vessel in the instruments window + - Various minor performance improvements + - Various minor UI tweaks + Version 14.1 - 2015-7-15 ------------------------ diff --git a/SCANsat/LICENSE.txt b/SCANsat/LICENSE.txt index 9e5f19699..ab27bb148 100644 --- a/SCANsat/LICENSE.txt +++ b/SCANsat/LICENSE.txt @@ -218,4 +218,11 @@ CLZF2: * you do not delete the provisions above, a recipient may use your version * of this file under either the BSD or the GPL. + ---------------------------------------------------------------- + Contract Pack: + + The contract pack is based on the SCANsatLite Contract Configurator pack by severedSolo + + Released under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license (see above) + diff --git a/SCANsat/Properties/AssemblyInfo.cs b/SCANsat/Properties/AssemblyInfo.cs index ab2c62952..7ed058665 100644 --- a/SCANsat/Properties/AssemblyInfo.cs +++ b/SCANsat/Properties/AssemblyInfo.cs @@ -14,9 +14,9 @@ // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion ("1.4.0.1")] -[assembly: AssemblyFileVersion ("1.4.0.1")] -[assembly: AssemblyInformationalVersion ("v14.1")] +[assembly: AssemblyVersion ("1.4.0.2")] +[assembly: AssemblyFileVersion ("1.4.0.2")] +[assembly: AssemblyInformationalVersion ("v14.2")] [assembly: KSPAssembly ("SCANsat", 1, 4)] diff --git a/SCANsat/SCAN_Data/SCANdata.cs b/SCANsat/SCAN_Data/SCANdata.cs index eb490771e..9d07cea33 100644 --- a/SCANsat/SCAN_Data/SCANdata.cs +++ b/SCANsat/SCAN_Data/SCANdata.cs @@ -33,15 +33,12 @@ public class SCANdata private static Dictionary heightMaps = new Dictionary(); /* MAP: state */ - private Int32[,] coverage = new Int32[360, 180]; - //private float[,] kethaneValueMap = new float[360, 180]; //Store kethane cell data in here - private Color[] cols_height_map_small = new Color[360]; + private Int32[,] coverage; private CelestialBody body; - private Texture2D map_small = new Texture2D(360, 180, TextureFormat.RGB24, false); private SCANterrainConfig terrainConfig; private bool building, externalBuilding, built; - private float[,] tempHeightMap = new float[360, 180]; + private float[,] tempHeightMap; /* MAP: options */ private bool disabled; @@ -50,20 +47,34 @@ public class SCANdata internal SCANdata(CelestialBody b) { body = b; - float? clamp = null; - if (b.ocean) - clamp = 0; + + coverage = new int[360, 180]; + + if (heightMaps.ContainsKey(body.flightGlobalsIndex)) + built = true; terrainConfig = SCANcontroller.getTerrainNode(b.name); if (terrainConfig == null) { + float? clamp = null; + if (b.ocean) + clamp = 0; + terrainConfig = new SCANterrainConfig(SCANconfigLoader.SCANNode.DefaultMinHeightRange, SCANconfigLoader.SCANNode.DefaultMaxHeightRange, clamp, SCANUtil.paletteLoader(SCANconfigLoader.SCANNode.DefaultPalette, 7), 7, false, false, body); SCANcontroller.addToTerrainConfigData(body.name, terrainConfig); } + } - if (heightMaps.ContainsKey(body.flightGlobalsIndex)) - built = true; + public SCANdata (SCANdata copy) + { + coverage = copy.coverage; + terrainConfig = new SCANterrainConfig(copy.terrainConfig); + + if (!heightMaps.ContainsKey(copy.body.flightGlobalsIndex)) + return; + + tempHeightMap = heightMaps[copy.body.flightGlobalsIndex]; } #region Public accessors @@ -74,8 +85,11 @@ internal SCANdata(CelestialBody b) internal set { coverage = value; } } - public float HeightMapValue(int i, int lon, int lat) + public float HeightMapValue(int i, int lon, int lat, bool useTemp = false) { + if (useTemp) + return tempHeightMap[lon, lat]; + if (!heightMaps.ContainsKey(i)) return 0; @@ -90,17 +104,6 @@ public CelestialBody Body get { return body; } } - public Texture2D Map - { - get { return map_small; } - } - - //public float[,] KethaneValueMap - //{ - // get { return kethaneValueMap; } - // set { kethaneValueMap = value; } - //} - public SCANterrainConfig TerrainConfig { get { return terrainConfig; } @@ -116,6 +119,7 @@ public bool Disabled public bool Building { get { return building; } + internal set { building = value; } } public bool ExternalBuilding @@ -366,89 +370,7 @@ internal int getCoverage(SCANtype type) #endregion - #region Map Texture - /* DATA: all hail the red line of scanning */ - private int scanline = 0; - private int scanstep = 0; - //Draws the actual map texture - - internal Texture2D drawPartialMap(SCANtype type) - { - if (externalBuilding) - { - return map_small; - } - - if (!built) - { - building = true; - generateHeightMap(ref scanline, ref scanstep, 360); - return map_small; - } - - if (palette.small_redline == null) - { - palette.small_redline = new Color[360]; - for (int i = 0; i < 360; i++) - palette.small_redline[i] = palette.red; - } - - int scheme = SCANcontroller.controller.colours; - - for (int ilon = 0; ilon < 360; ilon++) - { - if (body.pqsController == null) - { - cols_height_map_small[ilon] = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); - continue; - } - - Color c = palette.grey; - float val = heightMaps[body.flightGlobalsIndex][ilon, scanline]; - if (SCANUtil.isCovered(ilon, scanline, this, SCANtype.Altimetry)) - { - if (SCANUtil.isCovered(ilon, scanline, this, SCANtype.AltimetryHiRes)) - c = palette.heightToColor(val, scheme, this); - else - c = palette.heightToColor(val, 1, this); - } - else - { - if (scanline % 30 == 0 && ilon % 3 == 0) - { - c = palette.white; - } - else if (ilon % 30 == 0 && scanline % 3 == 0) - { - c = palette.white; - } - } - - if (type != SCANtype.Nothing) - { - if (!SCANUtil.isCoveredByAll(ilon, scanline, this, type)) - { - c = palette.lerp(c, palette.black, 0.5f); - } - } - - cols_height_map_small[ilon] = c; - } - - map_small.SetPixels(0, scanline, 360, 1, cols_height_map_small); - - if (scanline < 179) - map_small.SetPixels(0, scanline + 1, 360, 1, palette.small_redline); - - scanline++; - - if (scanline >= 180) - scanline = 0; - - map_small.Apply(); - - return map_small; - } + #region Height Map internal void generateHeightMap(ref int step, ref int xStart, int width) { @@ -462,6 +384,11 @@ internal void generateHeightMap(ref int step, ref int xStart, int width) return; } + if (tempHeightMap == null) + { + tempHeightMap = new float[360, 180]; + } + if (step >= 179) { step = 0; @@ -520,27 +447,13 @@ internal void fillResourceMap() internal void reset() { coverage = new Int32[360, 180]; - resetImages(); - } + if (SCANcontroller.controller == null) + return; - internal void resetImages() - { - // Just draw a simple grid to initialize the image; the map will appear on top of it - for (int y = 0; y < map_small.height; y++) - { - for (int x = 0; x < map_small.width; x++) - { - if ((x % 30 == 0 && y % 3 > 0) || (y % 30 == 0 && x % 3 > 0)) - { - map_small.SetPixel(x, y, palette.white); - } - else - { - map_small.SetPixel(x, y, palette.grey); - } - } - } - map_small.Apply(); + if (SCANcontroller.controller.mainMap == null) + return; + + SCANcontroller.controller.mainMap.resetImages(); } internal void resetResources() @@ -643,7 +556,6 @@ internal void integerDeserialize(string blob, bool b) Coverage = new Int32[360, 180]; throw e; } - resetImages(); } #endregion diff --git a/SCANsat/SCAN_Data/SCANresourceType.cs b/SCANsat/SCAN_Data/SCANresourceType.cs index 102ab9e32..fdae2e0ff 100644 --- a/SCANsat/SCAN_Data/SCANresourceType.cs +++ b/SCANsat/SCAN_Data/SCANresourceType.cs @@ -11,7 +11,6 @@ */ #endregion -using palette = SCANsat.SCAN_UI.UI_Framework.SCANpalette; using UnityEngine; namespace SCANsat.SCAN_Data @@ -27,7 +26,12 @@ internal SCANresourceType(string s, int i) type = (SCANtype)i; if ((type & SCANtype.Everything_SCAN) != SCANtype.Nothing) { - Debug.LogWarning("[SCANsat] Attempt To Override Default SCANsat Sensors; Resetting Resource Scanner Type To 0"); + Debug.LogWarning("[SCANsat] Attempt To Override Default SCANsat Sensors; Resetting Resource Scanner Type [" + i + "] To 0"); + type = SCANtype.Nothing; + } + else if ((type & SCANtype.FuzzyResources) != SCANtype.Nothing) + { + Debug.LogWarning("[SCANsat] Attempt To Override M700 Resource Scanner; Resetting Resource Scanner Type [" + i + "] To 0"); type = SCANtype.Nothing; } } diff --git a/SCANsat/SCAN_Data/SCANterrainConfig.cs b/SCANsat/SCAN_Data/SCANterrainConfig.cs index d7dbbdd81..3b54c3855 100644 --- a/SCANsat/SCAN_Data/SCANterrainConfig.cs +++ b/SCANsat/SCAN_Data/SCANterrainConfig.cs @@ -96,6 +96,8 @@ public override void OnDecodeFromConfigNode() body = FlightGlobals.Bodies.FirstOrDefault(b => b.flightGlobalsIndex == index); if (body != null) name = body.name; + else + name = "WrongBody" + index; colorPal = SCANUtil.paletteLoader(paletteName, paletteSize); diff --git a/SCANsat/SCAN_Map/SCANmap.cs b/SCANsat/SCAN_Map/SCANmap.cs index 8cb16f009..3657f3d38 100644 --- a/SCANsat/SCAN_Map/SCANmap.cs +++ b/SCANsat/SCAN_Map/SCANmap.cs @@ -308,8 +308,10 @@ internal double unprojectLatitude(double lon, double lat) private bool randomEdges = true; private double[] biomeIndex; private Color[] stockBiomeColor; + private int startLine; + private int stopLine; - internal void setSize(int w, int h) + internal void setSize(int w, int h, int interpolation = 2, int start = 0, int stop = 0) { if (w == 0) w = 360 * (Screen.width / 360); @@ -323,10 +325,12 @@ internal void setSize(int w, int h) if (h <= 0) h = (int)(180 * mapscale); mapheight = h; + startLine = start; + stopLine = stop == 0 ? mapheight - 1 : stop; resourceMapWidth = mapwidth; resourceMapHeight = mapheight; resourceCache = new float[resourceMapWidth, resourceMapHeight]; - resourceInterpolation = 2; + resourceInterpolation = interpolation; resourceMapScale = resourceMapWidth / 360; randomEdges = false; if (map != null) @@ -352,14 +356,16 @@ internal void setWidth(int w) pix = new Color[w]; biomeIndex = new double[w]; stockBiomeColor = new Color[w]; - resourceMapWidth = 512; - resourceMapHeight = resourceMapWidth / 2; - resourceInterpolation = 8; + resourceMapHeight = SCANcontroller.controller.overlayMapHeight; + resourceMapWidth = resourceMapHeight * 2; + resourceInterpolation = SCANcontroller.controller.overlayInterpolation; resourceMapScale = resourceMapWidth / 360f; resourceCache = new float[resourceMapWidth, resourceMapHeight]; randomEdges = true; mapscale = mapwidth / 360f; mapheight = (int)(w / 2); + startLine = 0; + stopLine = mapheight - 1; /* big map caching */ big_heightmap = new float[mapwidth, mapheight]; map = null; @@ -461,7 +467,7 @@ public void setBody(CelestialBody b) biomeMap = body.BiomeMap != null; data = SCANUtil.getData(body); - /* init cache if necessary */ + /* clear cache in place if necessary */ if (cache) { for (int x = 0; x < mapwidth; x++) @@ -514,6 +520,20 @@ public void resetMap(mapType mode, bool Cache, bool resourceOn, bool setRes = tr public void resetResourceMap() { + if (!zoom) + { + if (SCANcontroller.controller.overlayMapHeight != resourceMapHeight) + { + resourceMapHeight = SCANcontroller.controller.overlayMapHeight; + resourceMapWidth = resourceMapHeight * 2; + resourceMapScale = resourceMapWidth / 360f; + resourceCache = new float[resourceMapWidth, resourceMapHeight]; + } + + if (SCANcontroller.controller.overlayInterpolation != resourceInterpolation) + resourceInterpolation = SCANcontroller.controller.overlayInterpolation; + } + for (int i = 0; i < resourceMapWidth; i++ ) { for (int j = 0; j < resourceMapHeight; j++) @@ -565,6 +585,7 @@ internal Texture2D getPartialMap() System.Random r = new System.Random(ResourceScenario.Instance.gameSettings.Seed); bool resourceOn = false; + bool mapHidden = mapstep < startLine || mapstep > stopLine; if (map == null) { @@ -573,6 +594,7 @@ internal Texture2D getPartialMap() for (int i = 0; i < pix.Length; ++i) pix[i] = palette.clear; map.SetPixels(pix); + mapline = new double[map.width]; } else if (mapstep >= map.height) { @@ -590,16 +612,23 @@ internal Texture2D getPartialMap() if (mapstep <= -2) { - if (!resourceOn) - { - mapstep++; - return map; - } - else - { + if (resourceOn) SCANuiUtil.generateResourceCache(ref resourceCache, resourceMapHeight, resourceMapWidth, resourceInterpolation, resourceMapScale, this); - mapstep++; - return map; + + mapstep++; + return map; + } + + if (mapstep <= -1) + { + if (resourceOn) + { + for (int i = resourceInterpolation / 2; i >= 1; i /= 2) + { + SCANuiUtil.interpolate(resourceCache, resourceMapHeight, resourceMapWidth, i, i, i, r, randomEdges, zoom); + SCANuiUtil.interpolate(resourceCache, resourceMapHeight, resourceMapWidth, 0, i, i, r, randomEdges, zoom); + SCANuiUtil.interpolate(resourceCache, resourceMapHeight, resourceMapWidth, i, 0, i, r, randomEdges, zoom); + } } } @@ -625,6 +654,9 @@ internal Texture2D getPartialMap() if (mapstep < 0) continue; + if (mapHidden) + continue; + if (mType != mapType.Biome || !biomeMap) continue; @@ -652,24 +684,18 @@ internal Texture2D getPartialMap() if (mapstep <= -1) { - if (resourceOn) - { - for (int i = resourceInterpolation / 2; i >= 1; i /= 2) - { - SCANuiUtil.interpolate(resourceCache, resourceMapHeight, resourceMapWidth, i, i, i, r, randomEdges, zoom); - SCANuiUtil.interpolate(resourceCache, resourceMapHeight, resourceMapWidth, 0, i, i, r, randomEdges, zoom); - SCANuiUtil.interpolate(resourceCache, resourceMapHeight, resourceMapWidth, i, 0, i, r, randomEdges, zoom); - } - } - - mapstep = -1; - mapline = new double[map.width]; mapstep++; return map; } for (int i = 0; i < map.width; i++) { + if (mapHidden) + { + pix[i] = palette.clear; + continue; + } + Color baseColor = palette.grey; pix[i] = baseColor; int scheme = SCANcontroller.controller.colours; @@ -697,7 +723,7 @@ internal Texture2D getPartialMap() else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) { projVal = terrainElevation(lon, lat, data, out scheme); - baseColor = palette.heightToColor(projVal, scheme, data); + baseColor = palette.heightToColor(projVal, scheme, data.TerrainConfig); } break; } diff --git a/SCANsat/SCAN_Map/SCANmapLegend.cs b/SCANsat/SCAN_Map/SCANmapLegend.cs index d20dd2952..2cf066dfa 100644 --- a/SCANsat/SCAN_Map/SCANmapLegend.cs +++ b/SCANsat/SCAN_Map/SCANmapLegend.cs @@ -32,34 +32,34 @@ public Texture2D Legend set { legend = value; } } - internal Texture2D getLegend(float min, float max, int scheme, SCANdata data) + internal Texture2D getLegend(float min, float max, int scheme, SCANterrainConfig terrain) { - if (legend != null && legendMin == min && legendMax == max && legendScheme == scheme && data.TerrainConfig.ColorPal.hash == dataPalette.hash) + if (legend != null && legendMin == min && legendMax == max && legendScheme == scheme && terrain.ColorPal.hash == dataPalette.hash) return legend; legend = new Texture2D(256, 1, TextureFormat.RGB24, false); legendMin = min; legendMax = max; legendScheme = scheme; - dataPalette = data.TerrainConfig.ColorPal; + dataPalette = terrain.ColorPal; Color[] pix = legend.GetPixels(); for (int x = 0; x < 256; ++x) { float val = (x * (max - min)) / 256f + min; - pix[x] = palette.heightToColor(val, scheme, data); + pix[x] = palette.heightToColor(val, scheme, terrain); } legend.SetPixels(pix); legend.Apply(); return legend; } - internal Texture2D getLegend(int scheme, SCANdata data) + internal Texture2D getLegend(int scheme, SCANterrainConfig terrain) { Texture2D t = new Texture2D(256, 1, TextureFormat.RGB24, false); Color[] pix = t.GetPixels(); for (int x = 0; x < 256; ++x) { - float val = (x * (data.TerrainConfig.MaxTerrain - data.TerrainConfig.MinTerrain)) / 256f + data.TerrainConfig.MinTerrain; - pix[x] = palette.heightToColor(val, scheme, data); + float val = (x * (terrain.MaxTerrain - terrain.MinTerrain)) / 256f + terrain.MinTerrain; + pix[x] = palette.heightToColor(val, scheme, terrain); } t.SetPixels(pix); t.Apply(); diff --git a/SCANsat/SCAN_PartModules/SCANsat.cs b/SCANsat/SCAN_PartModules/SCANsat.cs index 601878d8c..e986280c0 100644 --- a/SCANsat/SCAN_PartModules/SCANsat.cs +++ b/SCANsat/SCAN_PartModules/SCANsat.cs @@ -174,11 +174,26 @@ public override void OnLoad(ConfigNode node) foreach (ConfigNode RPMNode in RPMPersistence.GetNodes("Prop")) { string id = RPMNode.GetValue("Prop ID"); - int Mode = Convert.ToInt32(RPMNode.GetValue("Mode")); - int Color = Convert.ToInt32(RPMNode.GetValue("Color")); - int Zoom = Convert.ToInt32(RPMNode.GetValue("Zoom")); - bool Lines = Convert.ToBoolean(RPMNode.GetValue("Lines")); - RPMList.Add(new RPMPersistence(id, Mode, Color, Zoom, Lines)); + int m = 0; + int c = 0; + int z = 0; + int r = 0; + bool lines = true; + bool anom = true; + bool resource = true; + + int.TryParse(RPMNode.GetValue("Mode"), out m); + int.TryParse(RPMNode.GetValue("Color"), out c); + int.TryParse(RPMNode.GetValue("Zoom"), out z); + int.TryParse(RPMNode.GetValue("Resource"), out r); + if (!bool.TryParse(RPMNode.GetValue("Lines"), out lines)) + lines = true; + if (!bool.TryParse(RPMNode.GetValue("Anomalies"), out anom)) + anom = true; + if (!bool.TryParse(RPMNode.GetValue("DrawResource"), out resource)) + resource = true; + + RPMList.Add(new RPMPersistence(id, m, c, z, lines, anom, resource, r)); } } } @@ -201,7 +216,10 @@ public override void OnSave(ConfigNode node) RPMProp.AddValue("Mode", RPMMFD.RPMMode); RPMProp.AddValue("Color", RPMMFD.RPMColor); RPMProp.AddValue("Zoom", RPMMFD.RPMZoom); + RPMProp.AddValue("Resource", RPMMFD.RPMResource); RPMProp.AddValue("Lines", RPMMFD.RPMLines); + RPMProp.AddValue("Anomalies", RPMMFD.RPMAnomaly); + RPMProp.AddValue("DrawResource", RPMMFD.RPMDrawResource); RPMPersistence.AddNode(RPMProp); } node.AddNode(RPMPersistence); @@ -372,16 +390,18 @@ public void analyzeData(KSPActionParam param) /* SCAN: add static (a warning that we're low on electric charge) */ private void addStatic() { - SCANdata data = SCANUtil.getData(vessel.mainBody); - if (data == null) + if (SCANcontroller.controller == null) return; - Texture2D map = data.Map; - if (map != null) + + if (SCANcontroller.controller.mainMap == null) + return; + + if (SCANcontroller.controller.mainMap.Map == null) + return; + + for (int i = 0; i < 1000; i++) { - for (int i = 0; i < 1000; ++i) - { - map.SetPixel(UnityEngine.Random.Range(0, 360), UnityEngine.Random.Range(0, 180), palette.lerp(palette.black, palette.white, UnityEngine.Random.value)); - } + SCANcontroller.controller.mainMap.Map.SetPixel(UnityEngine.Random.Range(0, 360), UnityEngine.Random.Range(0, 180), palette.lerp(palette.black, palette.white, UnityEngine.Random.value)); } } diff --git a/SCANsat/SCAN_Toolbar/SCANtoolbar.cs b/SCANsat/SCAN_Toolbar/SCANtoolbar.cs index 6e1b849eb..68218d93b 100644 --- a/SCANsat/SCAN_Toolbar/SCANtoolbar.cs +++ b/SCANsat/SCAN_Toolbar/SCANtoolbar.cs @@ -25,6 +25,7 @@ class SCANtoolbar : MonoBehaviour private IButton SCANButton; private IButton MapButton; private IButton SmallButton; + private IButton OverlayButton; private IButton KSCButton; internal SCANtoolbar() @@ -36,6 +37,7 @@ internal SCANtoolbar() SCANButton = ToolbarManager.Instance.add("SCANsat", "UIMenu"); MapButton = ToolbarManager.Instance.add("SCANsat", "BigMap"); SmallButton = ToolbarManager.Instance.add("SCANsat", "SmallMap"); + OverlayButton = ToolbarManager.Instance.add("SCANsat", "Overlay"); //Fall back to some default toolbar icons if someone deletes the SCANsat icons or puts them in the wrong folder if (File.Exists(Path.Combine(new DirectoryInfo(KSPUtil.ApplicationRootPath).FullName, "GameData/SCANsat/Icons/SCANsat_Icon.png").Replace("\\", "/"))) @@ -50,10 +52,15 @@ internal SCANtoolbar() SmallButton.TexturePath = "SCANsat/Icons/SCANsat_SmallMap_Icon"; // from unity, edited by DG else SmallButton.TexturePath = "000_Toolbar/resize-cursor"; + if (File.Exists(Path.Combine(new DirectoryInfo(KSPUtil.ApplicationRootPath).FullName, "GameData/SCANsat/Icons/SCANsat_OverlayToolbar_Icon.png").Replace("\\", "/"))) + OverlayButton.TexturePath = "SCANsat/Icons/SCANsat_OverlayToolbar_Icon"; + else + OverlayButton.TexturePath = "000_Toolbar/resize-cursor"; SCANButton.ToolTip = "SCANsat"; MapButton.ToolTip = "SCANsat Big Map"; SmallButton.ToolTip = "SCANsat Small Map"; + OverlayButton.ToolTip = "SCANsat Overlay Controller"; SCANButton.OnClick += (e) => { @@ -78,6 +85,13 @@ internal SCANtoolbar() SCANcontroller.controller.mainMapVisible = !SCANcontroller.controller.mainMapVisible; } }; + OverlayButton.OnClick += (e) => + { + if (SCANcontroller.controller != null) + { + SCANcontroller.controller.resourceOverlay.Visible = !SCANcontroller.controller.resourceOverlay.Visible; + } + }; } else if (HighLogic.LoadedScene == GameScenes.SPACECENTER || HighLogic.LoadedScene == GameScenes.TRACKSTATION) { @@ -176,6 +190,8 @@ internal void OnDestroy() SmallButton.Destroy(); if (KSCButton != null) KSCButton.Destroy(); + if (OverlayButton != null) + OverlayButton.Destroy(); } } diff --git a/SCANsat/SCAN_UI/SCANbigMap.cs b/SCANsat/SCAN_UI/SCANbigMap.cs index 8f78989fe..1c89af2e3 100644 --- a/SCANsat/SCAN_UI/SCANbigMap.cs +++ b/SCANsat/SCAN_UI/SCANbigMap.cs @@ -237,8 +237,8 @@ protected override void DrawWindowPost(int id) SCANcontroller.controller.colours = 1; else SCANcontroller.controller.colours = 0; - data.resetImages(); bigmap.resetMap(SCANcontroller.controller.map_ResourceOverlay); + SCANcontroller.controller.mainMap.resetImages(); } //Update grid overlay status @@ -307,26 +307,6 @@ private void topMenu(int id) drop_down_open = !drop_down_open; } fillS(40); - //if (GUILayout.Button("R", GUILayout.Width(20))) - // step = 0; - //if (GUILayout.Button("Map", GUILayout.Width(60))) - //{ - // overlay = !overlay; - // if (bigmap.Resource.MapOverlay == null) - // { - // bigmap.Resource.MapOverlay = new Texture2D(512, 256, TextureFormat.ARGB32, true); - // Color[] pix = bigmap.Resource.MapOverlay.GetPixels(); - // for (int i = 0; i < pix.Length; i++) - // pix[i] = palette.clear; - // bigmap.Resource.MapOverlay.SetPixels(pix); - // } - // if (overlay) - // Body.SetResourceMap(bigmap.Resource.MapOverlay); - // else - // Body.SetResourceMap(null); - //} - //if (overlay) - // SCANuiUtil.drawResourceTexture(256, ref step, data, bigmap.Resource); } if (GUILayout.Button("Celestial Body", GUILayout.MaxWidth(110))) { @@ -691,7 +671,7 @@ private void legendBar(int id) { if (bigmap.MapLegend == null) bigmap.MapLegend = new SCANmapLegend(); - bigmap.MapLegend.Legend = bigmap.MapLegend.getLegend(data.TerrainConfig.MinTerrain, data.TerrainConfig.MaxTerrain, SCANcontroller.controller.colours, data); + bigmap.MapLegend.Legend = bigmap.MapLegend.getLegend(data.TerrainConfig.MinTerrain, data.TerrainConfig.MaxTerrain, SCANcontroller.controller.colours, data.TerrainConfig); SCANuiUtil.drawLegend(data, bigmap.MapLegend); } } diff --git a/SCANsat/SCAN_UI/SCANcolorSelection.cs b/SCANsat/SCAN_UI/SCANcolorSelection.cs index d8531bffc..59998e06c 100644 --- a/SCANsat/SCAN_UI/SCANcolorSelection.cs +++ b/SCANsat/SCAN_UI/SCANcolorSelection.cs @@ -26,7 +26,7 @@ namespace SCANsat.SCAN_UI { class SCANcolorSelection: SCAN_MBW { - private bool dropDown, paletteBox, resourceBox, saveWarning; + private bool dropDown, paletteBox, resourceBox, planetBox, saveWarning; private bool oldReverseState, oldDiscreteState; private bool controlLock, clampState, oldClampState; private Rect ddRect; @@ -35,6 +35,7 @@ class SCANcolorSelection: SCAN_MBW private int windowMode = 0; private SCANterrainConfig currentTerrain; + private SCANterrainConfig bodyTerrain; private float minT, maxT, clampT, pSize; private SCANuiSlider minTerrainSlider, maxTerrainSlider, clampTerrainSlider, paletteSizeSlider, resourceMinSlider, resourceMaxSlider, resourceTransSlider, biomeTransSlider; @@ -63,7 +64,7 @@ class SCANcolorSelection: SCAN_MBW private SCANBigMap bigMapObj; private static SCANmap bigMap; - private SCANdata data; + private CelestialBody body; protected override void Awake() { @@ -88,7 +89,9 @@ protected override void Start() if (SCANkscMap.BigMap != null) bigMap = SCANkscMap.BigMap; if (kscMapObj.Data != null) - data = kscMapObj.Data; + body = kscMapObj.Body; + if (body == null) + body = Planetarium.fetch.Home; } else if (HighLogic.LoadedSceneIsFlight) { @@ -96,28 +99,22 @@ protected override void Start() if (SCANBigMap.BigMap != null) bigMap = SCANBigMap.BigMap; if (bigMapObj.Data != null) - data = bigMapObj.Data; + body = bigMapObj.Data.Body; + if (body == null) + body = FlightGlobals.currentMainBody; } - if (data == null) - { - data = SCANUtil.getData(Planetarium.fetch.Home); - if (data == null) - { - data = new SCANdata(Planetarium.fetch.Home); - SCANcontroller.controller.addToBodyData(Planetarium.fetch.Home, data); - } - } + setBodyTerrain(); - currentTerrain = new SCANterrainConfig(data.TerrainConfig); + currentTerrain = new SCANterrainConfig(bodyTerrain); stockBiomes = SCANcontroller.controller.useStockBiomes; biomeBorders = SCANcontroller.controller.biomeBorder; - minTerrainSlider = new SCANuiSlider(data.TerrainConfig.DefaultMinHeight - SCANconfigLoader.SCANNode.RangeBelowMinHeight, data.TerrainConfig.MaxTerrain - 100, data.TerrainConfig.MinTerrain, "Min: ", "m", -2); - maxTerrainSlider = new SCANuiSlider(data.TerrainConfig.MinTerrain + 100, data.TerrainConfig.DefaultMaxHeight + SCANconfigLoader.SCANNode.RangeAboveMaxHeight, data.TerrainConfig.MaxTerrain, "Max: ", "m", -2); - clampTerrainSlider = new SCANuiSlider(data.TerrainConfig.MinTerrain + 10, data.TerrainConfig.MaxTerrain - 10, data.TerrainConfig.ClampTerrain ?? data.TerrainConfig.MinTerrain + 10, "Clamp: ", "m", -1); - paletteSizeSlider = new SCANuiSlider(3, 12, data.TerrainConfig.PalSize, "Palette Size: ", "", 0); + minTerrainSlider = new SCANuiSlider(currentTerrain.DefaultMinHeight - SCANconfigLoader.SCANNode.RangeBelowMinHeight, currentTerrain.MaxTerrain - 100, currentTerrain.MinTerrain, "Min: ", "m", -2); + maxTerrainSlider = new SCANuiSlider(currentTerrain.MinTerrain + 100, currentTerrain.DefaultMaxHeight + SCANconfigLoader.SCANNode.RangeAboveMaxHeight, currentTerrain.MaxTerrain, "Max: ", "m", -2); + clampTerrainSlider = new SCANuiSlider(currentTerrain.MinTerrain + 10, currentTerrain.MaxTerrain - 10, currentTerrain.ClampTerrain ?? currentTerrain.MinTerrain + 10, "Clamp: ", "m", -1); + paletteSizeSlider = new SCANuiSlider(3, 12, currentTerrain.PalSize, "Palette Size: ", "", 0); slopeColorPickerLow = new SCANuiColorPicker(SCANcontroller.controller.lowSlopeColorOne, SCANcontroller.controller.highSlopeColorOne, true); slopeColorPickerHigh = new SCANuiColorPicker(SCANcontroller.controller.lowSlopeColorTwo, SCANcontroller.controller.highSlopeColorTwo, true); @@ -136,7 +133,7 @@ protected override void Start() { loadedResources = SCANcontroller.setLoadedResourceList(); currentResource = new SCANresourceGlobal(loadedResources[0]); - currentResource.CurrentBodyConfig(data.Body.name); + currentResource.CurrentBodyConfig(body.name); if (currentResource != null) { @@ -148,7 +145,7 @@ protected override void Start() } } - bodyIndex = data.Body.flightGlobalsIndex; + bodyIndex = body.flightGlobalsIndex; if (windowMode > 3 || (windowMode > 2 && !SCANconfigLoader.GlobalResource)) windowMode = 0; @@ -170,143 +167,75 @@ internal void removeControlLocks() protected override void DrawWindowPre(int id) { //Some clumsy logic is used here to ensure that the color selection fields always remain in sync with the current map in each scene - if (HighLogic.LoadedSceneIsFlight) + switch (HighLogic.LoadedScene) { - if (data == null) - { - data = SCANUtil.getData(FlightGlobals.currentMainBody); - if (data == null) + case GameScenes.FLIGHT: + if (SCANBigMap.BigMap != null) { - data = new SCANdata(FlightGlobals.currentMainBody); - SCANcontroller.controller.addToBodyData(FlightGlobals.currentMainBody, data); + bigMap = SCANBigMap.BigMap; } - } - if (bigMapObj.Visible && SCANBigMap.BigMap != null) - { - data = bigMapObj.Data; - bigMap = SCANBigMap.BigMap; - } - else if (data.Body != FlightGlobals.currentMainBody) - { - data = SCANUtil.getData(FlightGlobals.currentMainBody); - if (data == null) + if (body == null) { - data = new SCANdata(FlightGlobals.currentMainBody); - SCANcontroller.controller.addToBodyData(FlightGlobals.currentMainBody, data); + body = FlightGlobals.currentMainBody; + } + break; + case GameScenes.SPACECENTER: + if (kscMapObj.Visible) + { + bigMap = SCANkscMap.BigMap; } - } - if (bigMap == null) - { - if (SCANBigMap.BigMap != null) + if (body == null) { - bigMap = SCANBigMap.BigMap; + body = Planetarium.fetch.Home; } - } - } - //Lock space center click through - Sync SCANdata - else if (HighLogic.LoadedScene == GameScenes.SPACECENTER) - { - if (data == null) - { - data = SCANUtil.getData(Planetarium.fetch.Home); - if (data == null) + Vector2 mousePos = Input.mousePosition; + mousePos.y = Screen.height - mousePos.y; + if (WindowRect.Contains(mousePos) && !controlLock) { - data = new SCANdata(Planetarium.fetch.Home); - SCANcontroller.controller.addToBodyData(Planetarium.fetch.Home, data); + InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS | ControlTypes.KSC_ALL, lockID); + controlLock = true; } - } - if (kscMapObj.Visible) - { - data = kscMapObj.Data; - bigMap = SCANkscMap.BigMap; - } - else if (data.Body != Planetarium.fetch.Home) - { - data = SCANUtil.getData(Planetarium.fetch.Home); - if (data == null) + else if (!WindowRect.Contains(mousePos) && controlLock) { - data = new SCANdata(Planetarium.fetch.Home); - SCANcontroller.controller.addToBodyData(Planetarium.fetch.Home, data); + removeControlLocks(); } - } - if (bigMap == null) - { - if (SCANkscMap.BigMap != null) + break; + case GameScenes.TRACKSTATION: + if (kscMapObj.Visible) { bigMap = SCANkscMap.BigMap; } - } - Vector2 mousePos = Input.mousePosition; - mousePos.y = Screen.height - mousePos.y; - if (WindowRect.Contains(mousePos) && !controlLock) - { - InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS | ControlTypes.KSC_ALL, lockID); - controlLock = true; - } - else if (!WindowRect.Contains(mousePos) && controlLock) - { - removeControlLocks(); - } - } - //Lock tracking scene click through - Sync SCANdata - else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) - { - if (data == null) - { - data = SCANUtil.getData(Planetarium.fetch.Home); - if (data == null) + if (body == null) { - data = new SCANdata(Planetarium.fetch.Home); - SCANcontroller.controller.addToBodyData(Planetarium.fetch.Home, data); + body = Planetarium.fetch.Home; } - } - if (kscMapObj.Visible) - { - data = kscMapObj.Data; - bigMap = SCANkscMap.BigMap; - } - else if (data.Body != Planetarium.fetch.Home) - { - data = SCANUtil.getData(Planetarium.fetch.Home); - if (data == null) + + Vector2 mousePosT = Input.mousePosition; + mousePosT.y = Screen.height - mousePosT.y; + if (WindowRect.Contains(mousePosT) && !controlLock) { - data = new SCANdata(Planetarium.fetch.Home); - SCANcontroller.controller.addToBodyData(Planetarium.fetch.Home, data); + InputLockManager.SetControlLock(ControlTypes.TRACKINGSTATION_UI, lockID); + controlLock = true; } - } - if (bigMap == null) - { - if (SCANkscMap.BigMap != null) + else if (!WindowRect.Contains(mousePosT) && controlLock) { - bigMap = SCANkscMap.BigMap; + removeControlLocks(); } - } - Vector2 mousePos = Input.mousePosition; - mousePos.y = Screen.height - mousePos.y; - if (WindowRect.Contains(mousePos) && !controlLock) - { - InputLockManager.SetControlLock(ControlTypes.TRACKINGSTATION_UI, lockID); - controlLock = true; - } - else if (!WindowRect.Contains(mousePos) && controlLock) - { - removeControlLocks(); - } + break; } //This updates all of the fields whenever the palette selection is changed - if (windowMode == 0 && (currentLegend == null || bodyIndex != data.Body.flightGlobalsIndex)) + if (windowMode == 0 && (currentLegend == null || bodyIndex != body.flightGlobalsIndex)) { - currentTerrain = new SCANterrainConfig(data.TerrainConfig); + setBodyTerrain(); - SCANUtil.SCANdebugLog("Trigger Body Change"); - bodyIndex = data.Body.flightGlobalsIndex; + currentTerrain = new SCANterrainConfig(bodyTerrain); - currentTerrain = new SCANterrainConfig(data.TerrainConfig); + bodyIndex = body.flightGlobalsIndex; updateUI(); } @@ -320,6 +249,7 @@ protected override void DrawWindowPre(int id) { paletteBox = false; resourceBox = false; + planetBox = false; saveWarning = false; } } @@ -375,7 +305,7 @@ protected override void DrawWindow(int id) growE(); fillS(10); resourceColorPicker.drawColorSelector(WindowRect); - fillS(90); + fillS(120); growS(); resourceOptions(id); resourceConfirm(id); @@ -397,107 +327,111 @@ protected override void DrawWindowPost(int id) } //These methods update all of the UI elements whenever any of the options are changed - if (windowMode == 0) + switch (windowMode) { - if (currentTerrain.PalRev != oldReverseState) - { - oldReverseState = currentTerrain.PalRev; - drawPreviewLegend(); - } + case 0: + if (currentTerrain.PalRev != oldReverseState) + { + oldReverseState = currentTerrain.PalRev; + drawPreviewLegend(); + } - if (minTerrainSlider.valueChanged() || maxTerrainSlider.valueChanged()) - { - setTerrainSliders(); - } + if (minTerrainSlider.valueChanged() || maxTerrainSlider.valueChanged()) + { + setTerrainSliders(); + } - if (currentTerrain.PalDis != oldDiscreteState) - { - oldDiscreteState = currentTerrain.PalDis; - drawPreviewLegend(); - } + if (currentTerrain.PalDis != oldDiscreteState) + { + oldDiscreteState = currentTerrain.PalDis; + drawPreviewLegend(); + } - if (clampState != oldClampState) - { - oldClampState = clampState; - drawPreviewLegend(); - } + if (clampState != oldClampState) + { + oldClampState = clampState; + drawPreviewLegend(); + } - if (paletteSizeSlider.valueChanged()) - { - regenPaletteSets(); - currentTerrain.ColorPal = palette.CurrentPalettes.availablePalettes[paletteIndex]; - drawPreviewLegend(); - } - } - else if (windowMode == 1) - { - slopeColorPickerLow.colorStateChanged(); - slopeColorPickerLow.brightnessChanged(); - slopeColorPickerHigh.colorStateChanged(); - slopeColorPickerHigh.brightnessChanged(); - } - else if (windowMode == 2) - { - biomeColorPicker.colorStateChanged(); - biomeColorPicker.brightnessChanged(); - } - else if (windowMode == 3) - { - if (resourceMinSlider.valueChanged() || resourceMaxSlider.valueChanged()) - { - setResourceSliders(); - } + if (paletteSizeSlider.valueChanged()) + { + regenPaletteSets(); + currentTerrain.ColorPal = palette.CurrentPalettes.availablePalettes[paletteIndex]; + drawPreviewLegend(); + } + break; + + case 1: + slopeColorPickerLow.colorStateChanged(); + slopeColorPickerLow.brightnessChanged(); + slopeColorPickerHigh.colorStateChanged(); + slopeColorPickerHigh.brightnessChanged(); + break; + + case 2: + biomeColorPicker.colorStateChanged(); + biomeColorPicker.brightnessChanged(); + break; + + case 3: + if (resourceMinSlider.valueChanged() || resourceMaxSlider.valueChanged()) + { + setResourceSliders(); + } - if (bodyIndex != data.Body.flightGlobalsIndex) - { - SCANUtil.SCANdebugLog("Trigger Body Change"); - bodyIndex = data.Body.flightGlobalsIndex; + if (bodyIndex != body.flightGlobalsIndex) + { + SCANUtil.SCANdebugLog("Trigger Body Change"); + bodyIndex = body.flightGlobalsIndex; - currentResource.CurrentBodyConfig(data.Body.name); + currentResource.CurrentBodyConfig(body.name); - lowRCutoff = currentResource.CurrentBody.MinValue; - highRCutoff = currentResource.CurrentBody.MaxValue; + lowRCutoff = currentResource.CurrentBody.MinValue; + highRCutoff = currentResource.CurrentBody.MaxValue; - oldFineControl = fineControlMode = false; + oldFineControl = fineControlMode = false; - setResourceSliders(); - } + setResourceSliders(); + } - if (oldFineControl != fineControlMode) - { - oldFineControl = fineControlMode; - if (fineControlMode) + if (oldFineControl != fineControlMode) { - if (lowRCutoff < 5f) - resourceMinSlider.MinValue = 0f; - else - resourceMinSlider.MinValue = lowRCutoff - 5; - - if (lowRCutoff > 95f) - resourceMinSlider.MaxValue = 100f; - else if (highRCutoff < lowRCutoff + 5f) - resourceMinSlider.MaxValue = highRCutoff - 0.1f; - else - resourceMinSlider.MaxValue = lowRCutoff + 5f; - - if (highRCutoff < 5f) - resourceMaxSlider.MinValue = 0f; - else if (lowRCutoff > highRCutoff - 5f) - resourceMaxSlider.MinValue = lowRCutoff + 0.1f; - else - resourceMaxSlider.MinValue = highRCutoff - 5f; - - if (highRCutoff > 95f) - resourceMaxSlider.MaxValue = 100f; + oldFineControl = fineControlMode; + if (fineControlMode) + { + if (lowRCutoff < 5f) + resourceMinSlider.MinValue = 0f; + else + resourceMinSlider.MinValue = lowRCutoff - 5; + + if (lowRCutoff > 95f) + resourceMinSlider.MaxValue = 100f; + else if (highRCutoff < lowRCutoff + 5f) + resourceMinSlider.MaxValue = highRCutoff - 0.1f; + else + resourceMinSlider.MaxValue = lowRCutoff + 5f; + + if (highRCutoff < 5f) + resourceMaxSlider.MinValue = 0f; + else if (lowRCutoff > highRCutoff - 5f) + resourceMaxSlider.MinValue = lowRCutoff + 0.1f; + else + resourceMaxSlider.MinValue = highRCutoff - 5f; + + if (highRCutoff > 95f) + resourceMaxSlider.MaxValue = 100f; + else + resourceMaxSlider.MaxValue = highRCutoff + 5f; + } else - resourceMaxSlider.MaxValue = highRCutoff + 5f; + setResourceSliders(); } - else - setResourceSliders(); - } - resourceColorPicker.colorStateChanged(); - resourceColorPicker.brightnessChanged(); + resourceColorPicker.colorStateChanged(); + resourceColorPicker.brightnessChanged(); + break; + default: + break; } sessionRect = WindowRect; @@ -529,9 +463,11 @@ private void windowTabs(int id) { windowMode = 0; - currentTerrain = new SCANterrainConfig(data.TerrainConfig); + setBodyTerrain(); + + currentTerrain = new SCANterrainConfig(bodyTerrain); - bodyIndex = data.Body.flightGlobalsIndex; + bodyIndex = body.flightGlobalsIndex; updateUI(); } @@ -551,9 +487,9 @@ private void windowTabs(int id) fineControlMode = oldFineControl = false; - currentResource.CurrentBodyConfig(data.Body.name); + currentResource.CurrentBodyConfig(body.name); - bodyIndex = data.Body.flightGlobalsIndex; + bodyIndex = body.flightGlobalsIndex; updateUI(); } @@ -621,28 +557,40 @@ private void paletteOptions(int id) { growS(); fillS(4); - GUILayout.Label("Terrain Options: " + data.Body.name, SCANskins.SCAN_headlineSmall); + growE(); + fillS(20); + GUILayout.Label("Terrain Options: ", SCANskins.SCAN_headlineSmall, GUILayout.Width(150)); + + if (GUILayout.Button(body.name, SCANskins.SCAN_headerButton, GUILayout.Width(170))) + { + dropDown = !dropDown; + planetBox = !planetBox; + } + stopE(); growE(); fillS(10); - currentTerrain.MinTerrain = minTerrainSlider.drawSlider(false, ref minT); + currentTerrain.MinTerrain = minTerrainSlider.drawSlider(dropDown, ref minT); stopE(); fillS(8); growE(); fillS(10); - currentTerrain.MaxTerrain = maxTerrainSlider.drawSlider(false, ref maxT); + currentTerrain.MaxTerrain = maxTerrainSlider.drawSlider(dropDown, ref maxT); stopE(); fillS(6); growE(); fillS(); - clampState = GUILayout.Toggle(clampState, "Clamp Terrain", SCANskins.SCAN_settingsToggle, GUILayout.Width(100)); + if (dropDown) + GUILayout.Label("Clamp Terrain", SCANskins.SCAN_settingsToggle, GUILayout.Width(100)); + else + clampState = GUILayout.Toggle(clampState, "Clamp Terrain", SCANskins.SCAN_settingsToggle, GUILayout.Width(100)); fillS(); stopE(); if (clampState) { growE(); fillS(10); - currentTerrain.ClampTerrain = clampTerrainSlider.drawSlider(false, ref clampT); + currentTerrain.ClampTerrain = clampTerrainSlider.drawSlider(dropDown, ref clampT); stopE(); } fillS(6); @@ -651,14 +599,23 @@ private void paletteOptions(int id) { growE(); fillS(10); - currentTerrain.PalSize = (int)paletteSizeSlider.drawSlider(false, ref pSize); + currentTerrain.PalSize = (int)paletteSizeSlider.drawSlider(dropDown, ref pSize); stopE(); } growE(); - currentTerrain.PalRev = GUILayout.Toggle(currentTerrain.PalRev, " Reverse Order", SCANskins.SCAN_boldToggle, GUILayout.Width(120)); - fillS(10); - currentTerrain.PalDis = GUILayout.Toggle(currentTerrain.PalDis, " Discrete Gradient", SCANskins.SCAN_boldToggle, GUILayout.Width(140)); + if (dropDown) + { + GUILayout.Label(" Reverse Order", SCANskins.SCAN_boldToggle, GUILayout.Width(120)); + fillS(10); + GUILayout.Label(" Discrete Gradient", SCANskins.SCAN_boldToggle, GUILayout.Width(140)); + } + else + { + currentTerrain.PalRev = GUILayout.Toggle(currentTerrain.PalRev, " Reverse Order", SCANskins.SCAN_boldToggle, GUILayout.Width(120)); + fillS(10); + currentTerrain.PalDis = GUILayout.Toggle(currentTerrain.PalDis, " Discrete Gradient", SCANskins.SCAN_boldToggle, GUILayout.Width(140)); + } stopE(); stopS(); @@ -699,7 +656,7 @@ private void paletteConfirmation(int id) updateUI(); - if (bigMap != null) + if (bigMap != null && bigMap.Body == body) { if (bigMap.MType == mapType.Altimetry && SCANcontroller.controller.colours == 0) bigMap.resetMap(SCANcontroller.controller.map_ResourceOverlay); @@ -710,17 +667,21 @@ private void paletteConfirmation(int id) if (GUILayout.Button("Default Values", GUILayout.Width(110))) { - currentTerrain.MinTerrain = data.TerrainConfig.DefaultMinHeight; - currentTerrain.MaxTerrain = data.TerrainConfig.DefaultMaxHeight; - currentTerrain.ClampTerrain = data.TerrainConfig.DefaultClampHeight; - currentTerrain.ColorPal = data.TerrainConfig.DefaultPalette; - currentTerrain.PalRev = data.TerrainConfig.DefaultReverse; - currentTerrain.PalDis = data.TerrainConfig.DefaultDiscrete; - currentTerrain.PalSize = data.TerrainConfig.DefaultPaletteSize; + setBodyTerrain(); + + currentTerrain.MinTerrain = bodyTerrain.DefaultMinHeight; + currentTerrain.MaxTerrain = bodyTerrain.DefaultMaxHeight; + currentTerrain.ClampTerrain = bodyTerrain.DefaultClampHeight; + currentTerrain.ColorPal = bodyTerrain.DefaultPalette; + currentTerrain.PalRev = bodyTerrain.DefaultReverse; + currentTerrain.PalDis = bodyTerrain.DefaultDiscrete; + currentTerrain.PalSize = bodyTerrain.DefaultPaletteSize; + + SCANcontroller.updateTerrainConfig(currentTerrain); updateUI(); - if (bigMap != null) + if (bigMap != null && bigMap.Body == body) { if (bigMap.MType == mapType.Altimetry && SCANcontroller.controller.colours == 0) bigMap.resetMap(SCANcontroller.controller.map_ResourceOverlay); @@ -770,23 +731,43 @@ private void slopeOptions(int id) private void resourceOptions(int id) { - GUILayout.Label("Resource Options: " + data.Body.name, SCANskins.SCAN_headline, GUILayout.Width(300)); + growE(); + + fillS(30); + GUILayout.Label("Resource Options: ", SCANskins.SCAN_headlineSmall, GUILayout.Width(150)); + + if (GUILayout.Button(body.name, SCANskins.SCAN_headerButton, GUILayout.Width(170))) + { + dropDown = !dropDown; + planetBox = !planetBox; + } + + stopE(); fillS(10); growE(); - if (GUILayout.Button("Resource Selection:")) + fillS(20); + GUILayout.Label("Resource Selection: ", SCANskins.SCAN_headlineSmall, GUILayout.Width(180)); + + if (dropDown) { - dropDown = !dropDown; - resourceBox = !resourceBox; + GUILayout.Label(currentResource.Name, SCANskins.SCAN_headerButton, GUILayout.Width(140)); } - fillS(10); - GUILayout.Label(currentResource.Name, SCANskins.SCAN_whiteReadoutLabel); + else + { + if (GUILayout.Button(currentResource.Name, SCANskins.SCAN_headerButton, GUILayout.Width(140))) + { + dropDown = !dropDown; + resourceBox = !resourceBox; + } + } + stopE(); - fillS(20); + fillS(10); growE(); fillS(110); if (dropDown) - GUILayout.Toggle(fineControlMode, " Fine Control Mode", SCANskins.SCAN_boldToggle, GUILayout.Width(140)); + GUILayout.Label(" Fine Control Mode", SCANskins.SCAN_boldToggle, GUILayout.Width(140)); else fineControlMode = GUILayout.Toggle(fineControlMode, " Fine Control Mode", SCANskins.SCAN_boldToggle, GUILayout.Width(140)); stopE(); @@ -1089,7 +1070,7 @@ private void dropDownBox(int id) } else if (resourceBox && windowMode == 3) { - ddRect = new Rect(WindowRect.width - 440, 115, 160, 140); + ddRect = new Rect(WindowRect.width - 240, 112, 160, 140); GUI.Box(ddRect, ""); for (int i = 0; i < loadedResources.Count; i ++) { @@ -1098,7 +1079,7 @@ private void dropDownBox(int id) if (GUI.Button(r, loadedResources[i].Name, currentResource.Name == loadedResources[i].Name ? SCANskins.SCAN_dropDownButtonActive : SCANskins.SCAN_dropDownButton)) { currentResource = new SCANresourceGlobal(loadedResources[i]); - currentResource.CurrentBodyConfig(data.Body.name); + currentResource.CurrentBodyConfig(body.name); fineControlMode = oldFineControl = false; @@ -1110,6 +1091,47 @@ private void dropDownBox(int id) GUI.EndScrollView(); } } + else if (planetBox) + { + ddRect = new Rect(WindowRect.width - 250, 78, 180, 180); + GUI.Box(ddRect, ""); + for (int i = 0; i < FlightGlobals.Bodies.Count; i++) + { + CelestialBody b = FlightGlobals.Bodies[i]; + scrollR = GUI.BeginScrollView(ddRect, scrollR, new Rect(0, 0, 140, 23 * FlightGlobals.Bodies.Count)); + Rect r = new Rect(2, i * 23, 136, 22); + if (GUI.Button(r, b.name, body == b ? SCANskins.SCAN_dropDownButtonActive : SCANskins.SCAN_dropDownButton)) + { + body = b; + + bodyIndex = body.flightGlobalsIndex; + + if (windowMode == 0) + { + setBodyTerrain(); + + currentTerrain = new SCANterrainConfig(bodyTerrain); + } + else if (windowMode == 3) + { + currentResource.CurrentBodyConfig(body.name); + + lowRCutoff = currentResource.CurrentBody.MinValue; + highRCutoff = currentResource.CurrentBody.MaxValue; + + oldFineControl = fineControlMode = false; + + setResourceSliders(); + } + + updateUI(); + + dropDown = false; + planetBox = false; + } + GUI.EndScrollView(); + } + } else if (saveWarning) { ddRect = new Rect(WindowRect.width - 182, WindowRect.height - 92, 180, 90); @@ -1175,7 +1197,7 @@ private void updateUI() private void drawCurrentLegend() { currentLegend = new SCANmapLegend(); - currentLegend.Legend = currentLegend.getLegend(0, data); + currentLegend.Legend = currentLegend.getLegend(0, bodyTerrain); } //Draws the palette swatch for the newly adjusted palette @@ -1233,8 +1255,10 @@ private void setSizeSlider(Palette.Kind k) //Dynamically adjust the min and max values on all of the terrain height sliders; avoids impossible values private void setTerrainSliders() { - minTerrainSlider.MinValue = data.TerrainConfig.DefaultMinHeight - SCANconfigLoader.SCANNode.RangeBelowMinHeight; - maxTerrainSlider.MaxValue = data.TerrainConfig.DefaultMaxHeight + SCANconfigLoader.SCANNode.RangeAboveMaxHeight; + setBodyTerrain(); + + minTerrainSlider.MinValue = bodyTerrain.DefaultMinHeight - SCANconfigLoader.SCANNode.RangeBelowMinHeight; + maxTerrainSlider.MaxValue = bodyTerrain.DefaultMaxHeight + SCANconfigLoader.SCANNode.RangeAboveMaxHeight; minTerrainSlider.MaxValue = maxT - 100f; maxTerrainSlider.MinValue = minT + 100f; clampTerrainSlider.MinValue = minT + 10f; @@ -1264,5 +1288,21 @@ private void setResourceSliders() } } + private void setBodyTerrain() + { + bodyTerrain = SCANcontroller.getTerrainNode(body.name); + + if (bodyTerrain == null) + { + float? clamp = null; + if (body.ocean) + clamp = 0; + + bodyTerrain = new SCANterrainConfig(SCANconfigLoader.SCANNode.DefaultMinHeightRange, SCANconfigLoader.SCANNode.DefaultMaxHeightRange, clamp, SCANUtil.paletteLoader(SCANconfigLoader.SCANNode.DefaultPalette, 7), 7, false, false, body); + + SCANcontroller.addToTerrainConfigData(body.name, bodyTerrain); + } + } + } } diff --git a/SCANsat/SCAN_UI/SCANinstrumentUI.cs b/SCANsat/SCAN_UI/SCANinstrumentUI.cs index d6ca7d888..b4bb687cc 100644 --- a/SCANsat/SCAN_UI/SCANinstrumentUI.cs +++ b/SCANsat/SCAN_UI/SCANinstrumentUI.cs @@ -91,8 +91,6 @@ protected override void OnDestroy() protected override void DrawWindowPre(int id) { - v = FlightGlobals.ActiveVessel; - vlat = SCANUtil.fixLatShift(v.latitude); vlon = SCANUtil.fixLonShift(v.longitude); @@ -105,11 +103,12 @@ protected override void DrawWindowPre(int id) //Check if region below the vessel is scanned if (SCANUtil.isCovered(vlon, vlat, data, SCANtype.AltimetryLoRes)) { - sensors |= SCANtype.Altimetry; + sensors |= SCANtype.AltimetryLoRes; } - else if (SCANUtil.isCovered(vlon, vlat, data, SCANtype.AltimetryHiRes)) + + if (SCANUtil.isCovered(vlon, vlat, data, SCANtype.AltimetryHiRes)) { - sensors |= SCANtype.Altimetry; + sensors |= SCANtype.AltimetryHiRes; } if (SCANUtil.isCovered(vlon, vlat, data, SCANtype.Biome)) @@ -223,24 +222,55 @@ private void biomeInfo(int id) //Display the current vessel altitude private void altInfo(int id) { + double h = v.altitude; + double pqs = 0; + if (v.mainBody.pqsController != null) + { + pqs = v.PQSAltitude(); + if (pqs > 0 || !v.mainBody.ocean) + h -= pqs; + } + if (h < 0) + h = v.altitude; + + bool drawSlope = false; + if ((sensors & SCANtype.Altimetry) != SCANtype.Nothing) { - double h = v.altitude; - double pqs = 0; - if (v.mainBody.pqsController != null) + switch (v.situation) { - pqs = v.PQSAltitude(); - if (pqs > 0 || !v.mainBody.ocean) - h -= pqs; + case Vessel.Situations.LANDED: + case Vessel.Situations.SPLASHED: + case Vessel.Situations.PRELAUNCH: + infoLabel += string.Format("\nTerrain: {0:N1}m", pqs); + drawSlope = true; + break; + default: + if (h < 1000 || (sensors & SCANtype.AltimetryHiRes) != SCANtype.Nothing) + { + infoLabel += string.Format("\nAltitude: {0}", SCANuiUtil.distanceString(h, 100000)); + drawSlope = true; + } + else + { + h = ((int)(h / 500)) * 500; + infoLabel += string.Format("\nAltitude: {0}", SCANuiUtil.distanceString(h, 100000)); + } + break; } - if (h < 0) - h = v.altitude; - + } + else if (h < 1000) + { if (v.situation == Vessel.Situations.LANDED || v.situation == Vessel.Situations.SPLASHED || v.situation == Vessel.Situations.PRELAUNCH) infoLabel += string.Format("\nTerrain: {0:N1}m", pqs); else infoLabel += string.Format("\nAltitude: {0}", SCANuiUtil.distanceString(h, 100000)); + drawSlope = true; + } + + if (drawSlope) + { //Calculate slope less frequently; the rapidly changing value makes it difficult to read otherwise if (v.mainBody.pqsController != null) { @@ -265,6 +295,9 @@ private void altInfo(int id) //Display resource abundace info private void resourceInfo(int id) { + if (v.mainBody.pqsController == null) + return; + if (SCANcontroller.controller.needsNarrowBand) { bool tooHigh = false; @@ -331,6 +364,9 @@ private void drawInfoLabel(int id) private void drawResourceButtons(int id) { + if (v.mainBody.pqsController == null) + return; + if (resources.Count > 1) { Rect r = GUILayoutUtility.GetLastRect(); @@ -459,6 +495,7 @@ private void soiChange (GameEvents.HostedFromToAction VC) private void vesselChange(Vessel V) { + v = FlightGlobals.ActiveVessel; resetResourceList(); } diff --git a/SCANsat/SCAN_UI/SCANkscMap.cs b/SCANsat/SCAN_UI/SCANkscMap.cs index ca1a47ded..a881f0414 100644 --- a/SCANsat/SCAN_UI/SCANkscMap.cs +++ b/SCANsat/SCAN_UI/SCANkscMap.cs @@ -159,36 +159,34 @@ protected override void DrawWindowPre(int id) planetoid_drop_down = false; } - //Lock space center click through - if (HighLogic.LoadedScene == GameScenes.SPACECENTER) + switch (HighLogic.LoadedScene) { - Vector2 mousePos = Input.mousePosition; - mousePos.y = Screen.height - mousePos.y; - if (WindowRect.Contains(mousePos) && !controlLock) - { - InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS | ControlTypes.KSC_ALL, lockID); - controlLock = true; - } - else if (!WindowRect.Contains(mousePos) && controlLock) - { - removeControlLocks(); - } - } - - //Lock tracking scene click through - if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) - { - Vector2 mousePos = Input.mousePosition; - mousePos.y = Screen.height - mousePos.y; - if (WindowRect.Contains(mousePos) && !controlLock) - { - InputLockManager.SetControlLock(ControlTypes.TRACKINGSTATION_UI, lockID); - controlLock = true; - } - else if (!WindowRect.Contains(mousePos) && controlLock) - { - removeControlLocks(); - } + case GameScenes.SPACECENTER: + Vector2 mousePos = Input.mousePosition; + mousePos.y = Screen.height - mousePos.y; + if (WindowRect.Contains(mousePos) && !controlLock) + { + InputLockManager.SetControlLock(ControlTypes.CAMERACONTROLS | ControlTypes.KSC_ALL, lockID); + controlLock = true; + } + else if (!WindowRect.Contains(mousePos) && controlLock) + { + removeControlLocks(); + } + break; + case GameScenes.TRACKSTATION: + Vector2 mousePosT = Input.mousePosition; + mousePosT.y = Screen.height - mousePosT.y; + if (WindowRect.Contains(mousePosT) && !controlLock) + { + InputLockManager.SetControlLock(ControlTypes.TRACKINGSTATION_UI, lockID); + controlLock = true; + } + else if (!WindowRect.Contains(mousePosT) && controlLock) + { + removeControlLocks(); + } + break; } } @@ -234,7 +232,6 @@ protected override void DrawWindowPost(int id) SCANcontroller.controller.colours = 1; else SCANcontroller.controller.colours = 0; - data.resetImages(); bigmap.resetMap(SCANcontroller.controller.map_ResourceOverlay); } @@ -609,7 +606,7 @@ private void legendBar(int id) { if (bigmap.MapLegend == null) bigmap.MapLegend = new SCANmapLegend(); - bigmap.MapLegend.Legend = bigmap.MapLegend.getLegend(data.TerrainConfig.MinTerrain, data.TerrainConfig.MaxTerrain, SCANcontroller.controller.colours, data); + bigmap.MapLegend.Legend = bigmap.MapLegend.getLegend(data.TerrainConfig.MinTerrain, data.TerrainConfig.MaxTerrain, SCANcontroller.controller.colours, data.TerrainConfig); SCANuiUtil.drawLegend(data, bigmap.MapLegend); } } diff --git a/SCANsat/SCAN_UI/SCANmainMap.cs b/SCANsat/SCAN_UI/SCANmainMap.cs index 348fe9b14..2165ba96d 100644 --- a/SCANsat/SCAN_UI/SCANmainMap.cs +++ b/SCANsat/SCAN_UI/SCANmainMap.cs @@ -33,6 +33,14 @@ class SCANmainMap: SCAN_MBW internal static readonly Rect defaultRect = new Rect(10, 55, 380, 230); private static Rect sessionRect = defaultRect; private bool flash; + private Texture2D map_small = new Texture2D(360, 180, TextureFormat.ARGB32, false); + private Color[] cols_height_map_small = new Color[360]; + private Color32[] biomeCache = new Color32[360 * 180]; + private bool biomeBuilding; + private bool drawBiome; + private double[] biomeIndex = new double[360]; + private int scanline; + private int scanstep; protected override void Awake() { @@ -60,6 +68,15 @@ protected override void Start() SCANcontroller.controller.addToBodyData(v.mainBody, data); } TooltipsEnabled = SCANcontroller.controller.toolTips; + + if (palette.small_redline == null) + { + palette.small_redline = new Color[360]; + for (int i = 0; i < 360; i++) + palette.small_redline[i] = palette.red; + } + + resetImages(); } protected override void DrawWindowPre(int id) @@ -85,7 +102,7 @@ protected override void DrawWindow(int id) scannerInfo(id); /* Draws the scanner indicators */ windowButtons(id); /* Draw the buttons for other SCANsat windows */ stopE(); - fillS(-8); + fillS(-6); vesselInfo(id); /* Shows info for any SCANsat vessels */ stopS(); } @@ -105,17 +122,18 @@ private void versionLabel(int id) //Draw the top menu items private void topMenu(int id) { - Rect r = new Rect(WindowRect.width - 40, 0, 18, 18); - if (showVesselInfo) - { - if (GUI.Button(r, "-", SCANskins.SCAN_buttonBorderless)) - showVesselInfo = !showVesselInfo; - } - else + Rect r = new Rect(WindowRect.width - 90, 2, 50, 18); + + if (GUI.Button(r, drawBiome ? "Biome" : "Terrain", SCANskins.SCAN_buttonBorderlessSmall)) { - if (GUI.Button(r, "+", SCANskins.SCAN_buttonBorderless)) - showVesselInfo = !showVesselInfo; + drawBiome = !drawBiome; + resetImages(); } + r.x += 50; + r.y -= 2; + r.width = 18; + if (GUI.Button(r, showVesselInfo ? "-" : "+", SCANskins.SCAN_buttonBorderless)) + showVesselInfo = !showVesselInfo; r.x += 20; r.y += 1; if (GUI.Button(r, SCANcontroller.controller.closeBox, SCANskins.SCAN_closeButton)) @@ -129,7 +147,7 @@ private void topMenu(int id) private void mainMap(int id) { mapRect = new Rect(10, 20, 360, 180); - GUI.DrawTexture(mapRect, data.drawPartialMap(sensors)); + GUI.DrawTexture(mapRect, drawBiome ? drawBiomeMap(sensors) : drawPartialMap(sensors)); if (data.Building || data.ExternalBuilding) { @@ -147,14 +165,12 @@ private void scannerInfo(int id) if (!repainting) infoText = SCANuiUtil.InfoText(v, data, notMappingToday); - if (infoText != null) - SCANuiUtil.readableLabel(infoText, false); + SCANuiUtil.readableLabel(infoText, false); } //Draw the SCANsat window buttons with icons private void windowButtons(int id) { - //fillS(); if (GUILayout.Button(iconWithTT(SCANskins.SCAN_BigMapIcon, "Big Map"), SCANskins.SCAN_windowButton, GUILayout.Height(32), GUILayout.Width(32))) { SCANcontroller.controller.BigMap.Visible = !SCANcontroller.controller.BigMap.Visible; @@ -209,10 +225,37 @@ private bool vesselInfo(Vessel scanV, Rect r, int i, bool b) } float lon = (float)SCANUtil.fixLonShift(scanV.longitude); float lat = (float)SCANUtil.fixLatShift(scanV.latitude); - float alt = scanV.heightFromTerrain; - if (alt < 0) - alt = (float)scanV.altitude; - string text = string.Format("[{0}] {1} ({2:F1}°,{3:F1}°; {4:N1}m)", i, scanV.vesselName, lat, lon, alt); + + string units = ""; + if (drawBiome) + { + if (SCANUtil.isCovered(lon, lat, data, SCANtype.Biome)) + units = "; " + SCANUtil.getBiomeName(data.Body, lon, lat); + } + else + { + if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) + { + if (SCANUtil.isCovered(lon, lat, data, SCANtype.AltimetryHiRes)) + { + float alt = scanV.heightFromTerrain; + if (alt < 0) + alt = (float)scanV.altitude; + units = "; " + SCANuiUtil.distanceString(alt, 100000); + } + else + { + float alt = scanV.heightFromTerrain; + if (alt < 0) + alt = (float)scanV.altitude; + + alt = ((int)(alt / 500)) * 500; + units = "; " + SCANuiUtil.distanceString(alt, 100000); + } + } + } + + string text = string.Format("[{0}] {1} ({2:F1}°,{3:F1}°{4})", i, scanV.vesselName, lat, lon, units); if (SCANuiUtil.readableLabel(text, b)) { if (Event.current.clickCount > 1) @@ -229,5 +272,186 @@ private bool vesselInfo(Vessel scanV, Rect r, int i, bool b) return false; } + private Texture2D drawPartialMap(SCANtype type) + { + bool pqsController = data.Body.pqsController != null; + + if (data.ExternalBuilding) + { + return map_small; + } + + if (!data.Built) + { + data.Building = true; + data.generateHeightMap(ref scanline, ref scanstep, 360); + return map_small; + } + + int scheme = SCANcontroller.controller.colours; + + for (int ilon = 0; ilon < 360; ilon++) + { + if (!pqsController) + { + cols_height_map_small[ilon] = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); + continue; + } + + Color c = palette.grey; + float val = data.HeightMapValue(data.Body.flightGlobalsIndex, ilon, scanline); + if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.Altimetry)) + { + if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.AltimetryHiRes)) + c = palette.heightToColor(val, scheme, data.TerrainConfig); + else + c = palette.heightToColor(val, 1, data.TerrainConfig); + } + else + { + if (scanline % 30 == 0 && ilon % 3 == 0) + { + c = palette.white; + } + else if (ilon % 30 == 0 && scanline % 3 == 0) + { + c = palette.white; + } + } + + if (type != SCANtype.Nothing) + { + if (!SCANUtil.isCoveredByAll(ilon, scanline, data, type)) + { + c = palette.lerp(c, palette.black, 0.5f); + } + } + + cols_height_map_small[ilon] = c; + } + + map_small.SetPixels(0, scanline, 360, 1, cols_height_map_small); + + if (scanline < 179) + map_small.SetPixels(0, scanline + 1, 360, 1, palette.small_redline); + + scanline++; + + if (scanline >= 180) + scanline = 0; + + map_small.Apply(); + + return map_small; + } + + private Texture2D drawBiomeMap(SCANtype type) + { + bool biomeMap = data.Body.BiomeMap != null; + + if (biomeBuilding) + buildBiomeCache(); + + int scheme = SCANcontroller.controller.colours; + + for (int ilon = 0; ilon < 360; ilon++) + { + if (!biomeMap) + { + cols_height_map_small[ilon] = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); + continue; + } + + Color c = biomeCache[scanline * 360 + ilon]; + if (!SCANUtil.isCovered(ilon, scanline, data, SCANtype.Biome)) + { + c = palette.grey; + } + + if (type != SCANtype.Nothing) + { + if (!SCANUtil.isCoveredByAll(ilon, scanline, data, type)) + { + c = palette.lerp(c, palette.black, 0.5f); + } + } + + cols_height_map_small[ilon] = c; + } + + map_small.SetPixels(0, scanline, 360, 1, cols_height_map_small); + + if (scanline < 179) + map_small.SetPixels(0, scanline + 1, 360, 1, palette.small_redline); + + scanline++; + + if (scanline >= 180) + scanline = 0; + + map_small.Apply(); + + return map_small; + } + + private void buildBiomeCache() + { + for (int i = 0; i < 360; i++) + { + double index = SCANUtil.getBiomeIndexFraction(data.Body, i - 180, scanline - 90); + Color c = palette.grey; + + if (SCANcontroller.controller.biomeBorder && ((i > 0 && biomeIndex[i - 1] != index) || (scanline > 0 && biomeIndex[i] != index))) + { + c = palette.white; + } + else if (SCANcontroller.controller.useStockBiomes) + { + c = SCANUtil.getBiome(data.Body, i - 180, scanline - 90).mapColor; + } + else + { + c = palette.lerp(SCANcontroller.controller.lowBiomeColor, SCANcontroller.controller.highBiomeColor, (float)index); + } + + biomeCache[scanline * 360 + i] = c; + + biomeIndex[i] = index; + } + + if (scanline >= 179) + biomeBuilding = false; + } + + public Texture2D Map + { + get { return map_small; } + } + + internal void resetImages() + { + // Just draw a simple grid to initialize the image; the map will appear on top of it + for (int y = 0; y < map_small.height; y++) + { + for (int x = 0; x < map_small.width; x++) + { + if ((x % 30 == 0 && y % 3 > 0) || (y % 30 == 0 && x % 3 > 0)) + { + map_small.SetPixel(x, y, palette.white); + } + else + { + map_small.SetPixel(x, y, palette.grey); + } + } + } + map_small.Apply(); + if (drawBiome) + { + biomeBuilding = true; + scanline = 0; + } + } + } } diff --git a/SCANsat/SCAN_UI/SCANoverlayController.cs b/SCANsat/SCAN_UI/SCANoverlayController.cs index 9aa7d72c6..5a31b9a2d 100644 --- a/SCANsat/SCAN_UI/SCANoverlayController.cs +++ b/SCANsat/SCAN_UI/SCANoverlayController.cs @@ -15,6 +15,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Threading; using SCANsat.SCAN_Data; using SCANsat.SCAN_UI.UI_Framework; using SCANsat.SCAN_Platform; @@ -34,21 +35,24 @@ class SCANoverlayController : SCAN_MBW private List resourceFractions; private bool drawOverlay; private bool oldOverlay; - private bool terrainGenerated; + private bool mapGenerating; private int selection; private double degreeOffset; private bool enableUI = true; private int mapStep, mapStart; + private bool bodyBiome, bodyPQS; private int timer; + //These are read/written on multiple threads; we use volatile to ensure that cached values are not used when reading the value + private volatile bool threadRunning, threadFinished; + private volatile bool terrainGenerated; + private string tooltipText = ""; private Texture2D mapOverlay; - private Texture2D biomeOverlay; - private Texture2D terrainOverlay; private Color32[] resourcePixels; - private Color32[] biomePixels; + private Color[] biomePixels; private Color32[] terrainPixels; private float[,] abundanceValues; private float[,] terrainValues; @@ -99,6 +103,14 @@ protected override void OnDestroy() { GameEvents.onShowUI.Remove(showUI); GameEvents.onHideUI.Remove(hideUI); + + if (mapOverlay != null) + Destroy(mapOverlay); + resourcePixels = null; + biomePixels = null; + terrainPixels = null; + abundanceValues = null; + terrainValues = null; } public bool DrawOverlay @@ -106,11 +118,6 @@ public bool DrawOverlay get { return drawOverlay; } } - protected override void DrawWindowPre(int id) - { - - } - protected override void DrawWindow(int id) { versionLabel(id); /* Standard version label and close button */ @@ -130,7 +137,7 @@ protected override void DrawWindowPost(int id) if (oldOverlay) refreshMap(); else - OverlayGenerator.Instance.ClearDisplay(); + removeOverlay(); } sessionRect = WindowRect; @@ -170,10 +177,10 @@ private void drawResourceList(int id) if (GUILayout.Button(r.Name, selection == i ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) { - if (mapGenerating) + if (mapGenerating || threadRunning) return; - OverlayGenerator.Instance.ClearDisplay(); + removeOverlay(); if (selection != i) { @@ -197,55 +204,61 @@ private void drawResourceList(int id) } } - if (GUILayout.Button("Biome Map", selection == (resources.Count) ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) + if (bodyBiome) { - if (mapGenerating) - return; + if (GUILayout.Button("Biome Map", selection == (resources.Count) ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) + { + if (mapGenerating || threadRunning) + return; - OverlayGenerator.Instance.ClearDisplay(); + removeOverlay(); - if (selection != resources.Count) - { - selection = resources.Count; - oldOverlay = drawOverlay = true; - refreshMap(); - return; - } + if (selection != resources.Count) + { + selection = resources.Count; + oldOverlay = drawOverlay = true; + refreshMap(); + return; + } - if (drawOverlay) - { - oldOverlay = drawOverlay = false; - } - else - { - oldOverlay = drawOverlay = true; - refreshMap(); + if (drawOverlay) + { + oldOverlay = drawOverlay = false; + } + else + { + oldOverlay = drawOverlay = true; + refreshMap(); + } } } - if (GUILayout.Button("Terrain Map", selection == (resources.Count + 1) ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) + if (bodyPQS) { - if (mapGenerating) - return; + if (GUILayout.Button("Terrain Map", selection == (resources.Count + 1) ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) + { + if (mapGenerating || threadRunning) + return; - OverlayGenerator.Instance.ClearDisplay(); + removeOverlay(); - if (selection != resources.Count + 1) - { - selection = resources.Count + 1; - oldOverlay = drawOverlay = true; - refreshMap(); - return; - } + if (selection != resources.Count + 1) + { + selection = resources.Count + 1; + oldOverlay = drawOverlay = true; + refreshMap(); + return; + } - if (drawOverlay) - { - oldOverlay = drawOverlay = false; - } - else - { - oldOverlay = drawOverlay = true; - refreshMap(); + if (drawOverlay) + { + oldOverlay = drawOverlay = false; + } + else + { + oldOverlay = drawOverlay = true; + refreshMap(); + } } } @@ -314,11 +327,18 @@ private void resourceSettings(int id) // if (a.ResourceName == "Ore" && a.HarvestType == HarvestTypes.Planetary) // SCANUtil.SCANlog("{0}: For {1} on Body {2} of scanner type {3}: Abundance = {4:P3}", a.ResourceName, a.BiomeName, a.BodyId, a.HarvestType, a.Abundance); // } - - //} } + private void removeOverlay() + { + OverlayGenerator.Instance.ClearDisplay(); + + Destroy(mapOverlay); + + mapOverlay = null; + } + private void mouseOverToolTip() { if (!drawOverlay) @@ -356,11 +376,9 @@ private void mouseOverToolTip() { if (SCANUtil.isCovered(coords.longitude, coords.latitude, data, SCANtype.Altimetry)) { - double elevation = SCANUtil.getElevation(body, coords.longitude, coords.latitude); - tooltipText += string.Format("\nTerrain: {0}", SCANuiUtil.getMouseOverElevation(coords.longitude, coords.latitude, data, 0)); - tooltipText += string.Format("\nSlope: {0:F1}°", SCANUtil.slope(elevation, body, coords.longitude, coords.latitude, degreeOffset)); + tooltipText += string.Format("\nSlope: {0:F1}°", SCANUtil.slope(SCANUtil.getElevation(body, coords.longitude, coords.latitude), body, coords.longitude, coords.latitude, degreeOffset)); } } @@ -385,111 +403,13 @@ private void mouseOverToolTip() if (resources) { - if (SCANcontroller.controller.needsNarrowBand) - { - bool coverage = false; - bool scanner = false; - - foreach (Vessel vessel in FlightGlobals.Vessels) - { - if (vessel.protoVessel.protoPartSnapshots.Count <= 1) - continue; - - if (vessel.vesselType == VesselType.Debris || vessel.vesselType == VesselType.Unknown || vessel.vesselType == VesselType.EVA || vessel.vesselType == VesselType.Flag) - continue; - - if (vessel.mainBody != body) - continue; - - if (vessel.situation != Vessel.Situations.ORBITING) - continue; - - if (inc(vessel.orbit.inclination) < Math.Abs(coords.latitude)) - { - coverage = true; - continue; - } - - var scanners = from pref in vessel.protoVessel.protoPartSnapshots - where pref.modules.Any(a => a.moduleName == "ModuleResourceScanner") - select pref; - - if (scanners.Count() == 0) - continue; - - foreach (var p in scanners) - { - if (p.partInfo == null) - continue; - - ConfigNode node = p.partInfo.partConfig; - - if (node == null) - continue; - - var moduleNodes = from nodes in node.GetNodes("MODULE") - where nodes.GetValue("name") == "ModuleResourceScanner" - select nodes; - - foreach (ConfigNode moduleNode in moduleNodes) - { - if (moduleNode == null) - continue; - - if (moduleNode.GetValue("ScannerType") != "0") - continue; - - if (moduleNode.GetValue("ResourceName") != currentResource.Name) - continue; - - if (moduleNode.HasValue("MaxAbundanceAltitude") && !vessel.Landed) - { - string alt = moduleNode.GetValue("MaxAbundanceAltitude"); - float f = 0; - if (!float.TryParse(alt, out f)) - continue; - - if (f < vessel.altitude) - { - coverage = true; - continue; - } - } - - coverage = false; - scanner = true; - break; - } - if (scanner) - break; - } - if (scanner) - break; - } - - if (coverage) - tooltipText += string.Format("\n{0}: No Coverage", currentResource.Name); - else if (!scanner) - tooltipText += string.Format("\n{0}: No Scanner", currentResource.Name); - else - resourceLabel(ref tooltipText, fuzzy, coords.latitude, coords.longitude); - } - else - resourceLabel(ref tooltipText, fuzzy, coords.latitude, coords.longitude); + tooltipText += "\n" + SCANuiUtil.getResourceAbundance(body, coords.latitude, coords.longitude, fuzzy, currentResource); } drawToolTipLabel(); } } - private void resourceLabel(ref string t, bool fuzz, double lat, double lon) - { - if (fuzz) - t += string.Format("\n{0}: {1:P0}", currentResource.Name, SCANUtil.ResourceOverlay(lat, lon, currentResource.Name, body, SCANcontroller.controller.resourceBiomeLock)); - else - t += string.Format("\n{0}: {1:P2}", currentResource.Name, SCANUtil.ResourceOverlay(lat, lon, currentResource.Name, body, SCANcontroller.controller.resourceBiomeLock)); - } - private void drawToolTipLabel() { Vector2 size = SCANskins.SCAN_readoutLabelCenter.CalcSize(new GUIContent(tooltipText)); @@ -512,11 +432,12 @@ private void drawToolTipLabel() SCANuiUtil.drawLabel(r, tooltipText, SCANskins.SCAN_readoutLabelCenter, true, SCANskins.SCAN_shadowReadoutLabelCenter); } - public void refreshMap(float t, int height, int interp) + public void refreshMap(float t, int height, int interp, int biomeHeight) { SCANcontroller.controller.overlayTransparency = t; SCANcontroller.controller.overlayMapHeight = height; SCANcontroller.controller.overlayInterpolation = interp; + SCANcontroller.controller.overlayBiomeHeight = biomeHeight; if (drawOverlay) refreshMap(); } @@ -525,21 +446,95 @@ private void refreshMap() { if (mapGenerating) return; + if (threadRunning) + return; if (selection == resources.Count) - body.SetResourceMap(SCANuiUtil.drawBiomeMap(ref biomeOverlay, ref biomePixels, data, SCANcontroller.controller.overlayTransparency, SCANcontroller.controller.overlayMapHeight * 2)); + body.SetResourceMap(SCANuiUtil.drawBiomeMap(ref mapOverlay, ref biomePixels, data, SCANcontroller.controller.overlayTransparency, SCANcontroller.controller.overlayBiomeHeight)); else if (selection == resources.Count + 1) StartCoroutine(setTerrainMap()); else if (selection == resources.Count + 2) StartCoroutine(setSlopeMap()); else - body.SetResourceMap(SCANuiUtil.drawResourceTexture(ref mapOverlay, ref resourcePixels, ref abundanceValues, SCANcontroller.controller.overlayMapHeight, data, currentResource, SCANcontroller.controller.overlayInterpolation, SCANcontroller.controller.overlayTransparency)); + StartCoroutine(setOverlayMap()); + } + + private IEnumerator setOverlayMap() + { + int timer = 0; + + mapGenerating = true; + + SCANuiUtil.generateOverlayResourceValues(ref abundanceValues, SCANcontroller.controller.overlayMapHeight, data, currentResource, SCANcontroller.controller.overlayInterpolation); + + SCANdata copy = new SCANdata(data); + SCANresourceGlobal resourceCopy = new SCANresourceGlobal(currentResource); + resourceCopy.CurrentBodyConfig(body.name); + + SCANUtil.SCANlog("Starting Resource Thread"); + + Thread t = new Thread(() => resourceThreadRun(SCANcontroller.controller.overlayMapHeight, SCANcontroller.controller.overlayInterpolation, SCANcontroller.controller.overlayTransparency, new System.Random(ResourceScenario.Instance.gameSettings.Seed), copy, resourceCopy)); + threadRunning = true; + threadFinished = false; + t.Start(); + + SCANUtil.SCANlog("Resource Thread Started..."); + + while (threadRunning && timer < 1000) + { + SCANUtil.SCANlog("Resource Thread Running..."); + timer++; + yield return null; + } + + mapGenerating = false; + copy = null; + resourceCopy = null; + + if (timer >= 1000) + { + t.Abort(); + threadRunning = false; + yield break; + } + + if (!threadFinished) + { + yield break; + } + + SCANUtil.SCANlog("Resource Thread Finished; {0} Frames Used", timer); + + if (mapOverlay == null || mapOverlay.height != SCANcontroller.controller.overlayMapHeight) + mapOverlay = new Texture2D(SCANcontroller.controller.overlayMapHeight * 2, SCANcontroller.controller.overlayMapHeight, TextureFormat.ARGB32, true); + + mapOverlay.SetPixels32(resourcePixels); + mapOverlay.Apply(); + + body.SetResourceMap(mapOverlay); + } + + private void resourceThreadRun(int height, int step, float transparent, System.Random r, SCANdata copyData, SCANresourceGlobal copyResource) + { + try + { + SCANuiUtil.generateOverlayResourcePixels(ref resourcePixels, ref abundanceValues, height, copyData, copyResource, r, step, transparent); + threadFinished = true; + } + catch + { + threadFinished = false; + } + finally + { + threadRunning = false; + } } private IEnumerator setTerrainMap() { if (data.Body.pqsController == null) - yield return null; + yield break; int timer = 0; @@ -555,24 +550,87 @@ private IEnumerator setTerrainMap() yield return null; } - mapGenerating = false; - if (timer >= 2000) + { + mapGenerating = false; + yield break; + } + + timer = 0; + + SCANdata copy = new SCANdata(data); + int index = data.Body.flightGlobalsIndex; + + SCANUtil.SCANlog("Starting Terrain Thread"); + + Thread t = new Thread( () => terrainThreadRun(copy, index)); + threadFinished = false; + threadRunning = true; + t.Start(); + + SCANUtil.SCANlog("Terrain Thread Started..."); + + while (threadRunning && timer < 1000) + { + SCANUtil.SCANlog("Terrain Thread Running..."); + timer++; yield return null; + } - if (!terrainGenerated) + mapGenerating = false; + copy = null; + + if (timer >= 1000) { - SCANuiUtil.generateTerrainArray(ref terrainValues, 720, 4, data); - terrainGenerated = true; + t.Abort(); + threadRunning = false; + yield break; } - body.SetResourceMap(SCANuiUtil.drawTerrainMap(ref terrainOverlay, ref terrainPixels, ref terrainValues, data, 720, 4)); + if (!threadFinished) + { + yield break; + } + + SCANUtil.SCANlog("Terrain Thread Finished; {0} Frames Used", timer); + + if (mapOverlay == null) + mapOverlay = new Texture2D(1440, 720, TextureFormat.ARGB32, true); + + mapOverlay.SetPixels32(terrainPixels); + mapOverlay.Apply(); + + body.SetResourceMap(mapOverlay); + } + + private void terrainThreadRun(SCANdata copyData, int i) + { + try + { + if (!terrainGenerated) + { + SCANuiUtil.generateTerrainArray(ref terrainValues, 720, 4, copyData, i); + terrainGenerated = true; + } + + SCANuiUtil.drawTerrainMap(ref terrainPixels, ref terrainValues, copyData, 720, 4); + + threadFinished = true; + } + catch + { + threadFinished = false; + } + finally + { + threadRunning = false; + } } private IEnumerator setSlopeMap() { if (data.Body.pqsController == null) - yield return null; + yield break; int timer = 0; @@ -591,20 +649,21 @@ private IEnumerator setSlopeMap() mapGenerating = false; if (timer >= 2000) - yield return null; + yield break; if (!terrainGenerated) { - SCANuiUtil.generateTerrainArray(ref terrainValues, 720, 4, data); + SCANuiUtil.generateTerrainArray(ref terrainValues, 720, 4, data, data.Body.flightGlobalsIndex); terrainGenerated = true; } - body.SetResourceMap(SCANuiUtil.drawSlopeMap(ref terrainOverlay, ref terrainPixels, ref terrainValues, data, 720, 4)); + body.SetResourceMap(SCANuiUtil.drawSlopeMap(ref mapOverlay, ref terrainPixels, ref terrainValues, data, 720, 4)); } private void setBody(CelestialBody B) { body = B; + data = SCANUtil.getData(body); if (data == null) { @@ -625,6 +684,9 @@ private void setBody(CelestialBody B) currentResource.CurrentBodyConfig(body.name); } + bodyBiome = body.BiomeMap != null; + bodyPQS = body.pqsController != null; + terrainGenerated = false; if (drawOverlay) diff --git a/SCANsat/SCAN_UI/SCANresourceSettings.cs b/SCANsat/SCAN_UI/SCANresourceSettings.cs index 4537d95d9..bd299aac9 100644 --- a/SCANsat/SCAN_UI/SCANresourceSettings.cs +++ b/SCANsat/SCAN_UI/SCANresourceSettings.cs @@ -24,7 +24,7 @@ class SCANresourceSettings : SCAN_MBW { internal readonly static Rect defaultRect = new Rect(300, 200, 300, 270); private static Rect sessionRect = defaultRect; - private int mapHeight; + private int mapHeight, biomeMapHeight; private float transparency; private int interpolationScale; private bool popup, warningResource, warningStockResource, controlLock, oldNarrowBand; @@ -48,6 +48,7 @@ protected override void Start() { oldNarrowBand = SCANcontroller.controller.needsNarrowBand; + biomeMapHeight = SCANcontroller.controller.overlayBiomeHeight; mapHeight = SCANcontroller.controller.overlayMapHeight; transparency = SCANcontroller.controller.overlayTransparency; interpolationScale = SCANcontroller.controller.overlayInterpolation; @@ -163,21 +164,21 @@ private void resourceSettings(int id) { GUILayout.Label("Resource Settings", SCANskins.SCAN_headline); growE(); - SCANcontroller.controller.resourceBiomeLock = GUILayout.Toggle(SCANcontroller.controller.resourceBiomeLock, "Resource Biome Lock", SCANskins.SCAN_settingsToggle); - if (SCANcontroller.controller.disableStockResource) - GUILayout.Toggle(false, "Instant Resource Scan", SCANskins.SCAN_settingsToggle); - else - SCANcontroller.controller.easyModeScanning = GUILayout.Toggle(SCANcontroller.controller.easyModeScanning, "Instant Resource Scan", SCANskins.SCAN_settingsToggle); + SCANcontroller.controller.resourceBiomeLock = GUILayout.Toggle(SCANcontroller.controller.resourceBiomeLock, "Resource Biome Lock", SCANskins.SCAN_settingsToggle); + if (SCANcontroller.controller.disableStockResource) + GUILayout.Toggle(false, "Instant Resource Scan", SCANskins.SCAN_settingsToggle); + else + SCANcontroller.controller.easyModeScanning = GUILayout.Toggle(SCANcontroller.controller.easyModeScanning, "Instant Resource Scan", SCANskins.SCAN_settingsToggle); stopE(); growE(); - fillS(); - SCANcontroller.controller.needsNarrowBand = GUILayout.Toggle(SCANcontroller.controller.needsNarrowBand, "Requires Narrow Band Scanner", SCANskins.SCAN_settingsToggle); - fillS(); + fillS(); + SCANcontroller.controller.needsNarrowBand = GUILayout.Toggle(SCANcontroller.controller.needsNarrowBand, "Requires Narrow Band Scanner", SCANskins.SCAN_settingsToggle); + fillS(); stopE(); growE(); - fillS(); - SCANcontroller.controller.disableStockResource = GUILayout.Toggle(SCANcontroller.controller.disableStockResource, "Disable Stock Scanning", SCANskins.SCAN_settingsToggle); - fillS(); + fillS(); + SCANcontroller.controller.disableStockResource = GUILayout.Toggle(SCANcontroller.controller.disableStockResource, "Disable Stock Scanning", SCANskins.SCAN_settingsToggle); + fillS(); stopE(); GUILayout.Label("Resource Scan Data", SCANskins.SCAN_headline); if (popup) @@ -264,6 +265,24 @@ private void overlayOptions(int id) refreshMap(); } stopE(); + + growE(); + GUILayout.Label("Biome Map Height:", SCANskins.SCAN_labelSmallLeft); + + fillS(); + + if (GUILayout.Button("-", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + biomeMapHeight = Math.Max(256, biomeMapHeight / 2); + refreshMap(); + } + GUILayout.Label(biomeMapHeight.ToString(), SCANskins.SCAN_labelSmall, GUILayout.Width(36)); + if (GUILayout.Button("+", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + biomeMapHeight = Math.Min(1024, biomeMapHeight * 2); + refreshMap(); + } + stopE(); } //Confirmation boxes for map resets @@ -333,7 +352,7 @@ private void refreshMap() if (SCANcontroller.controller.resourceOverlay == null) return; - SCANcontroller.controller.resourceOverlay.refreshMap(transparency, mapHeight, interpolationScale); + SCANcontroller.controller.resourceOverlay.refreshMap(transparency, mapHeight, interpolationScale, biomeMapHeight); } private CelestialBody getTargetBody() diff --git a/SCANsat/SCAN_UI/SCANsatRPM.cs b/SCANsat/SCAN_UI/SCANsatRPM.cs index 81d4e1a84..0f7077fb8 100644 --- a/SCANsat/SCAN_UI/SCANsatRPM.cs +++ b/SCANsat/SCAN_UI/SCANsatRPM.cs @@ -30,7 +30,7 @@ namespace SCANsat.SCAN_UI public class JSISCANsatRPM: InternalModule { [KSPField] - public int buttonUp; + public int buttonUp = 0; [KSPField] public int buttonDown = 1; [KSPField] @@ -40,6 +40,22 @@ public class JSISCANsatRPM: InternalModule [KSPField] public int buttonHome = 4; [KSPField] + public int buttonRight = 5; + [KSPField] + public int buttonLeft = 6; + [KSPField] + public int buttonR9 = 7; + [KSPField] + public int buttonR10 = 8; + [KSPField] + public int startLine = 0; + [KSPField] + public int stopLine = 0; + [KSPField] + public int mapDivider = 2; + [KSPField] + public int resourceInterpolation = 4; + [KSPField] public int maxZoom = 20; [KSPField] public float iconPixelSize = 8f; @@ -125,6 +141,10 @@ public class JSISCANsatRPM: InternalModule private double start; private readonly List mapMarkup = new List(); private readonly Color scaleTint = new Color(0.5f, 0.5f, 0.5f, 0.5f); + private bool resourceOverlay; + private List loadedResources = new List(); + private int currentResource; + private bool drawAnomaly; // Neutral tint. private bool satFound; private bool satModuleFound = true; @@ -160,6 +180,17 @@ public bool MapRenderer(RenderTexture screen, float cameraAspect) zoomLevel = loadedZoom ?? 0; int? loadedColors = persist.RPMColor; SCANcontroller.controller.colours = loadedColors ?? 0; + + if (SCANconfigLoader.GlobalResource) + { + loadedResources = SCANcontroller.setLoadedResourceList(); + + int? loadedResource = persist.RPMResource; + currentResource = loadedResource ?? 0; + + loadedResources[currentResource].CurrentBodyConfig(vessel.mainBody.name); + } + } else { mapMode = 0; @@ -200,29 +231,34 @@ public bool MapRenderer(RenderTexture screen, float cameraAspect) DrawTrail(trail, trailColorValue, new Vector2d(vessel.longitude, vessel.latitude), true); // Anomalies go above trails - foreach (SCANanomaly anomaly in localAnomalies) { - if (anomaly.Known) - DrawIcon(anomaly.Longitude, anomaly.Latitude, SCANicon.orbitIconForVesselType(anomaly.Detail ? (VesselType)int.MaxValue : VesselType.Unknown), - anomaly.Detail ? iconColorVisitedAnomalyValue : iconColorUnvisitedAnomalyValue); - } - foreach (SCANwaypoint w in localWaypoints) + if (drawAnomaly) { - if (!w.LandingTarget) + foreach (SCANanomaly anomaly in localAnomalies) { - if (w.Root != null) - { - if (w.Root.ContractState != Contracts.Contract.State.Active) - continue; - } - if (w.Param != null) + if (anomaly.Known) + DrawIcon(anomaly.Longitude, anomaly.Latitude, SCANicon.orbitIconForVesselType(anomaly.Detail ? (VesselType)int.MaxValue : VesselType.Unknown), + anomaly.Detail ? iconColorVisitedAnomalyValue : iconColorUnvisitedAnomalyValue); + } + foreach (SCANwaypoint w in localWaypoints) + { + if (!w.LandingTarget) { - if (w.Param.State != Contracts.ParameterState.Incomplete) - continue; + if (w.Root != null) + { + if (w.Root.ContractState != Contracts.Contract.State.Active) + continue; + } + if (w.Param != null) + { + if (w.Param.State != Contracts.ParameterState.Incomplete) + continue; + } } - } - DrawIcon(w, iconColorVisitedAnomalyValue); + DrawIcon(w, iconColorVisitedAnomalyValue); + } } + // Target orbit and targets go above anomalies if (targetVessel != null && targetVessel.mainBody == orbitingBody) { if (showLines && JUtil.OrbitMakesSense(targetVessel)) { @@ -517,24 +553,46 @@ public void ButtonProcessor(int buttonID) if (buttonID == buttonUp) { ChangeZoom(false); } - if (buttonID == buttonDown) { + else if (buttonID == buttonDown) { ChangeZoom(true); } - if (buttonID == buttonEnter) { + else if (buttonID == buttonEnter) { ChangeMapMode(true); } - if (buttonID == buttonEsc) { + else if (buttonID == buttonEsc) { // Whatever possessed him to do THAT? SCANcontroller.controller.colours = SCANcontroller.controller.colours == 0 ? 1 : 0; if (satModuleFound) persist.RPMColor = SCANcontroller.controller.colours; RedrawMap(); } - if (buttonID == buttonHome) { + else if (buttonID == buttonHome) { showLines = !showLines; if (satModuleFound) persist.RPMLines = showLines; } + else if (buttonID == buttonRight) + { + resourceOverlay = !resourceOverlay; + if (SCANconfigLoader.GlobalResource) + RedrawMap(); + if (satModuleFound) + persist.RPMDrawResource = resourceOverlay; + } + else if (buttonID == buttonLeft) + { + drawAnomaly = !drawAnomaly; + if (satModuleFound) + persist.RPMAnomaly = drawAnomaly; + } + else if (buttonID == buttonR9) + { + ChangeResource(true); + } + else if (buttonID == buttonR10) + { + ChangeResource(false); + } } private void ChangeMapMode(bool up) @@ -565,6 +623,31 @@ private void ChangeZoom(bool up) } } + private void ChangeResource(bool up) + { + if (loadedResources.Count <= 0) + return; + + int oldResource = currentResource; + + currentResource += up ? 1 : -1; + + if (currentResource < 0) + currentResource = loadedResources.Count -1; + if (currentResource >= loadedResources.Count) + currentResource = 0; + if (currentResource != oldResource) + { + resourceOverlay = true; + if (satModuleFound) + { + persist.RPMResource = currentResource; + persist.RPMDrawResource = true; + } + RedrawMap(); + } + } + public void PageActive(bool status, int pageNumber) { pageActiveState = status; @@ -606,7 +689,7 @@ private void RedrawMap() map.setProjection(MapProjection.Rectangular); orbitingBody = vessel.mainBody; map.setBody(vessel.mainBody); - map.setSize(screenWidth, screenHeight); + map.setSize(screenWidth / mapDivider, screenHeight / mapDivider, resourceInterpolation, startLine, stopLine); map.MapScale *= (zoomLevel * zoomLevel + zoomModifier); mapCenterLong = vessel.longitude; mapCenterLat = vessel.latitude; @@ -614,7 +697,12 @@ private void RedrawMap() if (zoomLevel == 0) mapCenterLat = 0; map.centerAround(mapCenterLong, mapCenterLat); - map.resetMap((mapType)mapMode, false, SCANcontroller.controller.map_ResourceOverlay); + if (SCANconfigLoader.GlobalResource) + { + map.Resource = loadedResources[currentResource]; + map.Resource.CurrentBodyConfig(vessel.mainBody.name); + } + map.resetMap((mapType)mapMode, false, SCANconfigLoader.GlobalResource && resourceOverlay); // Compute and store the map scale factors in mapSizeScale. We // use these values for every segment when drawing trails, so it @@ -668,7 +756,7 @@ private void Start() persistentVarName = "scansat" + internalProp.propID; try { - sat = part.FindModulesImplementing().First(); + sat = part.FindModulesImplementing().FirstOrDefault(); } catch { Debug.LogWarning("[SCANsatRPM] SCANsat module not attached to this IVA, check for Module Manager problems and make sure the RPMMapTraq.cfg file is in the SCANsat/MMconfigs folder"); @@ -690,6 +778,8 @@ private void Start() sat.RPMList.Add(persist); } showLines = persist.RPMLines; + drawAnomaly = persist.RPMAnomaly; + resourceOverlay = persist.RPMDrawResource; } else satModuleFound = false; @@ -716,8 +806,6 @@ private void Start() if (!string.IsNullOrEmpty(trailColor)) trailColorValue = ConfigNode.ParseColor32(trailColor); - - trailMaterial = JUtil.DrawLineMaterial(); LeaveTrail(); @@ -793,7 +881,10 @@ public MapMarkupLine(ConfigNode node) internal class RPMPersistence { internal int RPMMode, RPMColor, RPMZoom = 0; + internal int RPMResource = 0; internal bool RPMLines = true; + internal bool RPMAnomaly = true; + internal bool RPMDrawResource = true; internal string RPMID; internal RPMPersistence(string id) @@ -801,13 +892,16 @@ internal RPMPersistence(string id) RPMID = id; } - internal RPMPersistence(string id, int mode, int color, int zoom, bool lines) + internal RPMPersistence(string id, int mode, int color, int zoom, bool lines, bool anomaly, bool drawResource, int resource) { RPMID = id; RPMMode = mode; RPMColor = color; RPMZoom = zoom; RPMLines = lines; + RPMResource = resource; + RPMDrawResource = drawResource; + RPMAnomaly = anomaly; } } diff --git a/SCANsat/SCAN_UI/SCANzoomWindow.cs b/SCANsat/SCAN_UI/SCANzoomWindow.cs index f1a23392e..abdd0b672 100644 --- a/SCANsat/SCAN_UI/SCANzoomWindow.cs +++ b/SCANsat/SCAN_UI/SCANzoomWindow.cs @@ -136,8 +136,6 @@ public virtual void setMapCenter(double lat, double lon, bool centering, SCANmap Visible = true; bigmap = big; - resource = bigmap.Resource; - SCANcontroller.controller.TargetSelecting = false; SCANcontroller.controller.TargetSelectingActive = false; @@ -158,7 +156,7 @@ public virtual void setMapCenter(double lat, double lon, bool centering, SCANmap spotmap.setBody(b); } - if (SCANconfigLoader.GlobalResource && narrowBand) + if (SCANconfigLoader.GlobalResource) { resource = bigmap.Resource; spotmap.Resource = resource; @@ -213,18 +211,18 @@ protected virtual void resyncMap() spotmap.setBody(b); } - if (SCANconfigLoader.GlobalResource && narrowBand) + if (SCANconfigLoader.GlobalResource && resourceOverlay) { resource = bigmap.Resource; spotmap.Resource = resource; spotmap.Resource.CurrentBodyConfig(b.name); } + spotmap.centerAround(spotmap.CenteredLong, spotmap.CenteredLat); + if (SCANcontroller.controller.needsNarrowBand && resourceOverlay) checkForScanners(); - spotmap.centerAround(spotmap.CenteredLong, spotmap.CenteredLat); - spotmap.resetMap(bigmap.MType, false, resourceOverlay, narrowBand); } @@ -233,14 +231,6 @@ public SCANmap SpotMap get { return spotmap; } } - private double inc(double d) - { - if (d > 90) - d = 180 - d; - - return d; - } - public virtual void closeMap() { removeControlLocks(); @@ -249,92 +239,18 @@ public virtual void closeMap() private void checkForScanners() { - narrowBand = false; - foreach (Vessel vessel in FlightGlobals.Vessels) - { - if (vessel.protoVessel.protoPartSnapshots.Count <= 1) - continue; - - if (vessel.vesselType == VesselType.Debris || vessel.vesselType == VesselType.Unknown || vessel.vesselType == VesselType.EVA || vessel.vesselType == VesselType.Flag) - continue; - - if (vessel.mainBody != b) - continue; - - if (vessel.situation != Vessel.Situations.ORBITING) - continue; - - if (inc(vessel.orbit.inclination) < Math.Abs(spotmap.CenteredLat) - 10) - continue; - - var scanners = from pref in vessel.protoVessel.protoPartSnapshots - where pref.modules.Any(a => a.moduleName == "ModuleResourceScanner") - select pref; - - if (scanners.Count() == 0) - continue; - - foreach (var p in scanners) - { - if (p.partInfo == null) - continue; - - ConfigNode node = p.partInfo.partConfig; - - if (node == null) - continue; - - var moduleNodes = from nodes in node.GetNodes("MODULE") - where nodes.GetValue("name") == "ModuleResourceScanner" - select nodes; - - foreach (ConfigNode moduleNode in moduleNodes) - { - if (moduleNode == null) - continue; - - if (moduleNode.HasValue("MaxAbundanceAltitude")) - { - string alt = moduleNode.GetValue("MaxAbundanceAltitude"); - float f = 0; - if (!float.TryParse(alt, out f)) - continue; - - if (f < vessel.altitude) - continue; - } - - if (moduleNode.GetValue("ScannerType") != "0") - continue; - - if (moduleNode.GetValue("ResourceName") != resource.Name) - continue; - - if (spotmap.Resource != resource) - { - spotmap.Resource = resource; - spotmap.Resource.CurrentBodyConfig(b.name); - if (resourceOverlay) - spotmap.resetMap(resourceOverlay, true); - } - - if (spotmap.Resource != null) - { - narrowBand = true; - break; - } - } - - if (narrowBand) - break; - } - - if (narrowBand) - break; - } + string t = ""; + narrowBand = SCANuiUtil.narrowBandInOrbit(ref t, b, Math.Abs(spotmap.CenteredLat - 10), resource); if (!narrowBand) spotmap.Resource = null; + else + { + spotmap.Resource = resource; + spotmap.Resource.CurrentBodyConfig(b.name); + if (resourceOverlay) + spotmap.resetMap(resourceOverlay, true); + } } protected override void Update() @@ -565,6 +481,18 @@ private void topBar(int id) GUI.DrawTexture(r, SCANskins.SCAN_TargetIcon); GUI.color = old; } + + r = new Rect(WindowRect.width - 68, 20, 18, 18); + + showWaypoints = GUI.Toggle(r, showWaypoints, textWithTT("", "Toggle Waypoints"), SCANskins.SCAN_settingsToggle); + + r.x += 13; + r.width = r.height = 20; + + if (GUI.Button(r, iconWithTT(SCANskins.SCAN_WaypointIcon, "Toggle Waypoints"), SCANskins.SCAN_buttonBorderless)) + { + showWaypoints = !showWaypoints; + } } r = new Rect(WindowRect.width / 2 - 58, 20, 26, 26); @@ -606,21 +534,6 @@ private void topBar(int id) } } - if (HighLogic.LoadedScene != GameScenes.SPACECENTER) - { - r = new Rect(WindowRect.width - 68, 20, 18, 18); - - showWaypoints = GUI.Toggle(r, showWaypoints, textWithTT("", "Toggle Waypoints"), SCANskins.SCAN_settingsToggle); - - r.x += 13; - r.width = r.height = 20; - - if (GUI.Button(r, iconWithTT(SCANskins.SCAN_WaypointIcon, "Toggle Waypoints"), SCANskins.SCAN_buttonBorderless)) - { - showWaypoints = !showWaypoints; - } - } - r = new Rect(WindowRect.width - 35, 20, 18, 18); showAnomaly = GUI.Toggle(r, showAnomaly, textWithTT("", "Toggle Anomalies"), SCANskins.SCAN_settingsToggle); @@ -638,7 +551,6 @@ private void drawMap(int id) { MapTexture = getMap(); - //A blank label used as a template for the actual map texture if (IsResizing) { //Set minimum map size during re-sizing diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs b/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs index a41830e29..5101a8750 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs @@ -118,15 +118,15 @@ public static Color32 lerp(Color32 a, Color32 b, float t) public static Color[] small_redline; - public static Color heightToColor(float val, int scheme, SCANdata data) + public static Color heightToColor(float val, int scheme, SCANterrainConfig terrain) { - Color32[] c = data.TerrainConfig.ColorPal.colors; - if (data.TerrainConfig.PalRev) - c = data.TerrainConfig.ColorPal.colorsReverse; + Color32[] c = terrain.ColorPal.colors; + if (terrain.PalRev) + c = terrain.ColorPal.colorsReverse; if (scheme == 0) - return heightToColor(val, data.TerrainConfig.MaxTerrain, data.TerrainConfig.MinTerrain, data.TerrainConfig.TerrainRange, data.TerrainConfig.ClampTerrain, data.TerrainConfig.PalDis, c); + return heightToColor(val, terrain.MaxTerrain, terrain.MinTerrain, terrain.TerrainRange, terrain.ClampTerrain, terrain.PalDis, c); else - return heightToColor(val, data.TerrainConfig.MaxTerrain, data.TerrainConfig.MinTerrain, data.TerrainConfig.TerrainRange, data.TerrainConfig.PalDis); + return heightToColor(val, terrain.MaxTerrain, terrain.MinTerrain, terrain.TerrainRange, terrain.PalDis); } private static Color heightToColor(float val, float max, float min, float range, bool discrete) @@ -217,17 +217,6 @@ internal static Color heightToColor(float val, float max, float min, float range return c; } - //int sealevel = 0; - //if (val <= sealevel) { - // val = (Mathf.Clamp (val , -1500 , sealevel) + 1500) / 1000f; - // c = lerp (xkcd_DarkPurple , xkcd_Cerulean , val); - //} else { - // val = (heightGradient.Length - 2) * Mathf.Clamp (val , sealevel , (sealevel + 7500)) / (sealevel + 7500.0f); - // c = lerp (heightGradient [(int)val] , heightGradient [(int)val + 1] , val - (int)val); - //} - // return c; - //} - public static string colorHex ( Color32 c ) { return "#" + c.r.ToString ("x2") + c.g.ToString ("x2") + c.b.ToString ("x2"); } @@ -283,11 +272,6 @@ public static void swatch(Color c) { } private static _Palettes currentPaletteSet; - //private static _Palettes divPaletteSet; - //private static _Palettes qualPaletteSet; - //private static _Palettes seqPaletteSet; - //private static _Palettes fixedPaletteSet; - //private static Palette currentHeightPalette; private static Palette greyScalePalette = BrewerPalettes.Greys(9); private static _Palettes generatePaletteSet(int size, Palette.Kind type) @@ -305,20 +289,6 @@ internal static _Palettes setCurrentPalettesType(Palette.Kind type, int size) default: return generatePaletteSet(size, type); } - //switch (type) - //{ - // case Palette.Kind.Diverging: - // return generatePaletteSet(size, type); - // //return divPaletteSet; - // case Palette.Kind.Qualitative: - // //return qualPaletteSet; - // case Palette.Kind.Sequential: - // //return seqPaletteSet; - // case Palette.Kind.Fixed: - // //return fixedPaletteSet; - // default: - // //return divPaletteSet; - //} } public static Palette GreyScalePalette @@ -339,36 +309,6 @@ public static string getPaletteTypeName { get { return currentPaletteSet.paletteType.ToString(); } } - - //public static _Palettes DivPaletteSet - //{ - // get { return divPaletteSet; } - // internal set { divPaletteSet = value; } - //} - - //public static _Palettes QualPaletteSet - //{ - // get { return qualPaletteSet; } - // internal set { qualPaletteSet = value; } - //} - - //public static _Palettes SeqPaletteSet - //{ - // get { return seqPaletteSet; } - // internal set { seqPaletteSet = value; } - //} - - //public static _Palettes FixedPaletteSet - //{ - // get { return fixedPaletteSet; } - // internal set { fixedPaletteSet = value; } - //} - - //public static Palette CurrentPalette - //{ - // get { return currentHeightPalette; } - // internal set { currentHeightPalette = value; } - //} } } diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs b/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs index 0af7fa31d..6d63b81c1 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs @@ -37,7 +37,9 @@ class SCANskins: SCAN_MBE internal static GUIStyle SCAN_windowButton; internal static GUIStyle SCAN_texButton; internal static GUIStyle SCAN_buttonBorderless; + internal static GUIStyle SCAN_buttonBorderlessSmall; internal static GUIStyle SCAN_closeButton; + internal static GUIStyle SCAN_headerButton; //Map info readout styles internal static GUIStyle SCAN_readoutLabel; @@ -73,8 +75,10 @@ class SCANskins: SCAN_MBE internal static GUIStyle SCAN_labelSmallLeft; internal static GUIStyle SCAN_labelSmallRight; internal static GUIStyle SCAN_vertSlider; + internal static GUIStyle SCAN_horSlider; internal static GUIStyle SCAN_sliderThumb; internal static GUIStyle SCAN_colorWheelButton; + internal static GUIStyle SCAN_headerLabel; //Styles for map overlay icons internal static GUIStyle SCAN_orbitalLabelOn; @@ -218,6 +222,9 @@ private static void initializeSkins() SCAN_buttonBorderless.padding = new RectOffset(2, 2, 2, 2); SCAN_buttonBorderless.normal.background = SCAN_SkinsLibrary.DefUnitySkin.label.normal.background; + SCAN_buttonBorderlessSmall = new GUIStyle(SCAN_buttonBorderless); + SCAN_buttonBorderlessSmall.fontSize = 12; + SCAN_closeButton = new GUIStyle(SCAN_buttonBorderless); SCAN_closeButton.name = "SCAN_CloseButton"; SCAN_closeButton.normal.textColor = palette.cb_vermillion; @@ -325,9 +332,17 @@ private static void initializeSkins() SCAN_headline.name = "SCAN_Headline"; SCAN_headline.normal.textColor = palette.xkcd_YellowGreen; SCAN_headline.alignment = TextAnchor.MiddleCenter; - SCAN_headline.fontSize = 40; + SCAN_headline.fontSize = 30; SCAN_headline.font = dotty; + SCAN_headerButton = new GUIStyle(SCAN_SkinsLibrary.DefUnitySkin.button); + SCAN_headerButton.fontSize = 18; + SCAN_headerButton.fontStyle = FontStyle.Bold; + + SCAN_headerLabel = new GUIStyle(SCAN_SkinsLibrary.DefUnitySkin.label); + SCAN_headerLabel.fontSize = 18; + SCAN_headerLabel.fontStyle = FontStyle.Bold; + SCAN_headlineSmall = new GUIStyle(SCAN_headline); SCAN_headlineSmall.name = "SCAN_HeadlineSmall"; SCAN_headlineSmall.fontSize = 30; @@ -377,6 +392,8 @@ private static void initializeSkins() SCAN_vertSlider = new GUIStyle(SCAN_SkinsLibrary.DefKSPSkin.verticalSlider); SCAN_vertSlider.name = "SCAN_VertSlider"; + SCAN_horSlider = new GUIStyle(SCAN_SkinsLibrary.DefUnitySkin.horizontalSlider); + SCAN_sliderThumb = new GUIStyle(SCAN_SkinsLibrary.DefKSPSkin.verticalSliderThumb); SCAN_sliderThumb.name = "SCAN_SliderThumb"; @@ -404,6 +421,7 @@ private static void initializeSkins() SCAN_SkinsLibrary.knownSkins["SCAN_Unity"].toggle = new GUIStyle(SCAN_toggle); SCAN_SkinsLibrary.knownSkins["SCAN_Unity"].label = new GUIStyle(SCAN_label); SCAN_SkinsLibrary.knownSkins["SCAN_Unity"].box = new GUIStyle(SCAN_dropDownBox); + SCAN_SkinsLibrary.knownSkins["SCAN_Unity"].horizontalSlider = new GUIStyle(SCAN_horSlider); SCAN_SkinsLibrary.AddStyle(SCAN_window, "SCAN_Unity"); SCAN_SkinsLibrary.AddStyle(SCAN_button, "SCAN_Unity"); @@ -411,6 +429,7 @@ private static void initializeSkins() SCAN_SkinsLibrary.AddStyle(SCAN_label, "SCAN_Unity"); SCAN_SkinsLibrary.AddStyle(SCAN_tooltip, "SCAN_Unity"); SCAN_SkinsLibrary.AddStyle(SCAN_dropDownBox, "SCAN_Unity"); + SCAN_SkinsLibrary.AddStyle(SCAN_horSlider, "SCAN_Unity"); } } diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANuiSlider.cs b/SCANsat/SCAN_UI/UI_Framework/SCANuiSlider.cs index d91e6a0f4..3424b8005 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANuiSlider.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANuiSlider.cs @@ -68,7 +68,7 @@ public float drawSlider(bool under, ref float value) r.width = 260; if (under) - GUI.HorizontalSlider(r, value, minValue, maxValue).Mathf_Round(precision); + GUI.Label(r, "", SCANskins.SCAN_horSlider); else value = GUI.HorizontalSlider(r, value, minValue, maxValue).Mathf_Round(precision); diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs b/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs index e4f21b9af..ca390be46 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs @@ -144,7 +144,19 @@ internal static void mouseOverInfo(double lon, double lat, SCANmap mapObj, SCANd else info += palette.colored(palette.grey, "MULTI "); - info += getMouseOverElevation(lon, lat, data, 2); + if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) + { + info += getMouseOverElevation(lon, lat, data, 2); + + if (SCANUtil.isCovered(lon, lat, data, SCANtype.AltimetryHiRes)) + { + double circum = body.Radius * 2 * Math.PI; + double eqDistancePerDegree = circum / 360; + double degreeOffset = 5 / eqDistancePerDegree; + + info += string.Format(" {0:F1}° ", SCANUtil.slope(SCANUtil.getElevation(body, lon, lat), body, lon, lat, degreeOffset)); + } + } if (SCANUtil.isCovered(lon, lat, data, SCANtype.Biome)) { @@ -153,26 +165,22 @@ internal static void mouseOverInfo(double lon, double lat, SCANmap mapObj, SCANd if (mapObj.ResourceActive && SCANconfigLoader.GlobalResource && mapObj.Resource != null) //Adds selected resource amount to big map legend { - string label = ""; + bool resources = false; + bool fuzzy = false; if (SCANUtil.isCovered(lon, lat, data, mapObj.Resource.SType)) { - double amount = SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body, SCANcontroller.controller.resourceBiomeLock); - if (amount < 0) - label = "Unknown"; - else - { - if (amount > 1) - amount = 1; - label = amount.ToString("P2"); - } - info += palette.colored(mapObj.Resource.MaxColor, mapObj.Resource.Name + ": " + label + " "); + resources = true; } else if (SCANUtil.isCovered(lon, lat, data, SCANtype.FuzzyResources)) { - int amount = Mathf.RoundToInt(((float)SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body, SCANcontroller.controller.resourceBiomeLock)) * 100f); - label = amount.ToString() + "%"; - info += palette.colored(mapObj.Resource.MaxColor, mapObj.Resource.Name + ": " + label + " "); + resources = true; + fuzzy = true; + } + + if (resources) + { + info += palette.colored(mapObj.Resource.MaxColor, getResourceAbundance(mapObj.Body, lat, lon, fuzzy, mapObj.Resource)); } } @@ -223,7 +231,19 @@ internal static void mouseOverInfoSimple(double lon, double lat, SCANmap mapObj, if (b) { - info += getMouseOverElevation(lon, lat, data, 0); + if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) + { + info += getMouseOverElevation(lon, lat, data, 0); + + if (SCANUtil.isCovered(lon, lat, data, SCANtype.AltimetryHiRes)) + { + double circum = body.Radius * 2 * Math.PI; + double eqDistancePerDegree = circum / 360; + double degreeOffset = 5 / eqDistancePerDegree; + + info += string.Format(" {0:F1}° ", SCANUtil.slope(SCANUtil.getElevation(body, lon, lat), body, lon, lat, degreeOffset)); + } + } if (SCANUtil.isCovered(lon, lat, data, SCANtype.Biome)) { @@ -248,8 +268,15 @@ internal static void mouseOverInfoSimple(double lon, double lat, SCANmap mapObj, } else if (SCANUtil.isCovered(lon, lat, data, SCANtype.FuzzyResources)) { - int amount = Mathf.RoundToInt(((float)SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body, SCANcontroller.controller.resourceBiomeLock)) * 100f); - label = amount.ToString() + "%"; + double amount = SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body, SCANcontroller.controller.resourceBiomeLock); + if (amount < 0) + label = "Unknown"; + else + { + if (amount > 1) + amount = 1; + label = amount.ToString("P0"); + } info += palette.colored(mapObj.Resource.MaxColor, mapObj.Resource.Name + ": " + label + " "); } } @@ -290,15 +317,134 @@ internal static void mouseOverInfoSimple(double lon, double lat, SCANmap mapObj, readableLabel(posInfo, false); } + internal static string getResourceAbundance(CelestialBody Body, double lat, double lon, bool fuzzy, SCANresourceGlobal resource) + { + string label = ""; + + if (narrowBandInOrbit(ref label, Body, lat, resource)) + label = resourceLabel(fuzzy, lat, lon, resource, Body); + + return label; + } + + internal static bool narrowBandInOrbit(ref string text, CelestialBody b, double lat, SCANresourceGlobal resource) + { + if (SCANcontroller.controller.needsNarrowBand) + { + bool scanner = false; + + foreach (Vessel vessel in FlightGlobals.Vessels) + { + if (vessel.protoVessel.protoPartSnapshots.Count <= 1) + continue; + + if (vessel.vesselType == VesselType.Debris || vessel.vesselType == VesselType.Unknown || vessel.vesselType == VesselType.EVA || vessel.vesselType == VesselType.Flag) + continue; + + if (vessel.mainBody != b) + continue; + + if (vessel.situation != Vessel.Situations.ORBITING) + continue; + + if (inc(vessel.orbit.inclination) < Math.Abs(lat)) + { + continue; + } + + var scanners = from pref in vessel.protoVessel.protoPartSnapshots + where pref.modules.Any(a => a.moduleName == "ModuleResourceScanner") + select pref; + + if (scanners.Count() == 0) + continue; + + foreach (var p in scanners) + { + if (p.partInfo == null) + continue; + + ConfigNode node = p.partInfo.partConfig; + + if (node == null) + continue; + + var moduleNodes = from nodes in node.GetNodes("MODULE") + where nodes.GetValue("name") == "ModuleResourceScanner" + select nodes; + + foreach (ConfigNode moduleNode in moduleNodes) + { + if (moduleNode == null) + continue; + + if (moduleNode.GetValue("ScannerType") != "0") + continue; + + if (moduleNode.GetValue("ResourceName") != resource.Name) + continue; + + if (moduleNode.HasValue("MaxAbundanceAltitude") && !vessel.Landed) + { + string alt = moduleNode.GetValue("MaxAbundanceAltitude"); + float f = 0; + if (!float.TryParse(alt, out f)) + continue; + + if (f < vessel.altitude) + { + scanner = false; + continue; + } + } + + scanner = true; + break; + } + if (scanner) + break; + } + if (scanner) + break; + } + + if (!scanner) + { + text = string.Format("{0}: No Scanner", resource.Name); + return false; + } + } + + return true; + } + + internal static string resourceLabel(bool fuzz, double lat, double lon, SCANresourceGlobal resource, CelestialBody b) + { + if (fuzz) + return string.Format("{0}: {1:P0}", resource.Name, SCANUtil.ResourceOverlay(lat, lon, resource.Name, b, SCANcontroller.controller.resourceBiomeLock)); + else + return string.Format("{0}: {1:P2}", resource.Name, SCANUtil.ResourceOverlay(lat, lon, resource.Name, b, SCANcontroller.controller.resourceBiomeLock)); + } + + private static double inc(double d) + { + d = Math.Abs(d); + + if (d > 90) + d = 180 - d; + + return d; + } + internal static string getMouseOverElevation(double Lon, double Lat, SCANdata d, int precision) { - string s = ""; + string s = " "; if (SCANUtil.isCovered(Lon, Lat, d, SCANtype.AltimetryHiRes)) { s = SCANUtil.getElevation(d.Body, Lon, Lat).ToString("N" + precision) + "m "; } - else if (SCANUtil.isCovered(Lon, Lat, d, SCANtype.AltimetryLoRes)) + else { s = (((int)SCANUtil.getElevation(d.Body, Lon, Lat) / 500) * 500).ToString() + "m "; } @@ -1419,6 +1565,57 @@ private static double unFixLon(double Lon) return Lon; } + internal static void generateOverlayResourceValues(ref float[,] values, int height, SCANdata data, SCANresourceGlobal resource, int stepScale = 8) + { + int width = height * 2; + float scale = height / 180f; + + if (values == null || height * width != values.Length) + { + values = new float[width, height]; + } + + for (int j = 0; j < height; j += stepScale) + { + double lat = (j / scale) - 90; + for (int i = 0; i < width; i += stepScale) + { + double lon = fixLon(i / scale); + + values[i, j] = SCANUtil.ResourceOverlay(lat, lon, resource.Name, data.Body, SCANcontroller.controller.resourceBiomeLock) * 100; + } + } + } + + internal static void generateOverlayResourcePixels(ref Color32[] pix, ref float[,] values, int height, SCANdata data, SCANresourceGlobal resource, System.Random r, int stepScale, float transparency = 0f) + { + int width = height * 2; + float scale = height / 180f; + + if (pix == null || height * width != pix.Length) + { + pix = new Color32[width * height]; + } + + for (int i = stepScale / 2; i >= 1; i /= 2) + { + interpolate(values, height, width, i, i, i, r, true); + interpolate(values, height, width, 0, i, i, r, true); + interpolate(values, height, width, i, 0, i, r, true); + } + + for (int i = 0; i < width; i++) + { + double lon = fixLon(i / scale); + for (int j = 0; j < height; j++) + { + double lat = (j / scale) - 90; + + pix[j * width + i] = resourceToColor32(palette.Clear, resource, values[i, j], data, lon, lat, transparency); + } + } + } + internal static Texture2D drawResourceTexture(ref Texture2D map, ref Color32[] pix, ref float[,] values, int height, SCANdata data, SCANresourceGlobal resource, int stepScale = 8, float transparency = 0f) { int width = height * 2; @@ -1468,10 +1665,10 @@ internal static Texture2D drawResourceTexture(ref Texture2D map, ref Color32[] p return map; } - internal static Texture2D drawBiomeMap(ref Texture2D map, ref Color32[] pix, SCANdata data, float transparency, int height = 256, bool useStock = false, bool whiteBorder = false) + internal static Texture2D drawBiomeMap(ref Texture2D map, ref Color[] pix, SCANdata data, float transparency, int height = 256, bool useStock = false, bool whiteBorder = false) { if (!useStock && !whiteBorder) - return drawBiomeMap(ref map, ref pix, data, transparency, height); + return drawBiomeMap(ref map, ref pix, data, height); int width = height * 2; float scale = (width * 1f) / 360f; @@ -1480,7 +1677,7 @@ internal static Texture2D drawBiomeMap(ref Texture2D map, ref Color32[] pix, SCA if (map == null || pix == null || map.height != height) { map = new Texture2D(width, height, TextureFormat.ARGB32, true); - pix = new Color32[width * height]; + pix = new Color[width * height]; } for (int j = 0; j < height; j++) @@ -1513,21 +1710,25 @@ internal static Texture2D drawBiomeMap(ref Texture2D map, ref Color32[] pix, SCA } } - map.SetPixels32(pix); + map.SetPixels(pix); map.Apply(); return map; } - private static Texture2D drawBiomeMap(ref Texture2D m, ref Color32[] p, SCANdata d, float t, int h) + private static Texture2D drawBiomeMap(ref Texture2D m, ref Color[] p, SCANdata d, int h) { if (d.Body.BiomeMap == null) return null; - if (m == null || p == null || m.height != h) + if (m == null || m.height != h) { m = new Texture2D(h * 2, h, TextureFormat.RGBA32, true); - p = new Color32[m.width * m.height]; + } + + if (p == null || p.Length != h * 2) + { + p = new Color[m.width]; } float scale = m.width / 360f; @@ -1539,29 +1740,27 @@ private static Texture2D drawBiomeMap(ref Texture2D m, ref Color32[] p, SCANdata { double lon = fixLon(i / scale); - Color32 c = palette.Clear; - if (SCANUtil.isCovered(lon, lat, d, SCANtype.Biome)) - c = (Color32)SCANUtil.getBiome(d.Body, lon, lat).mapColor;//, palette.clear, SCANcontroller.controller.biomeTransparency / 100); - - p[j *m.width + i] = c; + p[i] = SCANUtil.getBiome(d.Body, lon, lat).mapColor; + else + p[i] = palette.clear; } + + m.SetPixels(0, j, m.width, 1, p); } - m.SetPixels32(p); m.Apply(); return m; } - internal static Texture2D drawTerrainMap(ref Texture2D map, ref Color32[] pix, ref float[,] values, SCANdata data, int height, int stepScale) + internal static void drawTerrainMap(ref Color32[] pix, ref float[,] values, SCANdata data, int height, int stepScale) { int width = height * 2; float scale = height / 180f; - if (map == null || pix == null || map.height != height) + if (pix == null) { - map = new Texture2D(width, height, TextureFormat.ARGB32, true); pix = new Color32[width * height]; } @@ -1577,14 +1776,14 @@ internal static Texture2D drawTerrainMap(ref Texture2D map, ref Color32[] pix, r if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) { if (SCANUtil.isCovered(lon, lat, data, SCANtype.AltimetryHiRes)) - c = palette.heightToColor(values[i, j], 0, data); + c = palette.heightToColor(values[i, j], 0, data.TerrainConfig); else { int ilon = SCANUtil.icLON(unFixLon(lon)); int ilat = SCANUtil.icLAT(lat); int lo = ((int)(ilon * scale * 5)) / 5; int la = ((int)(ilat * scale * 5)) / 5; - c = palette.heightToColor(values[lo, la], 1, data); + c = palette.heightToColor(values[lo, la], 1, data.TerrainConfig); } c = palette.lerp(c, palette.Clear, 0.1f); @@ -1595,11 +1794,6 @@ internal static Texture2D drawTerrainMap(ref Texture2D map, ref Color32[] pix, r pix[j * width + i] = c; } } - - map.SetPixels32(pix); - map.Apply(); - - return map; } internal static Texture2D drawSlopeMap(ref Texture2D map, ref Color32[] pix, ref float[,] values, SCANdata data, int height, int stepScale) @@ -1701,7 +1895,7 @@ internal static Texture2D drawSlopeMap(ref Texture2D map, ref Color32[] pix, ref return map; } - internal static void generateTerrainArray(ref float[,] values, int height, int stepScale, SCANdata data) + internal static void generateTerrainArray(ref float[,] values, int height, int stepScale, SCANdata data, int index) { int width = height * 2; float scale = height / 180f; @@ -1712,7 +1906,7 @@ internal static void generateTerrainArray(ref float[,] values, int height, int s { for (int j = 0; j < 180; j++) { - values[i * stepScale, j * stepScale] = data.HeightMapValue(data.Body.flightGlobalsIndex, (int)fixLon(i) + 180, j); + values[i * stepScale, j * stepScale] = data.HeightMapValue(index, (int)fixLon(i) + 180, j, true); } } @@ -1750,7 +1944,7 @@ internal static Texture2D drawLoDetailMap(ref Color32[] pix, ref float[,] values { if (map.Map == null || pix == null || map.Map.height != height) { - map.Map= new Texture2D(width, height, TextureFormat.ARGB32, true); + map.Map= new Texture2D(width, height, TextureFormat.ARGB32, false); pix = new Color32[width * height]; values = new float[width, height]; } @@ -1780,7 +1974,7 @@ internal static Texture2D drawLoDetailMap(ref Color32[] pix, ref float[,] values { for (int j = 0; j < height; j++) { - pix[j * width + i] = palette.heightToColor(values[i, j], 1, data); + pix[j * width + i] = palette.heightToColor(values[i, j], 1, data.TerrainConfig); } } @@ -1949,7 +2143,7 @@ internal static Color resourceToColor(Color BaseColor, SCANresourceGlobal Resour if (Abundance == 0) return palette.lerp(BaseColor, palette.grey, 0.3f); else - return palette.lerp(palette.lerp(Resource.MinColor, Resource.MaxColor, Abundance / (Resource.CurrentBody.MaxValue - Resource.CurrentBody.MinValue)), BaseColor, Resource.Transparency / 100f); + return palette.lerp(palette.lerp(Resource.MinColor, Resource.MaxColor, (Abundance - Resource.CurrentBody.MinValue) / (Resource.CurrentBody.MaxValue - Resource.CurrentBody.MinValue)), BaseColor, Resource.Transparency / 100f); } private static Color32 resourceToColor32(Color32 BaseColor, SCANresourceGlobal Resource, float Abundance, SCANdata Data, double Lon, double Lat, float Transparency = 0.3f) @@ -1981,7 +2175,7 @@ private static Color32 resourceToColor32(Color32 BaseColor, SCANresourceGlobal R if (Abundance == 0) return palette.lerp(BaseColor, palette.Grey, Transparency); else - return palette.lerp(palette.lerp(Resource.MinColor32, Resource.MaxColor32, Abundance / (Resource.CurrentBody.MaxValue - Resource.CurrentBody.MinValue)), BaseColor, Resource.Transparency / 100f); + return palette.lerp(palette.lerp(Resource.MinColor32, Resource.MaxColor32, (Abundance - Resource.CurrentBody.MinValue) / (Resource.CurrentBody.MaxValue - Resource.CurrentBody.MinValue)), BaseColor, Resource.Transparency / 100f); } #endregion diff --git a/SCANsat/SCANconfigLoader.cs b/SCANsat/SCANconfigLoader.cs index c97275c47..b5816a4a0 100644 --- a/SCANsat/SCANconfigLoader.cs +++ b/SCANsat/SCANconfigLoader.cs @@ -146,7 +146,7 @@ private static void loadResources() private static SCANresourceType OverlayResourceType(string s) { - return SCANcontroller.getResourceType(s); + return SCANcontroller.getResourceType(s, false); } } } diff --git a/SCANsat/SCANcontroller.cs b/SCANsat/SCANcontroller.cs index 367d4df8b..3bb9bdcf6 100644 --- a/SCANsat/SCANcontroller.cs +++ b/SCANsat/SCANcontroller.cs @@ -113,6 +113,8 @@ public static SCANcontroller controller [KSPField(isPersistant = true)] public int overlayMapHeight = 256; [KSPField(isPersistant = true)] + public int overlayBiomeHeight = 512; + [KSPField(isPersistant = true)] public float overlayTransparency = 0; [KSPField(isPersistant = true)] public bool version14Patch = false; @@ -256,6 +258,19 @@ public static void setMasterTerrainNodes (List terrainConfigs { SCANUtil.SCANlog("Error while loading SCANsat terrain config settings: {0}", e); } + + for (int i = 0; i < FlightGlobals.Bodies.Count; i++) + { + CelestialBody b = FlightGlobals.Bodies[i]; + if (getTerrainNode(b.name) == null) + { + float? clamp = null; + if (b.ocean) + clamp = 0; + + addToTerrainConfigData(b.name, new SCANterrainConfig(SCANconfigLoader.SCANNode.DefaultMinHeightRange, SCANconfigLoader.SCANNode.DefaultMaxHeightRange, clamp, SCANUtil.paletteLoader(SCANconfigLoader.SCANNode.DefaultPalette, 7), 7, false, false, b)); + } + } } public static SCANterrainConfig getTerrainNode(string name) @@ -394,11 +409,11 @@ public static void addToResourceData (string name, SCANresourceGlobal res) Debug.LogError(string.Format("[SCANsat] Warning: SCANResource Dictionary Already Contains Key of This Type: Resource: {0}", name)); } - public static SCANresourceType getResourceType (string name) + public static SCANresourceType getResourceType (string name, bool warn = true) { if (resourceTypes.ContainsKey(name)) return resourceTypes[name]; - else + else if (warn) SCANUtil.SCANlog("SCANsat resource type [{0}] cannot be found in master resource type storage list", name); return null; @@ -1030,8 +1045,10 @@ private void drawGroundTracks(CelestialBody body) { double surfaceScale = (2 * Math.PI * body.Radius) / 360; - foreach (SCANvessel sv in knownVessels.Values) + for (int j = 0; j < knownVessels.Count; j++) { + SCANvessel sv = knownVessels.Values.ElementAt(j); + if (sv == null) continue; @@ -1066,8 +1083,10 @@ private double getFOV(SCANvessel v, CelestialBody b, out Color c) surfscale = 1; surfscale = Math.Sqrt(surfscale); - foreach (SCANsensor s in v.sensors.Values) + for (int j = 0; j < v.sensors.Count; j++) { + SCANsensor s = v.sensors.Values.ElementAt(j); + if (alt < s.min_alt) continue; if (alt > Math.Min(s.max_alt, soi_radius)) @@ -1494,9 +1513,12 @@ private void scanFromAllVessels() i++; if (i >= body_data.Count) i = 0; } - foreach (Vessel v in FlightGlobals.Vessels) + for (int j = 0; j < FlightGlobals.Vessels.Count; j++) { - if (!knownVessels.ContainsKey(v.id)) continue; + Vessel v = FlightGlobals.Vessels[j]; + if (!knownVessels.ContainsKey(v.id)) + continue; + SCANvessel vessel = knownVessels[v.id]; SCANdata data = SCANUtil.getData(v.mainBody); if (data == null) @@ -1571,8 +1593,10 @@ private void doScanPass(SCANvessel vessel, double UT, double startUT, double las actualPasses++; uncovered = res <= 0; - foreach (SCANsensor sensor in knownVessels[v.id].sensors.Values) + for (int j = 0; j < knownVessels[v.id].sensors.Count; j++) { + SCANsensor sensor = knownVessels[v.id].sensors.Values.ElementAt(j); + if (res <= 0) { if (data.getCoverage(sensor.sensor) > 0) uncovered = false; diff --git a/SCANsat/SCANutil.cs b/SCANsat/SCANutil.cs index 45294f22d..3202f9f00 100644 --- a/SCANsat/SCANutil.cs +++ b/SCANsat/SCANutil.cs @@ -411,20 +411,17 @@ internal static Palette paletteLoader(string name, int size) internal static CelestialBody getTargetBody(MapObject target) { - if (target.type == MapObject.MapObjectType.CELESTIALBODY) + switch (target.type) { - return target.celestialBody; + case MapObject.MapObjectType.CELESTIALBODY: + return target.celestialBody; + case MapObject.MapObjectType.MANEUVERNODE: + return target.maneuverNode.patch.referenceBody; + case MapObject.MapObjectType.VESSEL: + return target.vessel.mainBody; + default: + return null; } - else if (target.type == MapObject.MapObjectType.MANEUVERNODE) - { - return target.maneuverNode.patch.referenceBody; - } - else if (target.type == MapObject.MapObjectType.VESSEL) - { - return target.vessel.mainBody; - } - - return null; } internal static double slope(double centerElevation, CelestialBody body, double lon, double lat, double offset) @@ -531,7 +528,7 @@ internal static SCANCoordinates GetMouseCoordinates(CelestialBody body) mouseRay.origin = ScaledSpace.ScaledToLocalSpace(mouseRay.origin); Vector3d relOrigin = mouseRay.origin - body.position; Vector3d relSurfacePosition; - double curRadius = body.pqsController.radiusMax; + double curRadius = body.pqsController == null ? body.Radius : body.pqsController.radiusMax; double lastRadius = 0; double error = 0; int loops = 0; @@ -541,14 +538,15 @@ internal static SCANCoordinates GetMouseCoordinates(CelestialBody body) if (PQS.LineSphereIntersection(relOrigin, mouseRay.direction, curRadius, out relSurfacePosition)) { Vector3d surfacePoint = body.position + relSurfacePosition; - double alt = body.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(body.GetLongitude(surfacePoint), Vector3d.down) * QuaternionD.AngleAxis(body.GetLatitude(surfacePoint), Vector3d.forward) * Vector3d.right); + double alt = body.pqsController == null ? 0 : body.pqsController.GetSurfaceHeight(QuaternionD.AngleAxis(body.GetLongitude(surfacePoint), Vector3d.down) * QuaternionD.AngleAxis(body.GetLatitude(surfacePoint), Vector3d.forward) * Vector3d.right); error = Math.Abs(curRadius - alt); - if (error < (body.pqsController.radiusMax - body.pqsController.radiusMin) / 100) + if (body.pqsController == null || error < (body.pqsController.radiusMax - body.pqsController.radiusMin) / 100) { return new SCANCoordinates(fixLonShift((body.GetLongitude(surfacePoint))), fixLatShift(body.GetLatitude(surfacePoint))); } else { + lastRadius = curRadius; curRadius = alt; loops++;