diff --git a/README.md b/README.md index b6645e2cc..2859e0509 100644 --- a/README.md +++ b/README.md @@ -36,29 +36,30 @@ * [b. Mismatched Scanners][3b] * [4. Big Map][4] * [a. Big Map Options][4a] -* [5. Zoom Map][5] - * [a. Target Selection][5a] - * [b. MechJeb Landing Guidance][5b] -* [6. Instrument Window][6] -* [7. Parts and Sensors Types][7] - * [a. RADAR][7a] - * [b. SAR][7b] - * [c. Multi][7c] - * [d. BTDT][7d] - * [e. MapTraq (deprecated)][7e] -* [8. (Career Mode) Research and Development][8] - * [a. Community Tech Tree Support][8a] - * [b. Minimum Scan for Science (30%)][8b] - * [c. Getting Maximum Science][8c] - * [d. Contracts][8d] -* [9. Color Management][9] - * [a. Terrain Colors and Options][9a] - * [b. Biome Colors and Options][9b] - * [c. Resource Colors and Options][9c] -* [10 Background Scanning][10] -* [11. Time Warp][11] -* [12. Settings Menu][12] -* [13. Note: Data Sources][13] +* [5. Planetary Overlay][5] + * [a. Overlay Control Window][5a] +* [6. Zoom Map][6] + * [a. Target Selection][6a] + * [b. MechJeb Landing Guidance][6b] +* [7. Instrument Window][7] +* [8. Parts and Sensors Types][8] + * [a. RADAR][8a] + * [b. SAR][8b] + * [c. Multi][8c] + * [d. BTDT][8d] + * [e. MapTraq (deprecated)][8e] +* [9. (Career Mode) Research and Development][9] + * [a. Minimum Scan for Science (30%)][9a] + * [b. Getting Maximum Science][9b] + * [c. Contracts][9c] +* [10. Color Management][10] + * [a. Terrain Colors and Options][10a] + * [b. Biome Colors and Options][10b] + * [c. Resource Colors and Options][10c] +* [11 Background Scanning][11] +* [12. Time Warp][12] +* [13. Settings Menu][13] +* [14. Note: Data Sources][14] **WARNING**: @@ -121,8 +122,12 @@ For licensing information, please see the [included LICENSE.txt][SCANsat:rel-lic * **No!** This version is completely backwards compatible, and you current scanning state (which is stored in persistent.sfs) will be safe and sound. Nevertheless, you should make a backup copy of your game before upgading any mod. * Do I need to attach a part to my vessel to use SCANsat? * **No, but...**. You can view existing maps from any vessel, but you need to attach a scanner to add new data to the maps. + * What does the "field of view" mean? + * When a sensor is at or above its "best" altitude (but below its maximum altitude) the field of view is half of the width of the swath mapped by the instrument, if it were in orbit around Kerbin. In other words, a field of view of 5° would map swathes which are 1/36th (10°) of the planetary surface wide. The field of view is scaled for smaller bodies so that more of the surface is covered. + * What does the "best" altitude mean? + * At or above the best altitude, the sensor will operate with its listed field of view. Below this altitude the sensor suffers a linear penalty. A 10° FOV instrument with a best altitude of 500km would only have a 5° FOV at 250km. * [Career Mode] Does SCANsat give us science points? - * **Yes!** For each type of map, if you scan at least 30% of the surface, you can yse Data for partial science points; up until the maximum value at 95% map coverage. + * **Yes!** For each type of map, if you scan at least 30% of the surface, you can transmit that Data for partial science points; up until the maximum value at 95% map coverage. * [Career Mode] Is it integrated into the tech tree? * **Yes!** **[This link][8]** tells you which nodes unlock which parts in the tech tree. * [Contracts] Does SCANsat offer contracts to complete? @@ -217,6 +222,9 @@ Anomaly | **Been There, Done That(tm)** | **BTDT** **SCANsat** will scan celestial bodies for resources using the new stock resource system. +With default resource scanning options enabled the SCANsat resource map will automatically update as soon as a **stock resource scan** is completed. +> ![][resource-instant] + Resource scans are initiated in the same way as any other scan. In this case they use the stock **Orbital Survey Scanner**. > ![][resource-scanner] @@ -226,6 +234,11 @@ Resource scanning proceeds the same way as standard SCANsat scanning instruments The resource system can be enabled through the **SCANsat** Big Map: > ![][resource-walkthrough] +The examples below show the difference between high (top) and low (bottom) resolution resource scans +> ![][resource-bigmap-hires-full-biome] + +> ![][resource-bigmap-lores-full-biome] + Zoom map resource overlays require that a vessel with a narrow-band scanner be present in orbit and at an inclination high enough to cover the area in the zoom map. > ![][resource-zoom-map-covered] @@ -237,7 +250,7 @@ Resource overlays will work in IVA, too: #### [:top:][top] 2c. Resource Setting -A number of options are available in the **Settings Menu** for SCANsat resource scanning. +A number of options are available in the **Resource Settings Menu** for SCANsat resource scanning. > ![][resource-settings] @@ -250,10 +263,19 @@ A number of options are available in the **Settings Menu** for SCANsat resource * **Zoom Requires Narrow Band Scanner** * With this active the zoom map will only display resource overlays when a suitable **Narrow-Band Scanner** is in orbit around the planet, and its orbit covers the region showed in the zoom map. * When disabled the zoom map will display resource overlays regardless of **Narrow-Band Scanner** coverage. -* **Reset Resource Coverage** +* **Disable Stock Scanning** + * Disables the stock orbital survey + * Replaces the resource concentration readout from scanners with SCANsat modules + * Right-click menu resource concentration readout dependent on SCANsat scanning coverage +* **Reset SCANsat Resource Coverage** * This button will erase all resource scanning data for the current planet. * Regular SCANsat data will not be affected. * A confirmation window will appear upon clicking the button. +* **Reset Stock Resource Scanning** + * Stock resource scanning data can be erased for each planet (does not affect resource biome scanning data) +* **SCAN Planet Overlay Quality Settings** + * Interpolation settings can be increased or decreased to increase the accuracy of overlays + * Overlay map size can be adjusted for higher quality, but slower maps ### [:top:][top] 3. Basic Usage ------------------------------------------ @@ -332,7 +354,25 @@ The camera icon in the lower-right exports a copy of the map. The re-size icon in the lower-right corner can be dragged to re-size the map. -### [:top:][top] 5. Zoom Map +### [:top:][top] 5. Planetary Overlay +------------------------------------------ + +> ![][resource-planet-hires-full-biome] + +A separate window is used to control resource and biome planetary overlay maps. These maps are drawn directly over the surface of the current planet; they use the same system as the stock resource overlays and will replace those maps if both are opened at the same time. Map coverage is dependent upon SCANsat data; only scanned areas will be displayed on the map. +> ![][resource-planet-in-progress] + +SCANsat biome coverage can also be displayed using the overlay window. +> ![][biome-planet-overlay] + +#### [:top:][top] 5a. Overlay Control Window +> ![][resource-overlay-window] + +Each available resource can be selected for the planetary overlay maps, along with biome maps. Biome maps are currently limited to the stock color scheme without borders. + +The **Coverage Transparency** Options adds a grey background to areas that have been scanned but do not have any resources; this helps to visualize scanning progress. + +### [:top:][top] 6. Zoom Map ------------------------------------------ > ![][bigmap-zoom-open] @@ -351,15 +391,18 @@ The **zoom map** also features mouse-over information for the cursor location si Different map types, resource overlays and polar projections are all applied to the **zoom map** as well. > ![][zoommap-in] -#### [:top:][top] 5a. Target Selection +#### [:top:][top] 6a. Target Selection > ![][zoommap-scansat-landing] -The **zoom map** features an option to select and display a target site for each planet. Toggle selection mode by clicking on the target icon in the upper left, then select a sight +The **zoom map** features an option to select and display a target site for each planet. Toggle **Target Selection Mode** by clicking on the target icon in the upper left, then select a sight in the zoom map window. The icon will be displayed, along with standard, FinePrint waypoints, in the zoom window and the big map. While in map view the target site will be overlayed on the planet's surface; shown as a matching, four-arrow green icon. -#### [:top:][top] 5b. MechJeb Landing Guidance +To clear an existing target, activate **Target Selection Mode** by clicking the target icon, then click somewhere inside of the zoom map window, but outside of the map itself. +> ![][zoommap-clear-target] + +#### [:top:][top] 6b. MechJeb Landing Guidance > ![][zoommap-mechjeb-settings] If MechJeb is installed and an additional option is available in the settings menu to activate **MechJeb Landing Guidance Mode** @@ -372,7 +415,7 @@ and the MechJeb Landing Guidance module must be unlocked in the R&D Center. Landing sites selected through MechJeb will automatically show up as a waypoint on SCANsat maps. -### [:top:][top] 6. Instrument Window +### [:top:][top] 7. Instrument Window ------------------------------------------ > ![][instruments-small] @@ -389,7 +432,7 @@ The instruments window provides a readout of several types of data based on curr > ![][instruments-btdt] -### [:top:][top] 7. Parts and Sensor Types +### [:top:][top] 8. Parts and Sensor Types ------------------------------------------ | **Part** | **Scan Type** | **FOV** | Altitude (**Min**) | (**Ideal**) | (**Max**) @@ -400,19 +443,19 @@ The instruments window provides a readout of several types of data based on curr | [Been There Done That®][5d] | **Anomaly** | 1 | 0 m | 0 m | 2 km | [MapTraq® (deprecated)][5e] | **None** | N/A | N/A | N/A | N/A -#### [:top:][top] 7a. The RADAR Altimetry Sensor +#### [:top:][top] 8a. The RADAR Altimetry Sensor > ![RADAR][vab-radar] -#### [:top:][top] 7b. The SAR Altimetry Sensor +#### [:top:][top] 8b. The SAR Altimetry Sensor > ![SAR][vab-sar] -#### [:top:][top] 7c. The Multispectral Sensor +#### [:top:][top] 8c. The Multispectral Sensor > ![Multi][vab-multi] -#### [:top:][top] 7d. Been There Done That +#### [:top:][top] 8d. Been There Done That > ![BTDT][vab-btdt] -#### [:top:][top] 7e. MapTraq (deprecated) +#### [:top:][top] 8e. MapTraq (deprecated) > ![MapTraq][vab-maptraq] -### [:top:][top] 8. (Career Mode) Research and Development +### [:top:][top] 9. (Career Mode) Research and Development ------------------------------------------ The **RADAR Altimetry** sensor can be unlocked in **Basic Science**. @@ -423,35 +466,24 @@ The **Multispectral** sensor can be unlocked in **Advanced Exploration**. The **BTDT** sensor can be unlocked in **Field Science**. -##### [:top:][top] 8a. Community Tech Tree Support -When the [Community Tech Tree][ctt:release] addon is installed SCANsat parts will default to different tech tree nodes. - -The **RADAR Altimetry** sensor can be unlocked in **Orbital Surveys**. - -The **SAR Altimetry** sensor can be unlocked in **Specialized Science Tech**. - -The **Multispectral** sensor can be unlocked in **Advanced Surveys**. - -The **BTDT** sensor can be unlocked in **Field Science**. - -##### [:top:][top] 8b. Minimum Scan for Science +##### [:top:][top] 9a. Minimum Scan for Science Once you scan at least 30% of a particular map, you can use **Analyze Data** to get delicious science: > ![30% is your minimum][science-min] -##### [:top:][top] 8c. Getting Maximum Science +##### [:top:][top] 9b. Getting Maximum Science Between 30% and 100%, you will get a number of science points proportional to the percentage. Really, the upper cutoff is 95% in case you didn't scan the whole map. > ![Scan 95% to get all science][science-max] -##### [:top:][top] 8d. Contract Support +##### [:top:][top] 9c. Contract Support Career mode contracts are supported through third party addons. * [Contract Configurator Forum Thread][cconfig:release] * [SCANsat Contract Pack][ccfgSCANsat:release] -### [:top:][top] 9. Color Management +### [:top:][top] 10. Color Management ------------------------------------------ > ![][color-window] @@ -460,7 +492,7 @@ SCANsat provides multiple options for map color configurations and terrain level The color management window can be accessed from the big or small map with the color palette icon, or from the toolbar menu. -##### [:top:][top] 9a. Terrain Colors and Options +##### [:top:][top] 10a. Terrain Colors and Options On the left are the various color palettes available; there are four different styles that can be selected from the drop down menu. Palettes can be customized by changing the number of colors in the palette, reversing the order, or making the palette use discrete color transitions, rather than the smooth gradient used by default. @@ -480,7 +512,7 @@ from ocean to solid terrain more pronounced. All stock KSP planets have default color palette and terrain height values appropriate for the planet's terrain. Standard default values are used for any addon planets. -##### [:top:][top] 9b. Biome Colors and Options +##### [:top:][top] 10b. Biome Colors and Options Biome map colors and options can be controlled in the **Biome** tab of the window. * The end-point colors can be selected using the HSV color-picker; the value slider controls the brightness of the color. * Terrain transparency is controlled with a slider. @@ -492,7 +524,7 @@ Biomes can also be displayed using the stock color maps. > ![][color-biome-stock] -##### [:top:][top] 9c. Resource Colors and Options +##### [:top:][top] 10c. Resource Colors and Options Resource overlays can also be adjusted, using the **Resource** tab. * Resource colors are selected in the same manner as biome colors. * Upper and lower resource cutoff values can be adjusted with the sliders; use fine control mode for small adjustments. @@ -501,7 +533,7 @@ Resource overlays can also be adjusted, using the **Resource** tab. > ![][color-resource] -### [:top:][top] 10. Background Scanning +### [:top:][top] 12. Background Scanning ------------------------------------------ ![Note the background scanning (non-active vessels are scanning)][small-scan] @@ -510,7 +542,7 @@ Unlike some other KSP scanning systems, SCANsat allows scanning with multiple vessels. All online scanners scan at the same time during any scene where time progresses; no active SCANsat parts are necessary. -### [:top:][top] 11. Time Warp +### [:top:][top] 12. Time Warp ------------------------------------------ SCANsat does not interpolate satellite paths during time warp; nevertheless, due to the relatively large field of view @@ -527,7 +559,7 @@ It starts at **1000x** and then speeds up to **10,000x**: Notice that the only gaps in coverage are those at the poles (ie, the selected inclination was not high enough to capture the poles). -### [:top:][top] 12. Settings Menu +### [:top:][top] 13. Settings Menu ------------------------------------------ > ![][settings-window] @@ -536,7 +568,6 @@ The settings menu has a various general options * The marker used for **Anomalies** can be specified * **Background scanning** can be controlled for each planet * **Background scanning** resolution can be lowered for better performance (watch for short pauses when several scanners are active at very high timewarp; reducing the scanning resolution can help with this) -* See the **[Resource Settings][2c]** section for information about resource options * Toggles control the availability of the **Stock App Launcher** button, and the **Tooltips** for various icons on other windows * If MechJeb is installed an additional option is available to toggle the MechJeb Landing Guidance interface * If the windows are ever dragged off screen there is an option to **Reset All Windows** to their default positions @@ -546,7 +577,7 @@ The settings menu has a various general options * **Sensors:** The total number of SCANsat sensors on all vessels; note that all combination sensors are separated into their invidual components, i.e. the Multi-Spectral scanner consists of two sensors, Biomes and Anomalies. * **Passes:** The number of scanning passes recorded per second, this number can easily be in the tens of thousands at high time warp with multiple vessels and sensors active. -### [:top:][top] 13. Note Concerning Data Sources +### [:top:][top] 14. Note Concerning Data Sources ------------------------------------------ All data this mod shows you is pulled from your game as you play. This @@ -618,14 +649,31 @@ sneaky then they can of course be sneaky. [zoommap-scansat-landing]: http://i.imgur.com/ILqRfne.gif [zoommap-mechjeb-landing]: http://i.imgur.com/nE0BlA8.gif [zoommap-mechjeb-settings]: http://i.imgur.com/xOQ7ooj.png +[zoommap-clear-target]: http://i.imgur.com/YffxdNs.gif [resource-iva]: http://i.imgur.com/iRo4kSA.png [resource-walkthrough]: http://i.imgur.com/KS4FTh0.gif [resource-scanner]: http://i.imgur.com/mY0fFjr.gif [resource-bigmap]: http://i.imgur.com/JYKG6f5.gif -[resource-settings]: http://i.imgur.com/sgMklCu.png +[resource-settings]: http://i.imgur.com/TTKttD2.png [resource-zoom-map-covered]: http://i.imgur.com/7YuYMGW.png [resource-zoom-map-uncovered]: http://i.imgur.com/cJ9JtdW.png +[resource-instant]: http://i.imgur.com/mfIMBEP.gif + +[resource-planet-hires-limited-biome]: http://i.imgur.com/yhv2bsq.png +[resource-planet-hires-full-biome]: http://i.imgur.com/rwy77M3.png +[resource-planet-lores-limited-biome]: http://i.imgur.com/tR3eTzL.png +[resource-planet-lores-full-biome]: http://i.imgur.com/kPcO2H7.png +[resource-planet-in-progress]: http://i.imgur.com/0JBSFbB.png +[biome-planet-overlay]: http://i.imgur.com/YofnSEI.png +[biome-planet-in-progress]: http://i.imgur.com/AwQfBgq.png + +[resource-bigmap-hires-limited-biome]: http://i.imgur.com/y0jitxK.png +[resource-bigmap-hires-full-biome]: http://i.imgur.com/fCdXTIq.png +[resource-bigmap-lores-limited-biome]: http://i.imgur.com/iHCBfes.png +[resource-bigmap-lores-full-biome]: http://i.imgur.com/TIR1xv5.png + +[resource-overlay-window]: http://i.imgur.com/9PcxEqN.png [color-window]: http://i.imgur.com/RQVjq6g.png [color-palette-switch]: http://i.imgur.com/0XdMGSy.gif @@ -659,29 +707,30 @@ sneaky then they can of course be sneaky. [3b]: #top-3b-mismatched-scanners [4]: #top-4-big-map [4a]: #top-4a-big-map-options -[5]: #top-5-zoom-map -[5a]: #top-5a-target-selection -[5b]: #top-5b-mechJeb-landing-guidance -[6]: #top-6-instrument-window -[7]: #top-7-parts-and-sensor-types -[7a]: #top-7a-the-radar-altimetry-sensor -[7b]: #top-7b-the-sar-altimetry-sensor -[7c]: #top-7c-the-multispectral-sensor -[7d]: #top-7d-been-there-done-that -[7e]: #top-7e-maptraq-deprecated -[8]: #top-8-career-mode-research-and-development -[8a]: #top-8a-community-tech-tree-support -[8b]: #top-8b-minimum-scan-for-science -[8c]: #top-8c-getting-maximum-science -[8d]: #top-8d-contract-support -[9]: #top-9-color-management -[9a]: #top-9a-terrain-colors-and-options -[9b]: #top-9b-biome-colors-and-options -[9c]: #top-9c-resource-colors-and-options -[10]: #top-10-background-scanning -[11]: #top-11-time-warp -[12]: #top-12-settings-menu -[13]: #top-13-note-concerning-data-sources +[5]: #top-5-planetary-overlay +[5a]: #top-5a-overlay-control-window +[6]: #top-6-zoom-map +[6a]: #top-6a-target-selection +[6b]: #top-6b-mechJeb-landing-guidance +[7]: #top-7-instrument-window +[8]: #top-8-parts-and-sensor-types +[8a]: #top-8a-the-radar-altimetry-sensor +[8b]: #top-8b-the-sar-altimetry-sensor +[8c]: #top-8c-the-multispectral-sensor +[8d]: #top-8d-been-there-done-that +[8e]: #top-8e-maptraq-deprecated +[9]: #top-9-career-mode-research-and-development +[9a]: #top-9a-minimum-scan-for-science +[9b]: #top-9b-getting-maximum-science +[9c]: #top-9c-contract-support +[10]: #top-10-color-management +[10a]: #top-10a-terrain-colors-and-options +[10b]: #top-10b-biome-colors-and-options +[10c]: #top-10c-resource-colors-and-options +[11]: #top-11-background-scanning +[12]: #top-12-time-warp +[13]: #top-13-settings-menu +[14]: #top-14-note-concerning-data-sources [shield:license-bsd]: http://img.shields.io/:license-bsd-blue.svg [shield:license-mit]: http://img.shields.io/:license-mit-a31f34.svg diff --git a/SCANassets/Icons/SCAN_Overlay_Icon.dds b/SCANassets/Icons/SCAN_Overlay_Icon.dds new file mode 100644 index 000000000..78ab017f0 Binary files /dev/null and b/SCANassets/Icons/SCAN_Overlay_Icon.dds differ diff --git a/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg b/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg index c75cc7f7d..a9e8d4ed7 100644 --- a/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg +++ b/SCANassets/MM_Parts/SCANsat_Resource_Scanner.cfg @@ -1,3 +1,91 @@ +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[Ore],#ScannerType[0]]]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 256 + ScannerType = 0 + ResourceName = Ore + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[Karbonite],#ScannerType[0]]]:NEEDS[CommunityResourcePack]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 262144 + ScannerType = 0 + ResourceName = Karbonite + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[MetallicOre],#ScannerType[0]]]:NEEDS[CommunityResourcePack]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 128 + ScannerType = 0 + ResourceName = MetallicOre + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[Minerals],#ScannerType[0]]]:NEEDS[CommunityResourcePack]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 32768 + ScannerType = 0 + ResourceName = Minerals + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[Substrate],#ScannerType[0]]]:NEEDS[CommunityResourcePack]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 65536 + ScannerType = 0 + ResourceName = Substrate + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[Uraninite],#ScannerType[0]]]:NEEDS[CommunityResourcePack]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 1024 + ScannerType = 0 + ResourceName = Uraninite + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[Water],#ScannerType[0]]]:NEEDS[CommunityResourcePack]:FOR[SCANsat] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 8192 + ScannerType = 0 + ResourceName = Water + } +} + +@PART[*]:HAS[@MODULE[ModuleResourceScanner]:HAS[#ResourceName[He-3],#ScannerType[0]]]:FOR[SCANsat]:NEEDS[] +{ + MODULE + { + name = SCANresourceDisplay + sensorType = 512 + ScannerType = 0 + ResourceName = He-3 + } +} + @PART[OrbitalScanner]:FOR[SCANsat] { MODULE @@ -10,8 +98,6 @@ best_alt = 100000 scanName = Ore Scan power = 0.5 - activeModule = False - forceActive = False } } @@ -20,15 +106,13 @@ MODULE { name = ModuleSCANresourceScanner - sensorType = 392576 //Use 256 for Ore only + sensorType = 524288 fov = 4 min_alt = 20000 max_alt = 750000 best_alt = 100000 scanName = Resource Scan power = 0.75 - activeModule = True - forceActive = False } } @@ -44,8 +128,6 @@ best_alt = 100000 scanName = Resource Scan power = 0.5 - activeModule = True - forceActive = False } } @@ -61,7 +143,5 @@ best_alt = 100000 scanName = Karbonite Scan power = 0.5 - activeModule = True - forceActive = True } } diff --git a/SCANassets/Parts/MapTraq/MapTraq.cfg b/SCANassets/Parts/MapTraq/MapTraq.cfg index c326f25eb..866b98825 100644 --- a/SCANassets/Parts/MapTraq/MapTraq.cfg +++ b/SCANassets/Parts/MapTraq/MapTraq.cfg @@ -1,4 +1,4 @@ -PART +PART { name = SCANsat_Tracker module = Part @@ -7,7 +7,7 @@ author = damny MODEL { model = SCANsat/Parts/MapTraq/MapTraq - texture = SCANsat/Parts/BTDT/SCANsat + texture = SCANsat, SCANsat/Parts/BTDT/SCANsat position = 0, 0, 0 rotation = 0, 0, 0 scale = 1, 1, 1 diff --git a/SCANassets/Resources/SCANcolors.cfg b/SCANassets/Resources/SCANcolors.cfg index f107c2f19..63a4a2ce3 100644 --- a/SCANassets/Resources/SCANcolors.cfg +++ b/SCANassets/Resources/SCANcolors.cfg @@ -7,7 +7,7 @@ SCAN_Color_Config defaultPalette = Default lowBiomeColor = 0,0.46,0.02345098,1 highBiomeColor = 0.7,0.2388235,0,1 - biomeTransparency = 30 + biomeTransparency = 25 stockBiomeMap = False bottomLowSlopeColor = 0.004705883,0.6,0.3788235,1 bottemHighSlopeColor = 0.9764706,1,0.4627451,1 @@ -229,7 +229,7 @@ SCAN_Color_Config highResourceColor = 0.7888628,0,0.94,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 15 Resource_Planetary_Config { Item @@ -377,7 +377,7 @@ SCAN_Color_Config highResourceColor = 0.75,0.3823529,0,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 10 Resource_Planetary_Config { Item @@ -525,7 +525,7 @@ SCAN_Color_Config highResourceColor = 0,0.576471,0.07451,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 10 Resource_Planetary_Config { Item @@ -673,7 +673,7 @@ SCAN_Color_Config highResourceColor = 0.7428235,0.82,0,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 10 Resource_Planetary_Config { Item @@ -821,7 +821,7 @@ SCAN_Color_Config highResourceColor = 1,0.2352941,0.03137255,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 10 Resource_Planetary_Config { Item @@ -969,7 +969,7 @@ SCAN_Color_Config highResourceColor = 0,0.5687844,0.98,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 10 Resource_Planetary_Config { Item @@ -1117,7 +1117,7 @@ SCAN_Color_Config highResourceColor = 0.9,0.6,0,1 resourceTransparency = 20 defaultMinValue = 1 - defaultMaxValue = 7.5 + defaultMaxValue = 10 Resource_Planetary_Config { Item @@ -1258,5 +1258,153 @@ SCAN_Color_Config } } } + Item + { + name = He-3 + lowResourceColor = 0,0.5490196,1,1 + highResourceColor = 0.3670588,0.9,0,1 + resourceTransparency = 20 + defaultMinValue = 0 + defaultMaxValue = 5 + Resource_Planetary_Config + { + Item + { + resourceName = He-3 + bodyName = Sun + index = 0 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Kerbin + index = 1 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Mun + index = 2 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Minmus + index = 3 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Moho + index = 4 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Eve + index = 5 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Duna + index = 6 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Ike + index = 7 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Jool + index = 8 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Laythe + index = 9 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Vall + index = 10 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Bop + index = 11 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Tylo + index = 12 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Gilly + index = 13 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Pol + index = 14 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Dres + index = 15 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + Item + { + resourceName = He-3 + bodyName = Eeloo + index = 16 + lowResourceCutoff = 0 + highResourceCutoff = 5 + } + } + } } } diff --git a/SCANassets/Resources/SCANresource.cfg b/SCANassets/Resources/SCANresource.cfg index 96877a26c..bd968211b 100644 --- a/SCANassets/Resources/SCANresource.cfg +++ b/SCANassets/Resources/SCANresource.cfg @@ -23,6 +23,11 @@ SCANSAT_SENSOR SCANtype = 256 //2^8 } SCANSAT_SENSOR +{ + name = He-3 + SCANtype = 512 //2^9 +} +SCANSAT_SENSOR { name = Uraninite SCANtype = 1024 //2^10 diff --git a/SCANassets/SCANsat.version b/SCANassets/SCANsat.version index 792c47756..b350f5838 100644 --- a/SCANassets/SCANsat.version +++ b/SCANassets/SCANsat.version @@ -5,13 +5,13 @@ "GITHUB":{ "USERNAME":"S-C-A-N", "REPOSITORY":"SCANsat", - "ALLOW_PRE_RELEASE":false + "ALLOW_PRE_RELEASE":true }, "VERSION":{ "MAJOR":1, "MINOR":1, - "PATCH":2, - "BUILD":0 + "PATCH":3, + "BUILD":1 }, "KSP_VERSION":{ "MAJOR":1, diff --git a/SCANmechjeb/Properties/AssemblyInfo.cs b/SCANmechjeb/Properties/AssemblyInfo.cs index 38e235b4e..3ae449b3c 100644 --- a/SCANmechjeb/Properties/AssemblyInfo.cs +++ b/SCANmechjeb/Properties/AssemblyInfo.cs @@ -32,10 +32,10 @@ // 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.2.0.0")] -[assembly: AssemblyFileVersion("1.2.0.0")] -[assembly: AssemblyInformationalVersion ("v12")] +[assembly: AssemblyVersion("1.3.1.0")] +[assembly: AssemblyFileVersion("1.3.1.0")] +[assembly: AssemblyInformationalVersion ("v13.1")] [assembly: KSPAssembly ("SCANmechjeb", 0, 3)] -[assembly: KSPAssemblyDependency ("SCANsat", 1, 2)] +[assembly: KSPAssemblyDependency ("SCANsat", 1, 3)] [assembly: KSPAssemblyDependency("MechJeb2", 2, 5)] diff --git a/SCANmechjeb/SCANmechjebMainMenu.cs b/SCANmechjeb/SCANmechjebMainMenu.cs index 4588c3db8..e21b190b8 100644 --- a/SCANmechjeb/SCANmechjebMainMenu.cs +++ b/SCANmechjeb/SCANmechjebMainMenu.cs @@ -24,7 +24,7 @@ public class SCANmechjebMainMenu : MonoBehaviour { private const string SCANsatName = "SCANsat"; private const string MechJeb = "MechJeb2"; - private readonly Version MechJebVersion = new Version(2, 5, 0, 0); + private readonly Version MechJebVersion = new Version(2, 5, 1, 0); private static bool loaded = false; private void Awake() @@ -69,12 +69,7 @@ private bool checkLoaded() if (MechJebAssembly == null) return false; - var fileV = Attribute.GetCustomAttribute(MechJebAssembly.assembly, typeof(AssemblyFileVersionAttribute)) as AssemblyFileVersionAttribute; - - if (fileV == null) - return false; - - if (fileV.Version == MechJebVersion.ToString()) + if (MechJebAssembly.assembly.GetName().Version == MechJebVersion) { SCANsat.SCANmainMenuLoader.MechJebLoaded = true; return true; diff --git a/SCANsat/CHANGELOG.txt b/SCANsat/CHANGELOG.txt index 54289f033..510511872 100644 --- a/SCANsat/CHANGELOG.txt +++ b/SCANsat/CHANGELOG.txt @@ -1,3 +1,59 @@ +Version 13.1 - 2015-6-6 +------------------------ + +- Resource Scanning Overhaul + +- New option available to disable stock scanning + - Disables the orbital survey + - Replaces the resource concentration readout from scanners with SCANsat modules + - Right-click menu resource concentration readout dependent on SCANsat scanning coverage + - Stock resource scanning data can be erased for each planet (does not affect resource biome scanning data) + +- Stock resource parts adapted for SCANsat resource scanning + - Module Manager required for SCANsat resource scanning + - M700 (clamshell) scanner used for low-resolution resource scanning; covers all resources + - Narrow-band scanners used for high-resolution, individual resource scanning + +- Planetary map overlay + - New window to control resource and biome map overlays + - Biome overlays limited to stock color scheme for now + - Overlay window buttons added to the big map and small map windows; also added to the Toolbar menu + - Select between all available resources and biome maps + - Coverage Transparency option shows scanned areas in grey if there are no resources present + +- Resource settings window + - New window to control resource options and planetary overlay quality + - Biome lock, instant scan, and zoom window options are the same as in previous versions + - The instant scan option is automatically disabled when Disable Stock Resources is activated + - Both SCANsat and stock resource scanning data for the current planet can be reset + - Interpolation and map overlay size can be configured + - Biome maps use twice the map height as resource maps (512*256 for resources; 1024*512 for biomes by default) + +- SCANsat big map + - Resource overlay now matches the planetary overlay more closely + - Interpolation is used to generate the map overlay; this greatly speeds up big map rendering speed + - Zoom map uses more accurate interpolation method + - Biome maps can be generated without the white border + +- Bug Fixes + - Waypoint location correct when waypoint coordinates are stored with nonsense values (ie. -120 S...) + - Active vessel properly updates for the big map orbit display + +Version 12.1 - 2015-5-30 +------------------------ + +- Updated for MechJeb 2.5.1 + +- Added SCANsat sensor type and color configs for He-3 + - SCANsat sensortype = 512 + +- Fix a bug while adding resource scanners in the editor +- Add resource scanner action groups + - Only work when the scanner is deployed + +- Fix MapTraq texture location + + Version 12 - 2015-5-3 ------------------------ diff --git a/SCANsat/Properties/AssemblyInfo.cs b/SCANsat/Properties/AssemblyInfo.cs index cb9ab4faf..860401d5b 100644 --- a/SCANsat/Properties/AssemblyInfo.cs +++ b/SCANsat/Properties/AssemblyInfo.cs @@ -14,10 +14,10 @@ // 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.2.0.0")] -[assembly: AssemblyFileVersion ("1.2.0.0")] -[assembly: AssemblyInformationalVersion ("v12")] +[assembly: AssemblyVersion ("1.3.1.0")] +[assembly: AssemblyFileVersion ("1.3.1.0")] +[assembly: AssemblyInformationalVersion ("v13.1")] -[assembly: KSPAssembly ("SCANsat", 1, 2)] +[assembly: KSPAssembly ("SCANsat", 1, 3)] diff --git a/SCANsat/SCAN_Color_Config.cs b/SCANsat/SCAN_Color_Config.cs index 92f2e6ba7..e511d9585 100644 --- a/SCANsat/SCAN_Color_Config.cs +++ b/SCANsat/SCAN_Color_Config.cs @@ -44,6 +44,8 @@ public class SCAN_Color_Config : SCAN_ConfigNodeStorage [Persistent] private bool stockBiomeMap = false; [Persistent] + private bool biomeBorder = true; + [Persistent] private Color bottomLowSlopeColor = palette.xkcd_PukeGreen; [Persistent] private Color bottemHighSlopeColor = palette.xkcd_Lemon; @@ -82,6 +84,8 @@ public override void OnEncodeToConfigNode() lowBiomeColor = SCANcontroller.controller.lowBiomeColor; highBiomeColor = SCANcontroller.controller.highBiomeColor; biomeTransparency = SCANcontroller.controller.biomeTransparency; + stockBiomeMap = SCANcontroller.controller.useStockBiomes; + biomeBorder = SCANcontroller.controller.biomeBorder; bottomLowSlopeColor = SCANcontroller.controller.lowSlopeColorOne; bottemHighSlopeColor = SCANcontroller.controller.highSlopeColorOne; topLowSlopeColor = SCANcontroller.controller.lowSlopeColorTwo; @@ -134,6 +138,11 @@ public bool StockBiomeMap get { return stockBiomeMap; } } + public bool BiomeBorder + { + get { return biomeBorder; } + } + public Color BottomLowSlopeColor { get { return bottomLowSlopeColor; } diff --git a/SCANsat/SCAN_Data/SCANdata.cs b/SCANsat/SCAN_Data/SCANdata.cs index d0cbfced6..1abefb237 100644 --- a/SCANsat/SCAN_Data/SCANdata.cs +++ b/SCANsat/SCAN_Data/SCANdata.cs @@ -308,7 +308,7 @@ internal int getCoverage(SCANtype type) uncov += coverage_count[7]; if ((type & SCANtype.Ore) != SCANtype.Nothing) uncov += coverage_count[8]; - if ((type & SCANtype.Kethane_4) != SCANtype.Nothing) + if ((type & SCANtype.Helium3) != SCANtype.Nothing) uncov += coverage_count[9]; if ((type & SCANtype.Uraninite) != SCANtype.Nothing) uncov += coverage_count[10]; @@ -328,7 +328,7 @@ internal int getCoverage(SCANtype type) uncov += coverage_count[17]; if ((type & SCANtype.Karbonite) != SCANtype.Nothing) uncov += coverage_count[18]; - if ((type & SCANtype.Regolith_10) != SCANtype.Nothing) + if ((type & SCANtype.FuzzyResources) != SCANtype.Nothing) uncov += coverage_count[19]; if ((type & SCANtype.Regolith_11) != SCANtype.Nothing) uncov += coverage_count[20]; diff --git a/SCANsat/SCAN_Data/SCANresourceBody.cs b/SCANsat/SCAN_Data/SCANresourceBody.cs index 04704bc93..c97280d59 100644 --- a/SCANsat/SCAN_Data/SCANresourceBody.cs +++ b/SCANsat/SCAN_Data/SCANresourceBody.cs @@ -31,6 +31,7 @@ public class SCANresourceBody : SCAN_ConfigNodeStorage private CelestialBody body; private float defaultMinValue, defaultMaxValue; + private float fraction; internal SCANresourceBody(string rName, CelestialBody Body, float min, float max) { @@ -125,5 +126,11 @@ internal set defaultMaxValue = value; } } + + public float Fraction + { + get { return fraction; } + internal set { fraction = value; } + } } } diff --git a/SCANsat/SCAN_Data/SCANresourceGlobal.cs b/SCANsat/SCAN_Data/SCANresourceGlobal.cs index c24b23fa8..7675b101c 100644 --- a/SCANsat/SCAN_Data/SCANresourceGlobal.cs +++ b/SCANsat/SCAN_Data/SCANresourceGlobal.cs @@ -44,8 +44,9 @@ public class SCANresourceGlobal : SCAN_ConfigNodeStorage private Color defaultLowColor; private Color defaultHighColor; + private Color32 lowColor32; + private Color32 highColor32; private float defaultTrans; - private Texture2D mapOverlay; private SCANresourceBody currentBody; @@ -55,6 +56,8 @@ internal SCANresourceGlobal(string resource, float trans, float defMin, float de resourceTransparency = trans; lowResourceColor = minC; highResourceColor = maxC; + lowColor32 = (Color32)lowResourceColor; + highColor32 = (Color32)highResourceColor; defaultMinValue = defMin; defaultMaxValue = defMax; resourceType = t; @@ -73,6 +76,8 @@ internal SCANresourceGlobal(SCANresourceGlobal copy) resourceTransparency = copy.resourceTransparency; lowResourceColor = copy.lowResourceColor; highResourceColor = copy.highResourceColor; + lowColor32 = copy.lowColor32; + highColor32 = copy.highColor32; sType = copy.sType; resourceType = copy.resourceType; masterBodyConfigs = copyBodyConfigs(copy); @@ -101,6 +106,9 @@ public override void OnDecodeFromConfigNode() resourceType = SCANcontroller.getResourceType(name); sType = resourceType.Type; + lowColor32 = (Color32)lowResourceColor; + highColor32 = (Color32)highResourceColor; + setDefaultValues(); try { @@ -171,13 +179,31 @@ internal set public Color MinColor { get { return lowResourceColor; } - internal set { lowResourceColor = value; } + internal set + { + lowResourceColor = value; + lowColor32 = (Color32)value; + } } public Color MaxColor { get { return highResourceColor; } - internal set { highResourceColor = value; } + internal set + { + highResourceColor = value; + highColor32 = (Color32)value; + } + } + + public Color32 MinColor32 + { + get { return lowColor32; } + } + + public Color32 MaxColor32 + { + get { return highColor32; } } public float DefaultMinValue @@ -262,11 +288,5 @@ public float DefaultTrans { get { return defaultTrans; } } - - public Texture2D MapOverlay - { - get { return mapOverlay; } - set { mapOverlay = value; } - } } } diff --git a/SCANsat/SCAN_Data/SCANterrainConfig.cs b/SCANsat/SCAN_Data/SCANterrainConfig.cs index e4dae6c9c..d7dbbdd81 100644 --- a/SCANsat/SCAN_Data/SCANterrainConfig.cs +++ b/SCANsat/SCAN_Data/SCANterrainConfig.cs @@ -43,6 +43,7 @@ public class SCANterrainConfig : SCAN_ConfigNodeStorage private float? clampTerrain; private float defaultMinHeight, defaultMaxHeight; + private float terrainRange; private Palette defaultPalette; private int defaultPaletteSize; private bool defaultReverse, defaultDiscrete; @@ -52,6 +53,7 @@ internal SCANterrainConfig(float min, float max, float? clamp, Palette color, in { minHeightRange = min; maxHeightRange = max; + terrainRange = max - min; clampTerrain = clamp; if (clampTerrain == null) clampHeight = "Null"; @@ -77,6 +79,7 @@ internal SCANterrainConfig(SCANterrainConfig copy) { minHeightRange = copy.minHeightRange; maxHeightRange = copy.maxHeightRange; + terrainRange = maxHeightRange - minHeightRange; clampTerrain = copy.clampTerrain; clampHeight = copy.clampHeight; colorPal = copy.colorPal; @@ -104,18 +107,9 @@ public override void OnDecodeFromConfigNode() else clampTerrain = null; - setDefaultValues(); + terrainRange = maxHeightRange - minHeightRange; - SCANUtil.SCANdebugLog("SCANsat Terrain Config Decode"); - SCANUtil.SCANdebugLog("-------->Body Name => {0}", name); - SCANUtil.SCANdebugLog("-------->Body Index => {0}", index); - SCANUtil.SCANdebugLog("-------->Min Height Range => {0}", minHeightRange); - SCANUtil.SCANdebugLog("-------->Max Height Range => {0}", maxHeightRange); - SCANUtil.SCANdebugLog("-------->Clamp Height => {0}", clampHeight); - SCANUtil.SCANdebugLog("-------->Palette Name => {0}", paletteName); - SCANUtil.SCANdebugLog("-------->Palette Size => {0}", paletteSize); - SCANUtil.SCANdebugLog("-------->Palette Reverse => {0}", paletteReverse); - SCANUtil.SCANdebugLog("-------->Palette Discrete => {0}", paletteDiscrete); + setDefaultValues(); } private void setDefaultValues() @@ -131,7 +125,6 @@ private void setDefaultValues() public override void OnEncodeToConfigNode() { - SCANUtil.SCANdebugLog("Saving Terrain Node"); if (clampTerrain == null) clampHeight = "Null"; else @@ -146,7 +139,10 @@ public float MinTerrain internal set { if (value < maxHeightRange) + { + terrainRange = maxHeightRange - value; minHeightRange = value; + } } } @@ -156,10 +152,18 @@ public float MaxTerrain internal set { if (value > minHeightRange) + { + terrainRange = value - minHeightRange; maxHeightRange = value; + } } } + public float TerrainRange + { + get { return terrainRange; } + } + public float? ClampTerrain { get { return clampTerrain; } diff --git a/SCANsat/SCAN_Data/SCANtype.cs b/SCANsat/SCAN_Data/SCANtype.cs index 1ac7c2a2d..715a40e9c 100644 --- a/SCANsat/SCAN_Data/SCANtype.cs +++ b/SCANsat/SCAN_Data/SCANtype.cs @@ -25,10 +25,10 @@ public enum SCANtype : int Biome = 1 << 3, // biome data Anomaly = 1 << 4, // anomalies (position of anomaly) AnomalyDetail = 1 << 5, // anomaly detail (name of anomaly, etc.) - Kethane = 1 << 6, // Kethane - K-type - Kethane + Kethane = 1 << 6, // Kethane MetallicOre = 1 << 7, // CRP Ore - Regolith Ore = 1 << 8, //Stock Ore - Kethane_4 = 1 << 9, // Reserved - K-type + Helium3 = 1 << 9, // Helium 3 Uraninite = 1 << 10, // Uranium - Regolith - KSPI Thorium = 1 << 11, // Thorium - Regolith - KSPI Alumina = 1 << 12, // Alumina - Regolith - KSPI @@ -38,12 +38,13 @@ public enum SCANtype : int Substrate = 1 << 16, // Substrate - Regolith & K-type - MKS KEEZO = 1 << 17, // KEEZO - Regolith - Kass Effect Karbonite = 1 << 18, // Karbonite - Regolith - Regolith_10 = 1 << 19, // Reserved - Regolith + FuzzyResources = 1 << 19, // Low Detail Resource Regolith_11 = 1<< 20, // Reserved - Regolith Everything_SCAN = (1 << 6) - 1, // All default SCANsat scanners AllResources = 2147483584, // All resource types - DefinedResources = 392576, // All defined resource types + DefinedResources = 393088, // All defined resource types + MKSResources = 107648, // All standard MKS/USI resources Everything = Int32.MaxValue // All scanner types } } diff --git a/SCANsat/SCAN_Data/SCANwaypoint.cs b/SCANsat/SCAN_Data/SCANwaypoint.cs index cc83a31f0..dec8b376b 100644 --- a/SCANsat/SCAN_Data/SCANwaypoint.cs +++ b/SCANsat/SCAN_Data/SCANwaypoint.cs @@ -15,6 +15,7 @@ using FinePrint.Contracts.Parameters; using FinePrint; using FinePrint.Utilities; +using UnityEngine; namespace SCANsat.SCAN_Data { @@ -29,8 +30,9 @@ internal SCANwaypoint(SurveyWaypointParameter p) root = p.Root; param = p; name = way.name; - longitude = SCANUtil.fixLonShift(way.longitude); - latitude = SCANUtil.fixLatShift(way.latitude); + Vector2d coords = SCANUtil.fixRetardCoordinates(new Vector2d(way.longitude, way.latitude)); + longitude = coords.x; + latitude = coords.y; landingTarget = false; } } @@ -44,8 +46,9 @@ internal SCANwaypoint(StationaryPointParameter p) root = p.Root; param = p; name = way.name; - longitude = SCANUtil.fixLonShift(way.longitude); - latitude = SCANUtil.fixLatShift(way.latitude); + Vector2d coords = SCANUtil.fixRetardCoordinates(new Vector2d(way.longitude, way.latitude)); + longitude = coords.x; + latitude = coords.y; landingTarget = false; } } @@ -57,8 +60,9 @@ internal SCANwaypoint(Waypoint p) root = p.contractReference; param = null; name = way.name; - longitude = SCANUtil.fixLonShift(way.longitude); - latitude = SCANUtil.fixLatShift(way.latitude); + Vector2d coords = SCANUtil.fixRetardCoordinates(new Vector2d(way.longitude, way.latitude)); + longitude = coords.x; + latitude = coords.y; landingTarget = false; } diff --git a/SCANsat/SCAN_Map/SCANmap.cs b/SCANsat/SCAN_Map/SCANmap.cs index 32a998f9a..1d52c0bb5 100644 --- a/SCANsat/SCAN_Map/SCANmap.cs +++ b/SCANsat/SCAN_Map/SCANmap.cs @@ -27,6 +27,14 @@ public class SCANmap internal SCANmap(CelestialBody Body, bool Cache) { body = Body; + pqs = body.pqsController != null; + biomeMap = body.BiomeMap != null; + data = SCANUtil.getData(body); + if (data == null) + { + data = new SCANdata(body); + SCANcontroller.controller.addToBodyData(body, data); + } cache = Cache; } @@ -39,7 +47,11 @@ internal SCANmap() public double MapScale { get { return mapscale; } - internal set { mapscale = value; } + internal set + { + mapscale = value; + resourceMapScale = (mapwidth / resourceMapWidth) * mapscale; + } } public double Lon_Offset @@ -110,7 +122,6 @@ public MapProjection Projection /* MAP: Big Map height map caching */ private float[,] big_heightmap; - private CelestialBody big_heightmap_body; private bool cache; private double centeredLong, centeredLat; @@ -275,6 +286,15 @@ internal double unprojectLatitude(double lon, double lat) /* MAP: scaling, centering (setting origin), translating, etc */ private double mapscale, lon_offset, lat_offset; private int mapwidth, mapheight; + private Color[] pix; + private float[,] resourceCache; + private int resourceInterpolation; + private int resourceMapWidth; + private int resourceMapHeight; + private double resourceMapScale; + private bool randomEdges = true; + private double[] biomeIndex; + private Color[] stockBiomeColor; internal void setSize(int w, int h) { @@ -283,10 +303,19 @@ internal void setSize(int w, int h) if (w > 360 * 4) w = 360 * 4; mapwidth = w; + pix = new Color[mapwidth]; + biomeIndex = new double[mapwidth]; + stockBiomeColor = new Color[mapwidth]; mapscale = mapwidth / 360f; if (h <= 0) h = (int)(180 * mapscale); mapheight = h; + resourceMapWidth = mapwidth; + resourceMapHeight = mapheight; + resourceCache = new float[resourceMapWidth, resourceMapHeight]; + resourceInterpolation = 2; + resourceMapScale = resourceMapWidth / 360; + randomEdges = false; if (map != null) { if (mapwidth != map.width || mapheight != map.height) @@ -307,11 +336,19 @@ internal void setWidth(int w) if (mapwidth == w) return; mapwidth = w; + pix = new Color[w]; + biomeIndex = new double[w]; + stockBiomeColor = new Color[w]; + resourceMapWidth = 512; + resourceMapHeight = resourceMapWidth / 2; + resourceInterpolation = 8; + resourceMapScale = resourceMapWidth / 360f; + resourceCache = new float[resourceMapWidth, resourceMapHeight]; + randomEdges = true; mapscale = mapwidth / 360f; mapheight = (int)(w / 2); /* big map caching */ big_heightmap = new float[mapwidth, mapheight]; - big_heightmap_body = body; map = null; resetMap(); } @@ -356,6 +393,14 @@ private double unScaleLatitude(double lat) return lat; } + private double unScaleLatitude(double lat, double scale) + { + lat -= lat_offset; + lat += 90; + lat *= scale; + return lat; + } + private double unScaleLongitude(double lon) { lon -= lon_offset; @@ -364,11 +409,19 @@ private double unScaleLongitude(double lon) return lon; } + private double unScaleLongitude(double lon, double scale) + { + lon -= lon_offset; + lon += 180; + lon *= scale; + return lon; + } + private double fixUnscale(double value, int size) { if (value < 0) value = 0; - else if (value >= size - 0.5) + else if (value >= (size - 0.5f)) value = size - 1; return value; } @@ -378,16 +431,31 @@ private double fixUnscale(double value, int size) private Texture2D map; // refs above: 214,215,216,232, below, and JSISCANsatRPM. private CelestialBody body; // all refs are below private SCANresourceGlobal resource; + private SCANdata data; private SCANmapLegend mapLegend; private int mapstep; // all refs are below private double[] mapline; // all refs are below + private bool pqs; + private bool biomeMap; /* MAP: nearly trivial functions */ public void setBody(CelestialBody b) { - if (body == b) - return; body = b; + pqs = body.pqsController != null; + biomeMap = body.BiomeMap != null; + data = SCANUtil.getData(body); + + /* init cache if necessary */ + if (cache) + { + for (int x = 0; x < mapwidth; x++) + { + for (int y = 0; y < mapwidth / 2; y++) + big_heightmap[x, y] = 0f; + } + } + if (SCANconfigLoader.GlobalResource) { resource = SCANcontroller.getResourceNode(SCANcontroller.controller.resourceSelection); @@ -406,7 +474,7 @@ internal bool isMapComplete() public void resetMap(bool setRes = true) { - mapstep = 0; + mapstep = -2; if (SCANconfigLoader.GlobalResource && setRes) { //Make sure that a resource is initialized if necessary if (resource == null && body != null) @@ -416,6 +484,7 @@ public void resetMap(bool setRes = true) resource = SCANcontroller.GetFirstResource; resource.CurrentBodyConfig(body.name); } + resetResourceMap(); } } @@ -426,6 +495,17 @@ public void resetMap(mapType mode, bool Cache, bool setRes = true) resetMap(setRes); } + public void resetResourceMap() + { + for (int i = 0; i < resourceMapWidth; i++ ) + { + for (int j = 0; j < resourceMapHeight; j++) + { + resourceCache[i, j] = 0; + } + } + } + /* MAP: export: PNG file */ internal void exportPNG() { @@ -460,24 +540,12 @@ internal void exportPNG() /* MAP: build: map to Texture2D */ internal Texture2D getPartialMap() { - SCANdata data = SCANUtil.getData(body); if (data == null) return new Texture2D(1, 1); - Color[] pix; - /* init cache if necessary */ - if (cache) - { - if (body != big_heightmap_body) - { - for (int x = 0; x < mapwidth; x++) - { - for (int y = 0; y < mapwidth / 2; y++) - big_heightmap[x, y] = 0f; - } - big_heightmap_body = body; - } - } + System.Random r = new System.Random(ResourceScenario.Instance.gameSettings.Seed); + + bool resourceOn = false; if (map == null) { @@ -499,207 +567,283 @@ internal Texture2D getPartialMap() palette.redline[i] = palette.red; } - if (mapstep < map.height - 1) - { - map.SetPixels(0, mapstep + 1, map.width, 1, palette.redline); - } + resourceOn = SCANcontroller.controller.map_ResourceOverlay && SCANconfigLoader.GlobalResource && resource != null; - if (mapstep <= 0) + if (mapstep <= -2) { - mapstep = 0; - mapline = new double[map.width]; - } + if (!resourceOn) + { + mapstep++; + return map; + } + else + { + for (int j = 0; j < resourceMapHeight; j += resourceInterpolation) + { + for (int i = 0; i < resourceMapWidth; i += resourceInterpolation) + { + double rLon = (i * 1.0f / resourceMapScale) - 180f + lon_offset; + double rLat = (j * 1.0f / resourceMapScale) - 90f + lat_offset; - pix = map.GetPixels(0, mapstep, map.width, 1); + resourceCache[i, j] = SCANUtil.ResourceOverlay(rLat, rLon, resource.Name, body, SCANcontroller.controller.resourceBiomeLock) * 100f; + } + } + mapstep++; + return map; + } + } for (int i = 0; i < map.width; i++) { - Color baseColor = palette.grey; - pix[i] = baseColor; - int scheme = SCANcontroller.controller.colours; - float projVal = 0f; - double lat = (mapstep * 1.0f / mapscale) - 90f + lat_offset; - double lon = (i * 1.0f / mapscale) - 180f + lon_offset; - double la = lat, lo = lon; - lat = unprojectLatitude(lo, la); - lon = unprojectLongitude(lo, la); - /* Introduce altimetry check here; Use unprojected lat/long coordinates * All cached altimetry data stored in a single 2D array in rectangular format * Pull altimetry data from cache after unprojection */ - if (body.pqsController != null && cache) + double cacheLat = ((mapstep + 1) * 1.0f / mapscale) - 90f + lat_offset; + double lon = (i * 1.0f / mapscale) - 180f + lon_offset; + + if (body.pqsController != null && cache && mapstep + 1 < map.height) { - if (big_heightmap[i, mapstep] == 0f) + if (big_heightmap[i, mapstep + 1] == 0f) { - if (SCANUtil.isCovered(lo, la, data, SCANtype.Altimetry)) - terrainHeightToArray(lo, la, i, mapstep); + if (SCANUtil.isCovered(lon, cacheLat, data, SCANtype.Altimetry)) + terrainHeightToArray(lon, cacheLat, i, mapstep + 1); } } + if (mapstep < 0) + continue; + + if (mType != mapType.Biome || !biomeMap) + continue; + + double lat = (mapstep * 1.0f / mapscale) - 90f + lat_offset; + double la = lat, lo = lon; + lat = unprojectLatitude(lo, la); + lon = unprojectLongitude(lo, la); + if (double.IsNaN(lat) || double.IsNaN(lon) || lat < -90 || lat > 90 || lon < -180 || lon > 180) { - pix[i] = palette.clear; + stockBiomeColor[i] = palette.clear; + biomeIndex[i] = 0; continue; } - /* Altimetry Map */ - if (mType == mapType.Altimetry) + if (SCANcontroller.controller.useStockBiomes && SCANcontroller.controller.colours == 0) { - if (body.pqsController == null) - { - baseColor = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); - } - else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) - { - projVal = terrainElevation(lon, lat, data, out scheme); - baseColor = palette.heightToColor(projVal, scheme, data); - } - mapline[i] = projVal; + stockBiomeColor[i] = SCANUtil.getBiome(body, lon, lat).mapColor; + if (SCANcontroller.controller.biomeBorder) + biomeIndex[i] = SCANUtil.getBiomeIndexFraction(body, lon, lat); + } + else + biomeIndex[i] = SCANUtil.getBiomeIndexFraction(body, lon, lat); + } - if (SCANcontroller.controller.map_ResourceOverlay && SCANconfigLoader.GlobalResource && resource != null) + if (mapstep <= -1) + { + if (resourceOn) + { + for (int i = resourceInterpolation / 2; i >= 1; i /= 2) { - pix[i] = SCANuiUtil.resourceToColor(lon, lat, data, baseColor, resource); + SCANuiUtil.interpolate(resourceCache, 0, resourceMapHeight, resourceMapWidth, i, i, i, r, randomEdges); + SCANuiUtil.interpolate(resourceCache, 0, resourceMapHeight, resourceMapWidth, 0, i, i, r, randomEdges); + SCANuiUtil.interpolate(resourceCache, 0, resourceMapHeight, resourceMapWidth, i, 0, i, r, randomEdges); } - else pix[i] = baseColor; - - /* draw height lines - works, but mostly useless... - int step = (int)(val / 1000); - int step_h = step, step_v = step; - if(i > 0) step_h = (int)(bigline[i - 1] / 1000); - if(bigstep > 0) step_v = (int)(bigline[i] / 1000); - if(step != step_h || step != step_v) { - pix[i] = palette.white; } - */ - //mapline [i] = val; + + mapstep = -1; + mapline = new double[map.width]; + mapstep++; + return map; + } + + for (int i = 0; i < map.width; i++) + { + Color baseColor = palette.grey; + pix[i] = baseColor; + int scheme = SCANcontroller.controller.colours; + float projVal = 0f; + double lat = (mapstep * 1.0f / mapscale) - 90f + lat_offset; + double lon = (i * 1.0f / mapscale) - 180f + lon_offset; + double la = lat, lo = lon; + lat = unprojectLatitude(lo, la); + lon = unprojectLongitude(lo, la); + + if (double.IsNaN(lat) || double.IsNaN(lon) || lat < -90 || lat > 90 || lon < -180 || lon > 180) + { + pix[i] = palette.clear; + continue; } - /* Slope Map */ - else if (mType == mapType.Slope) + switch (mType) { - if (body.pqsController == null) - { - baseColor = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); - } - else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) - { - projVal = terrainElevation(lon, lat, data, out scheme); - if (mapstep == 0) - { - baseColor = palette.grey; - } - else + case mapType.Altimetry: { - // This doesn't actually calculate the slope per se, but it's faster - // than asking for yet more elevation data. Please don't use this - // code to operate nuclear power plants or rockets. - double v1 = mapline[i]; - if (i > 0) - v1 = Math.Max(v1, mapline[i - 1]); - if (i < mapline.Length - 1) - v1 = Math.Max(v1, mapline[i + 1]); - float v = Mathf.Clamp((float)Math.Abs(projVal - v1) / 1000f, 0, 2f); - if (SCANcontroller.controller.colours == 1) + if (!pqs) { - baseColor = palette.lerp(palette.black, palette.white, v / 2f); + baseColor = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); } - else + else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) { - if (v < 1) - { - baseColor = palette.lerp(SCANcontroller.controller.lowSlopeColorOne, SCANcontroller.controller.highSlopeColorOne, v); - } - else - { - baseColor = palette.lerp(SCANcontroller.controller.lowSlopeColorTwo, SCANcontroller.controller.highSlopeColorTwo, v - 1); - } + projVal = terrainElevation(lon, lat, data, out scheme); + baseColor = palette.heightToColor(projVal, scheme, data); } + break; } - mapline[i] = projVal; - } - if (SCANcontroller.controller.map_ResourceOverlay && SCANconfigLoader.GlobalResource && resource != null) - { - pix[i] = SCANuiUtil.resourceToColor(lon, lat, data, baseColor, resource); - } - else pix[i] = baseColor; - } - - /* Biome Map */ - else if (mType == mapType.Biome) - { - if (body.BiomeMap == null) - { - baseColor = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); - } - /* // this just basically stretches the actual biome map to fit... it looks horrible - float u = ((lon + 360 + 180 + 90)) % 360; - float v = ((lat + 180 + 90)) % 180; - if(u < 0 || v < 0 || u >= 360 || v >= 180) continue; - u /= 360f; v /= 180f; - pix[i] = body.BiomeMap.Map.GetPixelBilinear(u, v); - */ - else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Biome)) - { - double bio = SCANUtil.getBiomeIndexFraction(body, lon, lat); - Color biome = palette.grey; - if (SCANcontroller.controller.colours == 1) + case mapType.Slope: { - if ((i > 0 && mapline[i - 1] != bio) || (mapstep > 0 && mapline[i] != bio)) + if (!pqs) { - biome = palette.white; + baseColor = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); } - else + else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) { - biome = palette.lerp(palette.black, palette.white, (float)bio); + projVal = terrainElevation(lon, lat, data, out scheme); + if (mapstep >= 0) + { + // This doesn't actually calculate the slope per se, but it's faster + // than asking for yet more elevation data. Please don't use this + // code to operate nuclear power plants or rockets. + double v1 = mapline[i]; + if (i > 0) + v1 = Math.Max(v1, mapline[i - 1]); + if (i < mapline.Length - 1) + v1 = Math.Max(v1, mapline[i + 1]); + float v = Mathf.Clamp((float)Math.Abs(projVal - v1) / 1000f, 0, 2f); + if (SCANcontroller.controller.colours == 1) + { + baseColor = palette.lerp(palette.black, palette.white, v / 2f); + } + else + { + if (v < 1) + { + baseColor = palette.lerp(SCANcontroller.controller.lowSlopeColorOne, SCANcontroller.controller.highSlopeColorOne, v); + } + else + { + baseColor = palette.lerp(SCANcontroller.controller.lowSlopeColorTwo, SCANcontroller.controller.highSlopeColorTwo, v - 1); + } + } + } + mapline[i] = projVal; } + break; } - else + case mapType.Biome: { - Color elevation = palette.grey; - if (SCANcontroller.controller.biomeTransparency > 0) + if (!biomeMap) { - if (body.pqsController == null) + baseColor = palette.lerp(palette.black, palette.white, UnityEngine.Random.value); + } + else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Biome)) + { + Color biome = palette.grey; + if (SCANcontroller.controller.colours == 1) { - elevation = palette.grey; + if ((i > 0 && mapline[i - 1] != biomeIndex[i]) || (mapstep > 0 && mapline[i] != biomeIndex[i])) + { + biome = palette.white; + } + else + { + biome = palette.lerp(palette.black, palette.white, (float)biomeIndex[i]); + } } - else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) + else { - projVal = terrainElevation(lon, lat, data, out scheme); - elevation = palette.lerp(palette.black, palette.white, Mathf.Clamp(projVal + 1500f, 0, 9000) / 9000f); + Color elevation = palette.grey; + if (SCANcontroller.controller.biomeTransparency > 0) + { + if (!pqs) + { + elevation = palette.grey; + } + else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry)) + { + projVal = terrainElevation(lon, lat, data, out scheme); + elevation = palette.lerp(palette.black, palette.white, Mathf.Clamp(projVal + (-1f * data.TerrainConfig.TerrainRange), 0, data.TerrainConfig.TerrainRange) / data.TerrainConfig.TerrainRange); + } + } + + if (SCANcontroller.controller.biomeBorder && ((i > 0 && mapline[i - 1] != biomeIndex[i]) || (mapstep > 0 && mapline[i] != biomeIndex[i]))) + { + biome = palette.white; + } + else if (SCANcontroller.controller.useStockBiomes) + { + biome = palette.lerp(stockBiomeColor[i], elevation, SCANcontroller.controller.biomeTransparency / 100f); + } + else + { + biome = palette.lerp(palette.lerp(SCANcontroller.controller.lowBiomeColor, SCANcontroller.controller.highBiomeColor, (float)biomeIndex[i]), elevation, SCANcontroller.controller.biomeTransparency / 100f); + } } - } - if ((i > 0 && mapline[i - 1] != bio) || (mapstep > 0 && mapline[i] != bio)) - { - biome = palette.white; - } - else if (SCANcontroller.controller.useStockBiomes) - { - Color c = SCANUtil.getBiome(body, lon, lat).mapColor; - biome = palette.lerp(c, elevation, SCANcontroller.controller.biomeTransparency / 100f); - } - else - { - biome = palette.lerp(palette.lerp(SCANcontroller.controller.lowBiomeColor, SCANcontroller.controller.highBiomeColor, (float)bio), elevation, SCANcontroller.controller.biomeTransparency / 100f); + baseColor = biome; + mapline[i] = biomeIndex[i]; } + break; } + } - baseColor = biome; - mapline[i] = bio; - } - if (SCANcontroller.controller.map_ResourceOverlay && SCANconfigLoader.GlobalResource && resource != null) - { - pix[i] = SCANuiUtil.resourceToColor(lon, lat, data, baseColor, resource); - } - else pix[i] = baseColor; + if (resourceOn) + { + float abundance = 0; + double resourceLat = fixUnscale(unScaleLatitude(lat, resourceMapScale), resourceMapHeight); + double resourceLon = fixUnscale(unScaleLongitude(lon, resourceMapScale), resourceMapWidth); + + //switch (projection) + //{ + // case MapProjection.Polar: + // { + // if ((lat <= 6 && lat >= 0) || (lat >= -6 && lat <=0)) + // { + + // } + // //else if (lat >= 87 || lat <= -87) + // //{ + + // //} + // else + // { + abundance = resourceCache[Mathf.RoundToInt((float)resourceLon), Mathf.RoundToInt((float)resourceLat)]; + // } + // break; + // } + // default: + // { + // if (lat <= -85 || lat >= 85) + // { + + // } + // else + // { + // abundance = resourceCache[Mathf.RoundToInt((float)resourceLon), Mathf.RoundToInt((float)resourceLat)]; + // } + // break; + // } + //} + pix[i] = SCANuiUtil.resourceToColor(baseColor, resource, abundance, data, lon, lat); } + else + pix[i] = baseColor; } - map.SetPixels(0, mapstep, map.width, 1, pix); + + if (mapstep >= 0) + map.SetPixels(0, mapstep, map.width, 1, pix); + mapstep++; + if (mapstep % 10 == 0 || mapstep >= map.height) + { + if (mapstep < map.height - 1) + map.SetPixels(0, mapstep, map.width, 1, palette.redline); + map.Apply(); + } + return map; } diff --git a/SCANsat/SCAN_Map/SCANmapLegend.cs b/SCANsat/SCAN_Map/SCANmapLegend.cs index d338c5f3c..d20dd2952 100644 --- a/SCANsat/SCAN_Map/SCANmapLegend.cs +++ b/SCANsat/SCAN_Map/SCANmapLegend.cs @@ -66,14 +66,14 @@ internal Texture2D getLegend(int scheme, SCANdata data) return t; } - internal Texture2D getLegend(float max, float min, float? clamp, bool discrete, Color32[] c) + internal Texture2D getLegend(float max, float min, float range, float? clamp, bool discrete, Color32[] c) { Texture2D t = new Texture2D(128, 1, TextureFormat.RGB24, false); Color[] pix = t.GetPixels(); for (int x = 0; x < 128; x++) { float val = (x * (max - min)) / 128f + min; - pix[x] = palette.heightToColor(val, max, min, clamp, discrete, c); + pix[x] = palette.heightToColor(val, max, min, range, clamp, discrete, c); } t.SetPixels(pix); t.Apply(); diff --git a/SCANsat/SCAN_PartModules/SCANresourceDisplay.cs b/SCANsat/SCAN_PartModules/SCANresourceDisplay.cs new file mode 100644 index 000000000..7f5d5d721 --- /dev/null +++ b/SCANsat/SCAN_PartModules/SCANresourceDisplay.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SCANsat.SCAN_Data; + + +namespace SCANsat.SCAN_PartModules +{ + class SCANresourceDisplay : PartModule, IAnimatedModule + { + [KSPField] + public int sensorType; + [KSPField(guiActive = true, guiName = "Abundance")] + public string abundanceField; + [KSPField] + public string ResourceName; + [KSPField] + public float MaxAbundanceAltitude; + [KSPField] + public bool RequiresUnlock; + + private float abundanceValue; + + private List stockScanners; + private Dictionary abundanceSummary; + private CelestialBody body; + private bool tooHigh; + private bool fuzzy; + private bool forceStart; + private bool activated; + + public override void OnStart(PartModule.StartState state) + { + if (state == StartState.Editor) + return; + + GameEvents.onVesselSOIChanged.Add(onSOIChange); + + part.force_activate(); + this.enabled = true; + activated = true; + forceStart = true; + + stockScanners = findScanners(); + + setupFields(stockScanners.FirstOrDefault()); + + body = FlightGlobals.currentMainBody; + refreshAbundance(body.flightGlobalsIndex); + } + + private List findScanners() + { + return part.FindModulesImplementing().Where(r => r.ScannerType == 0 && r.ResourceName == ResourceName).ToList(); + } + + private void setupFields(ModuleResourceScanner m) + { + if (m != null) + { + SCANUtil.SCANlog("Resource Display Module set to Max Alt: {0} ; Unlock: {1}", m.MaxAbundanceAltitude, m.RequiresUnlock); + MaxAbundanceAltitude = m.MaxAbundanceAltitude; + RequiresUnlock = m.RequiresUnlock; + } + else + { + MaxAbundanceAltitude = 250000; + RequiresUnlock = true; + } + + Fields["abundanceField"].guiName = string.Format("{0}[Surf]", ResourceName); + } + + private void OnDestroy() + { + GameEvents.onVesselSOIChanged.Remove(onSOIChange); + } + + private void Update() + { + if (!activated) + { + Fields["abundanceField"].guiActive = false; + return; + } + + if (!HighLogic.LoadedSceneIsFlight || !FlightGlobals.ready) + return; + + if (SCANcontroller.controller == null) + return; + + if (forceStart && SCANcontroller.controller != null) + { + if (stockScanners != null && SCANcontroller.controller.disableStockResource) + { + foreach (ModuleResourceScanner m in stockScanners) + { + m.DisableModule(); + } + } + } + + if (!SCANcontroller.controller.disableStockResource) + { + Fields["abundanceField"].guiActive = false; + return; + } + + Fields["abundanceField"].guiActive = true; + + if (tooHigh) + { + abundanceField = "Too High"; + return; + } + else if (abundanceValue < 0) + { + abundanceField = "No Data"; + return; + } + + string biome = "Landed"; + + if (body.BiomeMap != null) + biome = SCANUtil.getBiomeName(body, SCANUtil.fixLonShift(vessel.longitude), SCANUtil.fixLatShift(vessel.latitude)); + + if (checkBiome(biome) || !SCANcontroller.controller.resourceBiomeLock) + { + if (fuzzy) + abundanceField = abundanceValue.ToString("P0"); + else + abundanceField = abundanceValue.ToString("P2"); + } + else + { + float biomeAbundance = abundanceSummary.ContainsKey(biome) ? abundanceSummary[biome].Abundance : 0f; + if (fuzzy) + abundanceField = biomeAbundance.ToString("P0"); + else + abundanceField = biomeAbundance.ToString("P2"); + } + } + + private bool checkBiome (string b) + { + return ResourceMap.Instance.IsBiomeUnlocked(body.flightGlobalsIndex, b); + } + + private void FixedUpdate() + { + if (!activated) + { + abundanceValue = -1f; + return; + } + + if (vessel.altitude > MaxAbundanceAltitude) + { + tooHigh = true; + return; + } + + tooHigh = false; + double lat = SCANUtil.fixLatShift(vessel.latitude); + double lon = SCANUtil.fixLonShift(vessel.longitude); + if (SCANUtil.isCovered(lon, lat, vessel.mainBody, sensorType)) + { + abundanceValue = SCANUtil.ResourceOverlay(lat, lon, ResourceName, vessel.mainBody, RequiresUnlock && SCANcontroller.controller.resourceBiomeLock); + fuzzy = false; + } + else if (SCANUtil.isCovered(lon, lat, vessel.mainBody, 524288)) + { + abundanceValue = SCANUtil.ResourceOverlay(lat, lon, ResourceName, vessel.mainBody, RequiresUnlock && SCANcontroller.controller.resourceBiomeLock); + fuzzy = true; + } + else + { + abundanceValue = -1; + } + } + + private void onSOIChange(GameEvents.HostedFromToAction VB) + { + body = VB.to; + refreshAbundance(body.flightGlobalsIndex); + } + + private void refreshAbundance(int bodyID) + { + abundanceSummary = new Dictionary(); + + abundanceSummary = ResourceCache.Instance.AbundanceCache. + Where(a => a.ResourceName == ResourceName && a.HarvestType == HarvestTypes.Planetary && a.BodyId == bodyID). + ToDictionary(a => a.BiomeName, a => a); + } + + public void EnableModule() + { + activated = true; + if (stockScanners != null && SCANcontroller.controller != null && SCANcontroller.controller.disableStockResource) + { + foreach (ModuleResourceScanner m in stockScanners) + { + m.DisableModule(); + } + } + } + + public void DisableModule() + { + activated = false; + if (stockScanners != null && SCANcontroller.controller != null && SCANcontroller.controller.disableStockResource) + { + foreach (ModuleResourceScanner m in stockScanners) + { + m.DisableModule(); + } + } + } + + public bool ModuleIsActive() + { + return activated; + } + + public bool IsSituationValid() + { + return true; + } + } +} diff --git a/SCANsat/SCAN_PartModules/SCANresourceScanner.cs b/SCANsat/SCAN_PartModules/SCANresourceScanner.cs new file mode 100644 index 000000000..5010b4540 --- /dev/null +++ b/SCANsat/SCAN_PartModules/SCANresourceScanner.cs @@ -0,0 +1,219 @@ +#region license +/* [Scientific Committee on Advanced Navigation] + * S.C.A.N. Satellite + * + * SCANresourceScanner - Resource scanner part module + * + * Copyright (c)2013 damny; + * Copyright (c)2014 technogeeky ; + * Copyright (c)2014 DMagic + * Copyright (c)2014 (Your Name Here) ; see LICENSE.txt for licensing details. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using SCANsat.SCAN_Data; + +namespace SCANsat.SCAN_PartModules +{ + public class ModuleSCANresourceScanner : SCANsat, IAnimatedModule + { + private List mSurvey; + private List mScanner; + private ModuleAnimationGroup animGroup; + private bool activated; + private bool forceStart; + + public override void OnStart(PartModule.StartState state) + { + base.OnStart(state); + + Actions["startScanAction"].active = false; + Actions["stopScanAction"].active = false; + Actions["toggleScanAction"].active = false; + Actions["startResourceScanAction"].guiName = "Start " + scanName; + Actions["stopResourceScanAction"].guiName = "Stop " + scanName; + Actions["toggleResourceScanAction"].guiName = "Toggle " + scanName; + + if (state == StartState.Editor) + return; + + mSurvey = findSurvey(); + mScanner = findScanner(); + animGroup = findAnimator(); + + if (animGroup == null) + activated = true; + + forceStart = true; + } + + public override string GetInfo() + { + string info = base.GetInfo(); + info += "Resource Scan: " + (SCANtype)sensorType + "\n"; + + return info; + } + + private List findScanner() + { + return part.FindModulesImplementing(); + } + + private List findSurvey() + { + return part.FindModulesImplementing(); + } + + private ModuleAnimationGroup findAnimator() + { + return part.FindModulesImplementing().FirstOrDefault(); + } + + private void updateEvents() + { + base.Events["startScan"].active = !scanning; + base.Events["stopScan"].active = scanning; + } + + public void Update() + { + base.OnUpdate(); + + if (!activated) + { + base.Events["startScan"].active = false; + base.Events["stopScan"].active = false; + if (scanning) + unregisterScanner(); + return; + } + + if (!HighLogic.LoadedSceneIsFlight) + return; + + if (!FlightGlobals.ready) + return; + + if (forceStart && SCANcontroller.controller != null) + { + if (SCANcontroller.controller.disableStockResource) + { + if (mSurvey != null) + { + foreach (ModuleOrbitalSurveyor m in mSurvey) + m.DisableModule(); + } + + if (mScanner != null) + { + foreach (ModuleOrbitalScanner m in mScanner) + m.DisableModule(); + } + } + forceStart = false; + } + + if (SCANcontroller.controller == null) + return; + + if (!SCANcontroller.controller.easyModeScanning || SCANcontroller.controller.disableStockResource) + updateEvents(); + else + { + base.Events["startScan"].active = false; + base.Events["stopScan"].active = false; + if (scanning) + unregisterScanner(); + } + } + + [KSPAction("Start Resource Scan")] + public void startResourceScanAction(KSPActionParam param) + { + if (!SCANcontroller.controller.easyModeScanning || SCANcontroller.controller.disableStockResource) + { + if (animGroup != null && !scanning && !animGroup.isDeployed) + animGroup.DeployModule(); + startScan(); + } + } + + [KSPAction("Stop Resource Scan")] + public void stopResourceScanAction(KSPActionParam param) + { + stopScan(); + } + + [KSPAction("Toggle Resource Scan")] + public void toggleResourceScanAction(KSPActionParam param) + { + if (scanning) + stopScan(); + else + { + if (!SCANcontroller.controller.easyModeScanning || SCANcontroller.controller.disableStockResource) + { + if (animGroup != null && !animGroup.isDeployed) + animGroup.DeployModule(); + startScan(); + } + } + } + + public void DisableModule() + { + activated = false; + base.Events["startScan"].active = false; + base.Events["stopScan"].active = false; + if (scanning) + unregisterScanner(); + + if (SCANcontroller.controller != null && SCANcontroller.controller.disableStockResource) + { + if (mSurvey != null) + { + foreach (ModuleOrbitalSurveyor m in mSurvey) + m.DisableModule(); + } + + if (mScanner != null) + { + foreach (ModuleOrbitalScanner m in mScanner) + m.DisableModule(); + } + } + } + + public void EnableModule() + { + activated = true; + if (SCANcontroller.controller != null && SCANcontroller.controller.disableStockResource) + { + if (mSurvey != null) + { + foreach (ModuleOrbitalSurveyor m in mSurvey) + m.DisableModule(); + } + + if (mScanner != null) + { + foreach (ModuleOrbitalScanner m in mScanner) + m.DisableModule(); + } + } + } + + public bool IsSituationValid() + { + return true; + } + + public bool ModuleIsActive() + { + return activated; + } + } +} diff --git a/SCANsat/SCANsat.cs b/SCANsat/SCAN_PartModules/SCANsat.cs similarity index 89% rename from SCANsat/SCANsat.cs rename to SCANsat/SCAN_PartModules/SCANsat.cs index 6663d5dee..760a4dcca 100644 --- a/SCANsat/SCANsat.cs +++ b/SCANsat/SCAN_PartModules/SCANsat.cs @@ -1,567 +1,570 @@ -#region license -/* [Scientific Committee on Advanced Navigation] - * S.C.A.N. Satellite - * - * SCANsat - SCAN RADAR Altimetry Sensor part (& More) - * - * Copyright (c)2013 damny; - * Copyright (c)2014 technogeeky ; - * Copyright (c)2014 (Your Name Here) ; see LICENSE.txt for licensing details. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using SCANsat.SCAN_Data; -using SCANsat.SCAN_Toolbar; -using SCANsat.SCAN_UI; - -using UnityEngine; -using palette = SCANsat.SCAN_UI.UI_Framework.SCANpalette; - -namespace SCANsat -{ - public class SCANsat : PartModule, IScienceDataContainer - { - private bool powerIsProblem; - private Animation anim = null; - private List storedData = new List(); - private ExperimentsResultDialog expDialog = null; - - /* SAT: KSP entry points */ - public override void OnStart(StartState state) - { - if (state == StartState.Editor) - { - print("[SCANsat] start: in editor"); - Events["editorExtend"].active = !string.IsNullOrEmpty(animationName); - } - else - { - print("[SCANsat] start: live"); - } - if (!string.IsNullOrEmpty(animationName)) - { - Animation[] a = part.FindModelAnimators(animationName); - if (a.Length == 0) - { - print("[SCANsat] animation '" + animationName + "' not found"); - } - else - { - print("[SCANsat] using animation #1 out of " + a.Length.ToString() + " animations named '" + animationName + "'"); - anim = a[0]; - } - } - if (scanName != null) - { // Use bitwise operators to check if the part has valid science collection scanners - if ((sensorType & (Int32)SCANtype.AltimetryLoRes) == 0 && (sensorType & (Int32)SCANtype.AltimetryHiRes) == 0 && (sensorType & (Int32)SCANtype.Biome) == 0) - { - Events["startScan"].guiName = "Start " + scanName; - Events["stopScan"].guiName = "Stop " + scanName; - Events["analyze"].active = false; - Actions["startScanAction"].guiName = "Start " + scanName; - Actions["stopScanAction"].guiName = "Stop " + scanName; - Actions["toggleScanAction"].guiName = "Toggle " + scanName; - Actions["analyzeData"].active = false; - } - else - { - Events["startScan"].guiName = "Start " + scanName; - Events["stopScan"].guiName = "Stop " + scanName; - Events["analyze"].active = true; - Actions["startScanAction"].guiName = "Start " + scanName; - Actions["stopScanAction"].guiName = "Stop " + scanName; - Actions["toggleScanAction"].guiName = "Toggle " + scanName; - } - } - - if (sensorType == 0) - { - // here, we override all event and action labels - // and we also disable the analyze button (it does nothing) - Events["startScan"].active = false; - Events["stopScan"].active = false; - Events["analyze"].active = false; - Events["editorExtend"].active = false; - Actions["startScanAction"].active = false; - Actions["stopScanAction"].active = false; - Actions["toggleScanAction"].active = false; - Actions["analyzeData"].active = false; - } - else if (sensorType == 32) - { - // here, we only disable analyze; BTDT has good labels - Events["analyze"].active = false; - Actions["analyzeData"].active = false; - } - if (scanning) animate(1, 1); - powerIsProblem = false; - print("[SCANsat] sensorType: " + sensorType.ToString() + " fov: " + fov.ToString() + " min_alt: " + min_alt.ToString() + " max_alt: " + max_alt.ToString() + " best_alt: " + best_alt.ToString() + " power: " + power.ToString()); - } - - public override void OnUpdate() - { - if (sensorType != 0) - { - Events["reviewEvent"].active = storedData.Count > 0; - Events["EVACollect"].active = storedData.Count > 0; - Events["startScan"].active = !scanning; - Events["stopScan"].active = scanning; - if (sensorType != 32) - Fields["alt_indicator"].guiActive = scanning; - if (scanning) - { - if (SCANcontroller.controller == null) - { - scanning = false; - Debug.LogError("[SCANsat] Warning: SCANsat scenario module not initialized; Shutting down"); - } - else - { - if (sensorType != 0 || SCANcontroller.controller.isVesselKnown(vessel.id, (SCANtype)sensorType)) - { - if (TimeWarp.CurrentRate < 1500) - { - float p = power * TimeWarp.deltaTime; - float e = part.RequestResource("ElectricCharge", p); - if (e < p) - { - unregisterScanner(); - powerIsProblem = true; - } - else - { - registerScanner(); - powerIsProblem = false; - } - } - else if (powerIsProblem) - { - registerScanner(); - powerIsProblem = false; - } - } - else - unregisterScanner(); - alt_indicator = scanAlt(); - } - } - if (vessel == FlightGlobals.ActiveVessel) - { - if (powerIsProblem) - { - addStatic(); - registerScanner(); - } - } - } - } - - public override void OnLoad(ConfigNode node) - { - if (node.HasNode("ScienceData")) - { - foreach (ConfigNode storedDataNode in node.GetNodes("ScienceData")) - { - ScienceData data = new ScienceData(storedDataNode); - storedData.Add(data); - } - } - if (node.HasNode("SCANsatRPM")) - { - ConfigNode RPMPersistence = node.GetNode("SCANsatRPM"); - 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)); - } - } - } - - public override void OnSave(ConfigNode node) - { - node.RemoveNodes("ScienceData"); //** Prevent duplicates - foreach (ScienceData SCANData in storedData) - { - ConfigNode storedDataNode = node.AddNode("ScienceData"); - SCANData.Save(storedDataNode); - } - if (RPMList.Count > 0) - { - ConfigNode RPMPersistence = new ConfigNode("SCANsatRPM"); - foreach (RPMPersistence RPMMFD in RPMList) - { - ConfigNode RPMProp = new ConfigNode("Prop"); - RPMProp.AddValue("Prop ID", RPMMFD.RPMID); - RPMProp.AddValue("Mode", RPMMFD.RPMMode); - RPMProp.AddValue("Color", RPMMFD.RPMColor); - RPMProp.AddValue("Zoom", RPMMFD.RPMZoom); - RPMProp.AddValue("Lines", RPMMFD.RPMLines); - RPMPersistence.AddNode(RPMProp); - } - node.AddNode(RPMPersistence); - } - } - - public override string GetInfo() - { - string str = base.GetInfo(); - if (min_alt != 0) - { - str += "Altitude ( min): " + (min_alt / 1000).ToString("F0") + " km\n"; - } - if (best_alt != min_alt) - { - str += "Altitude (best): " + (best_alt / 1000).ToString("F0") + " km\n"; - } - if (max_alt != 0) - { - str += "Altitude ( max): " + (max_alt / 1000).ToString("F0") + " km\n"; - } - if (fov != 0) - { - str += "FOV: " + fov.ToString("F0") + " °\n"; - } - str += "Power usage: " + power.ToString("F1") + " charge/s\n"; - return str; - } - - /* SAT: KSP fields */ - [KSPField] - public int sensorType; - [KSPField] - public float fov; - [KSPField] - public float min_alt; - [KSPField] - public float max_alt; - [KSPField] - public float best_alt; - [KSPField] - public float power; - [KSPField] - public string scanName; - [KSPField] - public string animationName; - [KSPField(guiName = "SCANsat Altitude", guiActive = false)] - public string alt_indicator; - internal List RPMList = new List(); - - /* SCAN: all of these fields and only scanning is persistant */ - [KSPField(isPersistant = true)] - protected bool scanning = false; - public bool scanningNow() { return scanning; } - - /* SCAN: context (right click) buttons in FLIGHT */ - [KSPEvent(guiActive = true, guiName = "Start RADAR Scan", active = true)] - public void startScan() - { - if (!ToolbarManager.ToolbarAvailable && SCANcontroller.controller != null) - { - if (!SCANcontroller.controller.useStockAppLauncher) - SCANcontroller.controller.mainMap.Visible = true; - } - registerScanner(); - animate(1, 0); - } - - [KSPEvent(guiActive = true, guiName = "Stop RADAR Scan", active = true)] - public void stopScan() - { - unregisterScanner(); - powerIsProblem = false; - animate(-1, 1); - } - - [KSPEvent(guiActive = true, guiName = "Analyze Data", active = true)] - public void analyze() - { - makeScienceData(true); - ReviewData(); - } - - [KSPEvent(guiActive = true, guiName = "Review Data", active = false)] - public void reviewEvent() - { - ReviewData(); - } - - [KSPEvent(guiActiveUnfocused = true, guiName = "Collect Stored Data", externalToEVAOnly = true, unfocusedRange = 1.5f, active = false)] - public void EVACollect() - { - List EVACont = FlightGlobals.ActiveVessel.FindPartModulesImplementing(); - if (storedData.Count > 0) - { - if (EVACont.First().StoreData(new List() { this }, false)) - { - foreach (ScienceData data in storedData) - DumpData(data); - } - } - } - - /* SCAN: context (right click) buttons in EDTIOR */ - [KSPEvent(guiActiveEditor = true, guiName = "Extend", active = true)] - public void editorExtend() - { - Events["editorExtend"].active = false; - Events["editorRetract"].active = true; - animate(1, 0); - } - - [KSPEvent(guiActiveEditor = true, guiName = "Retract", active = false)] - public void editorRetract() - { - Events["editorExtend"].active = true; - Events["editorRetract"].active = false; - animate(-1, 1); - } - - /* SCAN: trivial function to do animation */ - private void animate(float speed, float time) - { - if (anim != null && anim[animationName] != null) - { - anim[animationName].speed = speed; - if (anim.IsPlaying(animationName)) - { - if (anim[animationName].normalizedTime <= 0) - { - anim[animationName].normalizedTime = time; - } - else if (anim[animationName].normalizedTime >= 1 - float.Epsilon) - { - anim[animationName].normalizedTime = time; - } - } - else - { - anim[animationName].wrapMode = WrapMode.ClampForever; - anim[animationName].normalizedTime = time; - anim.Play(animationName); - } - } - } - - /* SCAN: actions for ... something ... */ - [KSPAction("Start Scan")] - public void startScanAction(KSPActionParam param) - { - startScan(); - } - - [KSPAction("Stop Scan")] - public void stopScanAction(KSPActionParam param) - { - stopScan(); - } - - [KSPAction("Toggle Scan")] - public void toggleScanAction(KSPActionParam param) - { - if (scanning) - stopScan(); - else - startScan(); - } - - [KSPAction("Analyze Data")] - public void analyzeData(KSPActionParam param) - { - //if (scanning) ** Always available - analyze(); - } - - /* SCAN: add static (a warning that we're low on electric charge) */ - private void addStatic() - { - SCANdata data = SCANUtil.getData(vessel.mainBody); - if (data == null) - return; - Texture2D map = data.Map; - if (map != null) - { - 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)); - } - } - } - - /* SCAN: register scanners without going through animation */ - private void registerScanner() - { - scanning = true; - if (sensorType > 0 && SCANcontroller.controller != null) - SCANcontroller.controller.registerSensor(vessel, (SCANtype)sensorType, fov, min_alt, max_alt, best_alt); - } - - protected void unregisterScanner() - { - scanning = false; - if (sensorType > 0 && SCANcontroller.controller != null) - SCANcontroller.controller.unregisterSensor(vessel, (SCANtype)sensorType); - } - - private string scanAlt() - { - string altitude = "Unknown"; - if (vessel.altitude < min_alt) - altitude = "Too low"; - else if (vessel.altitude < best_alt) - altitude = "Sub-optimal"; - else if (vessel.altitude >= best_alt && vessel.altitude <= max_alt) - altitude = "Ideal"; - else if (vessel.altitude > max_alt) - altitude = "Too high"; - return altitude; - } - - /* SCAN: SCIENCE! make, store, transmit, keep - * discard, review, count DATA */ - private void makeScienceData(bool notZero) - { - if (expDialog != null) - DestroyImmediate(expDialog); - storedData.Clear(); - ScienceData sd = getAvailableScience((SCANtype)sensorType, notZero); - if (sd == null) - return; - storedData.Add(sd); - } - - private ScienceData getAvailableScience(SCANtype sensor, bool notZero) - { - SCANdata data = SCANUtil.getData(vessel.mainBody); - if (data == null) - return null; - ScienceData sd = null; - ScienceExperiment se = null; - ScienceSubject su = null; - bool found = false; - string id = null; - double coverage = 0f; - float multiplier = 1f; - - if (!found && (sensor & SCANtype.AltimetryLoRes) != SCANtype.Nothing) - { - found = true; - if (vessel.mainBody.pqsController == null) - multiplier = 0.5f; - id = "SCANsatAltimetryLoRes"; - coverage = SCANUtil.getCoveragePercentage(data, SCANtype.AltimetryLoRes); - } - else if (!found && (sensor & SCANtype.AltimetryHiRes) != SCANtype.Nothing) - { - found = true; - if (vessel.mainBody.pqsController == null) - multiplier = 0.5f; - id = "SCANsatAltimetryHiRes"; - coverage = SCANUtil.getCoveragePercentage(data, SCANtype.AltimetryHiRes); - } - else if (!found && (sensor & SCANtype.Biome) != SCANtype.Nothing) - { - found = true; - if (vessel.mainBody.BiomeMap == null) - multiplier = 0.5f; - id = "SCANsatBiomeAnomaly"; - coverage = SCANUtil.getCoveragePercentage(data, SCANtype.Biome); - } - if (!found) return null; - se = ResearchAndDevelopment.GetExperiment(id); - if (se == null) return null; - - su = ResearchAndDevelopment.GetExperimentSubject(se, ExperimentSituations.InSpaceHigh, vessel.mainBody, "surface"); - if (su == null) return null; - - su.scienceCap *= multiplier; - - SCANUtil.SCANlog("Coverage: {0}, Science cap: {1}, Subject value: {2}, Scientific value: {3}, Science: {4}", new object[5] { coverage.ToString("F1"), su.scienceCap.ToString("F1"), su.subjectValue.ToString("F2"), su.scientificValue.ToString("F2"), su.science.ToString("F2") }); - - su.scientificValue = 1; - - float science = (float)coverage; - if (science > 95) science = 100; - if (science < 30) science = 0; - science = science / 100f; - science = Mathf.Max(0, (science * su.scienceCap) - su.science); - - SCANUtil.SCANlog("Remaining science: {0}, Base value: {1}", new object[2] { science.ToString("F1"), se.baseValue.ToString("F1") }); - - science /= Mathf.Max(0.1f, su.scientificValue); //look 10 lines up; this is always 1... - science /= su.subjectValue; - - SCANUtil.SCANlog("Resulting science value: {0}", new object[1] { science.ToString("F2") }); - - if (notZero && science <= 0) science = 0.00001f; - - sd = new ScienceData(science * su.dataScale, 1f, 0f, su.id, se.experimentTitle + " of " + vessel.mainBody.theName); - su.title = sd.title; - return sd; - } - - public ScienceData[] GetData() - { - return storedData.ToArray(); - } - - private void KeepData(ScienceData data) - { - expDialog = null; - } - - private void TransmitData(ScienceData data) - { - expDialog = null; - List tranList = vessel.FindPartModulesImplementing(); - if (tranList.Count > 0 && storedData.Count > 0) - { - makeScienceData(false); - tranList.OrderBy(ScienceUtil.GetTransmitterScore).First().TransmitData(storedData); - DumpData(storedData[0]); - } - else ScreenMessages.PostScreenMessage("No transmitters available on this vessel.", 4f, ScreenMessageStyle.UPPER_LEFT); - } - - public void DumpData(ScienceData data) - { - expDialog = null; - while (storedData.Contains(data)) - { - storedData.Remove(data); - } - } - - public void ReviewDataItem(ScienceData sd) - { - ReviewData(); - } - - public void ReviewData() - { - if (storedData.Count < 1) - return; - if (expDialog != null) - DestroyImmediate(expDialog); - ScienceData sd = storedData[0]; - expDialog = ExperimentsResultDialog.DisplayResult(new ExperimentResultDialogPage(part, sd, 1f, 0f, false, "", true, false, DumpData, KeepData, TransmitData, null)); - } - - public bool IsRerunnable() - { - return true; - } - - public int GetScienceCount() - { - return storedData.Count; - } - } -} - +#region license +/* [Scientific Committee on Advanced Navigation] + * S.C.A.N. Satellite + * + * SCANsat - SCAN RADAR Altimetry Sensor part (& More) + * + * Copyright (c)2013 damny; + * Copyright (c)2014 technogeeky ; + * Copyright (c)2014 (Your Name Here) ; see LICENSE.txt for licensing details. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using SCANsat.SCAN_Data; +using SCANsat.SCAN_Toolbar; +using SCANsat.SCAN_UI; + +using UnityEngine; +using palette = SCANsat.SCAN_UI.UI_Framework.SCANpalette; + +namespace SCANsat.SCAN_PartModules +{ + public class SCANsat : PartModule, IScienceDataContainer + { + private bool powerIsProblem; + private Animation anim = null; + private List storedData = new List(); + private ExperimentsResultDialog expDialog = null; + + /* SAT: KSP entry points */ + public override void OnStart(StartState state) + { + if (state == StartState.Editor) + { + print("[SCANsat] start: in editor"); + Events["editorExtend"].active = !string.IsNullOrEmpty(animationName); + } + else + { + print("[SCANsat] start: live"); + } + if (!string.IsNullOrEmpty(animationName)) + { + Animation[] a = part.FindModelAnimators(animationName); + if (a.Length == 0) + { + print("[SCANsat] animation '" + animationName + "' not found"); + } + else + { + print("[SCANsat] using animation #1 out of " + a.Length.ToString() + " animations named '" + animationName + "'"); + anim = a[0]; + } + } + if (scanName != null) + { // Use bitwise operators to check if the part has valid science collection scanners + if ((sensorType & (Int32)SCANtype.AltimetryLoRes) == 0 && (sensorType & (Int32)SCANtype.AltimetryHiRes) == 0 && (sensorType & (Int32)SCANtype.Biome) == 0) + { + Events["startScan"].guiName = "Start " + scanName; + Events["stopScan"].guiName = "Stop " + scanName; + Events["analyze"].active = false; + Actions["startScanAction"].guiName = "Start " + scanName; + Actions["stopScanAction"].guiName = "Stop " + scanName; + Actions["toggleScanAction"].guiName = "Toggle " + scanName; + Actions["analyzeData"].active = false; + } + else + { + Events["startScan"].guiName = "Start " + scanName; + Events["stopScan"].guiName = "Stop " + scanName; + Events["analyze"].active = true; + Actions["startScanAction"].guiName = "Start " + scanName; + Actions["stopScanAction"].guiName = "Stop " + scanName; + Actions["toggleScanAction"].guiName = "Toggle " + scanName; + } + } + + if (sensorType == 0) + { + // here, we override all event and action labels + // and we also disable the analyze button (it does nothing) + Events["startScan"].active = false; + Events["stopScan"].active = false; + Events["analyze"].active = false; + Events["editorExtend"].active = false; + Actions["startScanAction"].active = false; + Actions["stopScanAction"].active = false; + Actions["toggleScanAction"].active = false; + Actions["analyzeData"].active = false; + } + else if (sensorType == 32) + { + // here, we only disable analyze; BTDT has good labels + Events["analyze"].active = false; + Actions["analyzeData"].active = false; + } + if (scanning) animate(1, 1); + powerIsProblem = false; + print("[SCANsat] sensorType: " + sensorType.ToString() + " fov: " + fov.ToString() + " min_alt: " + min_alt.ToString() + " max_alt: " + max_alt.ToString() + " best_alt: " + best_alt.ToString() + " power: " + power.ToString()); + } + + public override void OnUpdate() + { + if (sensorType == 0) + return; + + Events["reviewEvent"].active = storedData.Count > 0; + Events["EVACollect"].active = storedData.Count > 0; + Events["startScan"].active = !scanning; + Events["stopScan"].active = scanning; + if (sensorType != 32) + Fields["alt_indicator"].guiActive = scanning; + if (scanning) + { + if (SCANcontroller.controller == null) + { + scanning = false; + Debug.LogError("[SCANsat] Warning: SCANsat scenario module not initialized; Shutting down"); + } + else + { + if (sensorType != 0 || SCANcontroller.controller.isVesselKnown(vessel.id, (SCANtype)sensorType)) + { + if (TimeWarp.CurrentRate < 1500) + { + float p = power * TimeWarp.deltaTime; + float e = part.RequestResource("ElectricCharge", p); + if (e < p) + { + unregisterScanner(); + powerIsProblem = true; + } + else + { + registerScanner(); + powerIsProblem = false; + } + } + else if (powerIsProblem) + { + registerScanner(); + powerIsProblem = false; + } + } + else + unregisterScanner(); + alt_indicator = scanAlt(); + } + } + if (vessel == FlightGlobals.ActiveVessel) + { + if (powerIsProblem) + { + addStatic(); + registerScanner(); + } + } + } + + public override void OnLoad(ConfigNode node) + { + if (node.HasNode("ScienceData")) + { + foreach (ConfigNode storedDataNode in node.GetNodes("ScienceData")) + { + ScienceData data = new ScienceData(storedDataNode); + storedData.Add(data); + } + } + if (node.HasNode("SCANsatRPM")) + { + ConfigNode RPMPersistence = node.GetNode("SCANsatRPM"); + 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)); + } + } + } + + public override void OnSave(ConfigNode node) + { + node.RemoveNodes("ScienceData"); //** Prevent duplicates + foreach (ScienceData SCANData in storedData) + { + ConfigNode storedDataNode = node.AddNode("ScienceData"); + SCANData.Save(storedDataNode); + } + if (RPMList.Count > 0) + { + ConfigNode RPMPersistence = new ConfigNode("SCANsatRPM"); + foreach (RPMPersistence RPMMFD in RPMList) + { + ConfigNode RPMProp = new ConfigNode("Prop"); + RPMProp.AddValue("Prop ID", RPMMFD.RPMID); + RPMProp.AddValue("Mode", RPMMFD.RPMMode); + RPMProp.AddValue("Color", RPMMFD.RPMColor); + RPMProp.AddValue("Zoom", RPMMFD.RPMZoom); + RPMProp.AddValue("Lines", RPMMFD.RPMLines); + RPMPersistence.AddNode(RPMProp); + } + node.AddNode(RPMPersistence); + } + } + + public override string GetInfo() + { + if (sensorType == 0) + return ""; + + string str = base.GetInfo(); + if (min_alt != 0) + { + str += "Altitude ( min): " + (min_alt / 1000).ToString("F0") + " km\n"; + } + if (best_alt != min_alt) + { + str += "Altitude (best): " + (best_alt / 1000).ToString("F0") + " km\n"; + } + if (max_alt != 0) + { + str += "Altitude ( max): " + (max_alt / 1000).ToString("F0") + " km\n"; + } + if (fov != 0) + { + str += "FOV: " + fov.ToString("F0") + " °\n"; + } + str += "Power usage: " + power.ToString("F1") + " charge/s\n"; + return str; + } + + /* SAT: KSP fields */ + [KSPField] + public int sensorType; + [KSPField] + public float fov; + [KSPField] + public float min_alt; + [KSPField] + public float max_alt; + [KSPField] + public float best_alt; + [KSPField] + public float power; + [KSPField] + public string scanName; + [KSPField] + public string animationName; + [KSPField(guiName = "SCANsat Altitude", guiActive = false)] + public string alt_indicator; + internal List RPMList = new List(); + + /* SCAN: all of these fields and only scanning is persistant */ + [KSPField(isPersistant = true)] + protected bool scanning = false; + public bool scanningNow() { return scanning; } + + /* SCAN: context (right click) buttons in FLIGHT */ + [KSPEvent(guiActive = true, guiName = "Start RADAR Scan", active = true)] + public void startScan() + { + if (!ToolbarManager.ToolbarAvailable && SCANcontroller.controller != null) + { + if (!SCANcontroller.controller.useStockAppLauncher) + SCANcontroller.controller.mainMap.Visible = true; + } + registerScanner(); + animate(1, 0); + } + + [KSPEvent(guiActive = true, guiName = "Stop RADAR Scan", active = true)] + public void stopScan() + { + unregisterScanner(); + powerIsProblem = false; + animate(-1, 1); + } + + [KSPEvent(guiActive = true, guiName = "Analyze Data", active = true)] + public void analyze() + { + makeScienceData(true); + ReviewData(); + } + + [KSPEvent(guiActive = true, guiName = "Review Data", active = false)] + public void reviewEvent() + { + ReviewData(); + } + + [KSPEvent(guiActiveUnfocused = true, guiName = "Collect Stored Data", externalToEVAOnly = true, unfocusedRange = 1.5f, active = false)] + public void EVACollect() + { + List EVACont = FlightGlobals.ActiveVessel.FindPartModulesImplementing(); + if (storedData.Count > 0) + { + if (EVACont.First().StoreData(new List() { this }, false)) + { + foreach (ScienceData data in storedData) + DumpData(data); + } + } + } + + /* SCAN: context (right click) buttons in EDTIOR */ + [KSPEvent(guiActiveEditor = true, guiName = "Extend", active = true)] + public void editorExtend() + { + Events["editorExtend"].active = false; + Events["editorRetract"].active = true; + animate(1, 0); + } + + [KSPEvent(guiActiveEditor = true, guiName = "Retract", active = false)] + public void editorRetract() + { + Events["editorExtend"].active = true; + Events["editorRetract"].active = false; + animate(-1, 1); + } + + /* SCAN: trivial function to do animation */ + private void animate(float speed, float time) + { + if (anim != null && anim[animationName] != null) + { + anim[animationName].speed = speed; + if (anim.IsPlaying(animationName)) + { + if (anim[animationName].normalizedTime <= 0) + { + anim[animationName].normalizedTime = time; + } + else if (anim[animationName].normalizedTime >= 1 - float.Epsilon) + { + anim[animationName].normalizedTime = time; + } + } + else + { + anim[animationName].wrapMode = WrapMode.ClampForever; + anim[animationName].normalizedTime = time; + anim.Play(animationName); + } + } + } + + /* SCAN: actions for ... something ... */ + [KSPAction("Start Scan")] + public void startScanAction(KSPActionParam param) + { + startScan(); + } + + [KSPAction("Stop Scan")] + public void stopScanAction(KSPActionParam param) + { + stopScan(); + } + + [KSPAction("Toggle Scan")] + public void toggleScanAction(KSPActionParam param) + { + if (scanning) + stopScan(); + else + startScan(); + } + + [KSPAction("Analyze Data")] + public void analyzeData(KSPActionParam param) + { + //if (scanning) ** Always available + analyze(); + } + + /* SCAN: add static (a warning that we're low on electric charge) */ + private void addStatic() + { + SCANdata data = SCANUtil.getData(vessel.mainBody); + if (data == null) + return; + Texture2D map = data.Map; + if (map != null) + { + 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)); + } + } + } + + /* SCAN: register scanners without going through animation */ + private void registerScanner() + { + scanning = true; + if (sensorType > 0 && SCANcontroller.controller != null) + SCANcontroller.controller.registerSensor(vessel, (SCANtype)sensorType, fov, min_alt, max_alt, best_alt); + } + + protected void unregisterScanner() + { + scanning = false; + if (sensorType > 0 && SCANcontroller.controller != null) + SCANcontroller.controller.unregisterSensor(vessel, (SCANtype)sensorType); + } + + private string scanAlt() + { + string altitude = "Unknown"; + if (vessel.altitude < min_alt) + altitude = "Too low"; + else if (vessel.altitude < best_alt) + altitude = "Sub-optimal"; + else if (vessel.altitude >= best_alt && vessel.altitude <= max_alt) + altitude = "Ideal"; + else if (vessel.altitude > max_alt) + altitude = "Too high"; + return altitude; + } + + /* SCAN: SCIENCE! make, store, transmit, keep + * discard, review, count DATA */ + private void makeScienceData(bool notZero) + { + if (expDialog != null) + DestroyImmediate(expDialog); + storedData.Clear(); + ScienceData sd = getAvailableScience((SCANtype)sensorType, notZero); + if (sd == null) + return; + storedData.Add(sd); + } + + private ScienceData getAvailableScience(SCANtype sensor, bool notZero) + { + SCANdata data = SCANUtil.getData(vessel.mainBody); + if (data == null) + return null; + ScienceData sd = null; + ScienceExperiment se = null; + ScienceSubject su = null; + bool found = false; + string id = null; + double coverage = 0f; + float multiplier = 1f; + + if (!found && (sensor & SCANtype.AltimetryLoRes) != SCANtype.Nothing) + { + found = true; + if (vessel.mainBody.pqsController == null) + multiplier = 0.5f; + id = "SCANsatAltimetryLoRes"; + coverage = SCANUtil.getCoveragePercentage(data, SCANtype.AltimetryLoRes); + } + else if (!found && (sensor & SCANtype.AltimetryHiRes) != SCANtype.Nothing) + { + found = true; + if (vessel.mainBody.pqsController == null) + multiplier = 0.5f; + id = "SCANsatAltimetryHiRes"; + coverage = SCANUtil.getCoveragePercentage(data, SCANtype.AltimetryHiRes); + } + else if (!found && (sensor & SCANtype.Biome) != SCANtype.Nothing) + { + found = true; + if (vessel.mainBody.BiomeMap == null) + multiplier = 0.5f; + id = "SCANsatBiomeAnomaly"; + coverage = SCANUtil.getCoveragePercentage(data, SCANtype.Biome); + } + if (!found) return null; + se = ResearchAndDevelopment.GetExperiment(id); + if (se == null) return null; + + su = ResearchAndDevelopment.GetExperimentSubject(se, ExperimentSituations.InSpaceHigh, vessel.mainBody, "surface"); + if (su == null) return null; + + su.scienceCap *= multiplier; + + SCANUtil.SCANlog("Coverage: {0}, Science cap: {1}, Subject value: {2}, Scientific value: {3}, Science: {4}", new object[5] { coverage.ToString("F1"), su.scienceCap.ToString("F1"), su.subjectValue.ToString("F2"), su.scientificValue.ToString("F2"), su.science.ToString("F2") }); + + su.scientificValue = 1; + + float science = (float)coverage; + if (science > 95) science = 100; + if (science < 30) science = 0; + science = science / 100f; + science = Mathf.Max(0, (science * su.scienceCap) - su.science); + + SCANUtil.SCANlog("Remaining science: {0}, Base value: {1}", new object[2] { science.ToString("F1"), se.baseValue.ToString("F1") }); + + science /= Mathf.Max(0.1f, su.scientificValue); //look 10 lines up; this is always 1... + science /= su.subjectValue; + + SCANUtil.SCANlog("Resulting science value: {0}", new object[1] { science.ToString("F2") }); + + if (notZero && science <= 0) science = 0.00001f; + + sd = new ScienceData(science * su.dataScale, 1f, 0f, su.id, se.experimentTitle + " of " + vessel.mainBody.theName); + su.title = sd.title; + return sd; + } + + public ScienceData[] GetData() + { + return storedData.ToArray(); + } + + private void KeepData(ScienceData data) + { + expDialog = null; + } + + private void TransmitData(ScienceData data) + { + expDialog = null; + List tranList = vessel.FindPartModulesImplementing(); + if (tranList.Count > 0 && storedData.Count > 0) + { + makeScienceData(false); + tranList.OrderBy(ScienceUtil.GetTransmitterScore).First().TransmitData(storedData); + DumpData(storedData[0]); + } + else ScreenMessages.PostScreenMessage("No transmitters available on this vessel.", 4f, ScreenMessageStyle.UPPER_LEFT); + } + + public void DumpData(ScienceData data) + { + expDialog = null; + while (storedData.Contains(data)) + { + storedData.Remove(data); + } + } + + public void ReviewDataItem(ScienceData sd) + { + ReviewData(); + } + + public void ReviewData() + { + if (storedData.Count < 1) + return; + if (expDialog != null) + DestroyImmediate(expDialog); + ScienceData sd = storedData[0]; + expDialog = ExperimentsResultDialog.DisplayResult(new ExperimentResultDialogPage(part, sd, 1f, 0f, false, "", true, false, DumpData, KeepData, TransmitData, null)); + } + + public bool IsRerunnable() + { + return true; + } + + public int GetScienceCount() + { + return storedData.Count; + } + } +} + diff --git a/SCANsat/SCAN_Toolbar/SCANtoolbar.cs b/SCANsat/SCAN_Toolbar/SCANtoolbar.cs index 9d1e272b0..8c56bb6a8 100644 --- a/SCANsat/SCAN_Toolbar/SCANtoolbar.cs +++ b/SCANsat/SCAN_Toolbar/SCANtoolbar.cs @@ -121,6 +121,7 @@ private void createMenu(IButton menu) IButton bigMap = list.AddOption("Big Map"); IButton settings = list.AddOption("Settings"); IButton color = list.AddOption("Color Options"); + IButton resource = list.AddOption("Planetary Overlay"); smallMap.OnClick += (e2) => { @@ -144,6 +145,10 @@ private void createMenu(IButton menu) { SCANcontroller.controller.colorManager.Visible = !SCANcontroller.controller.colorManager.Visible; }; + resource.OnClick += (e2) => + { + SCANcontroller.controller.resourceOverlay.Visible = !SCANcontroller.controller.resourceOverlay.Visible; + }; list.OnAnyOptionClicked += () => destroyMenu(menu); menu.Drawable = list; } diff --git a/SCANsat/SCAN_UI/SCANbigMap.cs b/SCANsat/SCAN_UI/SCANbigMap.cs index f8572bb6c..ccc8d660f 100644 --- a/SCANsat/SCAN_UI/SCANbigMap.cs +++ b/SCANsat/SCAN_UI/SCANbigMap.cs @@ -75,22 +75,37 @@ protected override void Start() { //Initialize the map object Visible = SCANcontroller.controller.bigMapVisible; - if (v == null) - v = FlightGlobals.ActiveVessel; + WindowRect.x = SCANcontroller.controller.map_x; + WindowRect.y = SCANcontroller.controller.map_y; + lastColor = currentColor = SCANcontroller.controller.colours == 0; + lastResource = SCANcontroller.controller.map_ResourceOverlay; + if (SCANconfigLoader.GlobalResource) + loadedResources = SCANcontroller.setLoadedResourceList(); + TooltipsEnabled = SCANcontroller.controller.toolTips; + + initializeMap(); + } + + private void initializeMap() + { + v = FlightGlobals.ActiveVessel; if (b == null) - b = v.mainBody; + { + if (v == null) + b = FlightGlobals.Bodies[1]; + else + b = v.mainBody; + } + if (bigmap == null) { bigmap = new SCANmap(b, true); bigmap.setProjection((MapProjection)SCANcontroller.controller.projection); + if (SCANcontroller.controller.map_width % 2 != 0) + SCANcontroller.controller.map_width += 1; bigmap.setWidth(SCANcontroller.controller.map_width); } - WindowRect.x = SCANcontroller.controller.map_x; - WindowRect.y = SCANcontroller.controller.map_y; - currentColor = SCANcontroller.controller.colours == 0; - lastColor = currentColor; - lastResource = SCANcontroller.controller.map_ResourceOverlay; - WindowCaption = string.Format("Map of {0}", b.theName); + data = SCANUtil.getData(b); if (data == null) { @@ -98,11 +113,8 @@ protected override void Start() SCANcontroller.controller.addToBodyData(b, data); } bigmap.setBody(b); - if (SCANconfigLoader.GlobalResource) - { - loadedResources = SCANcontroller.setLoadedResourceList(); - } - TooltipsEnabled = SCANcontroller.controller.toolTips; + + WindowCaption = string.Format("Map of {0}", b.theName); } protected override void OnDestroy() @@ -111,6 +123,12 @@ protected override void OnDestroy() Destroy(spotMap); } + protected override void Update() + { + if (FlightGlobals.ready) + v = FlightGlobals.ActiveVessel; + } + //Properties used to sync with color selection window public static SCANmap BigMap { @@ -150,6 +168,8 @@ protected override void DrawWindowPre(int id) IsResizing = false; if (resizeW < WindowSize_Min.x) resizeW = WindowSize_Min.x; + if ((int)resizeW % 2 != 0) + resizeW += 1; bigmap.setWidth((int)resizeW); drawGrid = true; SCANcontroller.controller.map_width = bigmap.MapWidth; @@ -188,7 +208,7 @@ protected override void DrawWindow(int id) mapDraw(id); /* Draw the main map texture */ stopE(); growE(); - fillS(160); + fillS(180); growS(); mouseOver(id); /* Handle all mouse-over info and zoom-map code */ legendBar(id); /* Draw the mouseover info and legend bar along the bottom */ @@ -465,27 +485,34 @@ private void toggleBar(int id) SCANcontroller.controller.mainMap.Visible = !SCANcontroller.controller.mainMap.Visible; } - s.x += 40; + s.x += 36; if (GUI.Button(s, iconWithTT(SCANskins.SCAN_InstrumentIcon, "Instrument Window"), SCANskins.SCAN_windowButton)) { SCANcontroller.controller.instrumentsWindow.Visible = !SCANcontroller.controller.instrumentsWindow.Visible; } - s.x += 40; + s.x += 36; if (GUI.Button(s, iconWithTT(SCANskins.SCAN_SettingsIcon, "Settings Menu"), SCANskins.SCAN_windowButton)) { SCANcontroller.controller.settingsWindow.Visible = !SCANcontroller.controller.settingsWindow.Visible; } - s.x += 40; + s.x += 36; if (GUI.Button(s, iconWithTT(SCANskins.SCAN_ColorIcon, "Color Control"), SCANskins.SCAN_windowButton)) { SCANcontroller.controller.colorManager.Visible = !SCANcontroller.controller.colorManager.Visible; } + s.x += 36; + + if (GUI.Button(s, iconWithTT(SCANskins.SCAN_OverlayIcon, "Overlay Control"), SCANskins.SCAN_windowButton)) + { + SCANcontroller.controller.resourceOverlay.Visible = !SCANcontroller.controller.resourceOverlay.Visible; + } + s.x = WindowRect.width - 66; if (GUI.Button(s, iconWithTT(SCANskins.SCAN_ScreenshotIcon, "Export Map"), SCANskins.SCAN_windowButton)) diff --git a/SCANsat/SCAN_UI/SCANcolorSelection.cs b/SCANsat/SCAN_UI/SCANcolorSelection.cs index 1542fd00c..2c71a5493 100644 --- a/SCANsat/SCAN_UI/SCANcolorSelection.cs +++ b/SCANsat/SCAN_UI/SCANcolorSelection.cs @@ -43,6 +43,7 @@ class SCANcolorSelection: SCAN_MBW private float bTrans, rTrans; private bool stockBiomes = false; + private bool biomeBorders = true; private SCANresourceGlobal currentResource; private float lowRCutoff, highRCutoff; @@ -111,6 +112,7 @@ protected override void Start() currentTerrain = new SCANterrainConfig(data.TerrainConfig); 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); @@ -750,6 +752,8 @@ private void biomeOptions(int id) fillS(20); stockBiomes = GUILayout.Toggle(stockBiomes, "Use Stock Biome Maps", SCANskins.SCAN_toggle); fillS(8); + biomeBorders = GUILayout.Toggle(biomeBorders, "White Biome Borders", SCANskins.SCAN_toggle); + fillS(8); growE(); fillS(10); biomeTransSlider.drawSlider(false, ref bTrans); @@ -811,6 +815,7 @@ private void biomeConfirm(int id) SCANcontroller.controller.lowBiomeColor = biomeColorPicker.ColorLow; SCANcontroller.controller.highBiomeColor = biomeColorPicker.ColorHigh; SCANcontroller.controller.useStockBiomes = stockBiomes; + SCANcontroller.controller.biomeBorder = biomeBorders; SCANcontroller.controller.biomeTransparency = bTrans; biomeColorPicker.updateOldSwatches(); @@ -829,9 +834,11 @@ private void biomeConfirm(int id) SCANcontroller.controller.lowBiomeColor = SCANconfigLoader.SCANNode.LowBiomeColor; SCANcontroller.controller.highBiomeColor = SCANconfigLoader.SCANNode.HighBiomeColor; SCANcontroller.controller.useStockBiomes = SCANconfigLoader.SCANNode.StockBiomeMap; + SCANcontroller.controller.biomeBorder = SCANconfigLoader.SCANNode.BiomeBorder; SCANcontroller.controller.biomeTransparency = SCANconfigLoader.SCANNode.BiomeTransparency; - stockBiomes = false; + stockBiomes = SCANcontroller.controller.useStockBiomes; + biomeBorders = SCANcontroller.controller.biomeBorder; biomeColorPicker = new SCANuiColorPicker(SCANcontroller.controller.lowBiomeColor, SCANcontroller.controller.highBiomeColor, biomeColorPicker.LowColorChange); @@ -1166,7 +1173,7 @@ private void drawPreviewLegend() if (currentTerrain.PalRev) c = currentTerrain.ColorPal.colorsReverse; previewLegend = new SCANmapLegend(); - previewLegend.Legend = previewLegend.getLegend(maxT, minT, clamp, currentTerrain.PalDis, c); + previewLegend.Legend = previewLegend.getLegend(maxT, minT, maxT - minT, clamp, currentTerrain.PalDis, c); } //Resets the palettes whenever the size slider is adjusted diff --git a/SCANsat/SCAN_UI/SCANkscMap.cs b/SCANsat/SCAN_UI/SCANkscMap.cs index e99aa3b4b..21fff1ce3 100644 --- a/SCANsat/SCAN_UI/SCANkscMap.cs +++ b/SCANsat/SCAN_UI/SCANkscMap.cs @@ -482,7 +482,7 @@ private void toggleBar(int id) SCANcontroller.controller.settingsWindow.removeControlLocks(); } - s.x += 40; + s.x += 36; if (GUI.Button(s, iconWithTT(SCANskins.SCAN_ColorIcon, "Color Control"), SCANskins.SCAN_windowButton)) { @@ -490,6 +490,16 @@ private void toggleBar(int id) SCANcontroller.controller.colorManager.removeControlLocks(); } + if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) + { + s.x += 36; + + if (GUI.Button(s, iconWithTT(SCANskins.SCAN_OverlayIcon, "Overlay Control"), SCANskins.SCAN_windowButton)) + { + SCANcontroller.controller.resourceOverlay.Visible = !SCANcontroller.controller.resourceOverlay.Visible; + } + } + s.x = WindowRect.width - 66; if (GUI.Button(s, iconWithTT(SCANskins.SCAN_ScreenshotIcon, "Export Map"), SCANskins.SCAN_windowButton)) diff --git a/SCANsat/SCAN_UI/SCANmainMap.cs b/SCANsat/SCAN_UI/SCANmainMap.cs index d3dee6239..ba80d93c7 100644 --- a/SCANsat/SCAN_UI/SCANmainMap.cs +++ b/SCANsat/SCAN_UI/SCANmainMap.cs @@ -165,6 +165,10 @@ private void windowButtons(int id) { SCANcontroller.controller.colorManager.Visible = !SCANcontroller.controller.colorManager.Visible; } + if (GUILayout.Button(iconWithTT(SCANskins.SCAN_OverlayIcon, "Overlay Contral"), SCANskins.SCAN_windowButton, GUILayout.Height(32), GUILayout.Width(32))) + { + SCANcontroller.controller.resourceOverlay.Visible = !SCANcontroller.controller.resourceOverlay.Visible; + } } //Draw the vessel location and alt info diff --git a/SCANsat/SCAN_UI/SCANoverlayController.cs b/SCANsat/SCAN_UI/SCANoverlayController.cs new file mode 100644 index 000000000..70b941616 --- /dev/null +++ b/SCANsat/SCAN_UI/SCANoverlayController.cs @@ -0,0 +1,304 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SCANsat.SCAN_Data; +using SCANsat.SCAN_UI.UI_Framework; +using SCANsat.SCAN_Platform; +using UnityEngine; +using palette = SCANsat.SCAN_UI.UI_Framework.SCANpalette; + +namespace SCANsat.SCAN_UI +{ + class SCANoverlayController : SCAN_MBW + { + internal readonly static Rect defaultRect = new Rect(Screen.width - 280, 200, 200, 260); + private static Rect sessionRect = defaultRect; + private CelestialBody body; + private SCANdata data; + private SCANresourceGlobal currentResource; + private List resources; + private List resourceFractions; + private bool biomeMode = false; + private bool drawOverlay = false; + private bool oldOverlay = false; + private int selection; + + private Texture2D mapOverlay; + private Texture2D biomeOverlay; + private int mapHeight = 256; + private float transparency = 0f; + private int interpolationScale = 8; + + protected override void Awake() + { + WindowCaption = "S.C.A.N. Overlay"; + WindowRect = sessionRect; + WindowStyle = SCANskins.SCAN_window; + WindowOptions = new GUILayoutOption[2] { GUILayout.Width(200), GUILayout.Height(260) }; + Visible = false; + DragEnabled = true; + ClampToScreenOffset = new RectOffset(-140, -140, -200, -200); + + SCAN_SkinsLibrary.SetCurrent("SCAN_Unity"); + } + + protected override void Start() + { + resources = SCANcontroller.setLoadedResourceList(); + + setBody(HighLogic.LoadedSceneIsFlight ? FlightGlobals.currentMainBody : Planetarium.fetch.Home); + } + + protected override void Update() + { + if ((MapView.MapIsEnabled && HighLogic.LoadedSceneIsFlight && FlightGlobals.ready) || HighLogic.LoadedScene == GameScenes.TRACKSTATION) + { + CelestialBody mapBody = SCANUtil.getTargetBody(MapView.MapCamera.target); + + if (mapBody == null) + return; + + if (mapBody != body) + setBody(mapBody); + } + else if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready) + { + if (body != FlightGlobals.currentMainBody) + setBody(FlightGlobals.currentMainBody); + } + } + + protected override void OnDestroy() + { + + } + + 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 */ + closeBox(id); + + drawResourceList(id); + overlayToggle(id); + overlayOptions(id); + resourceSettings(id); + } + + protected override void DrawWindowPost(int id) + { + if (oldOverlay != drawOverlay) + { + oldOverlay = drawOverlay; + if (oldOverlay) + refreshMap(); + else + OverlayGenerator.Instance.ClearDisplay(); + } + + sessionRect = WindowRect; + } + + //Draw the version label in the upper left corner + private void versionLabel(int id) + { + Rect r = new Rect(4, 0, 50, 18); + GUI.Label(r, SCANmainMenuLoader.SCANsatVersion, SCANskins.SCAN_whiteReadoutLabel); + } + + //Draw the close button in the upper right corner + private void closeBox(int id) + { + Rect r = new Rect(WindowRect.width - 20, 1, 18, 18); + if (GUI.Button(r, SCANcontroller.controller.closeBox, SCANskins.SCAN_closeButton)) + { + Visible = false; + } + } + + private void drawResourceList(int id) + { + for (int i = 0; i < resources.Count; i++) + { + SCANresourceGlobal r = resources[i]; + + if (r == null) + continue; + + if (GUILayout.Button(r.Name, selection == i ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) + { + biomeMode = false; + OverlayGenerator.Instance.ClearDisplay(); + + if (selection != i) + { + selection = i; + currentResource = r; + currentResource.CurrentBodyConfig(body.name); + oldOverlay = drawOverlay = true; + refreshMap(); + return; + } + + if (drawOverlay) + { + oldOverlay = drawOverlay = false; + } + else + { + oldOverlay = drawOverlay = true; + refreshMap(); + } + } + } + + if (GUILayout.Button("Biome Map", selection == (resources.Count) ? SCANskins.SCAN_labelLeftActive : SCANskins.SCAN_labelLeft)) + { + biomeMode = true; + + OverlayGenerator.Instance.ClearDisplay(); + + if (selection != resources.Count) + { + selection = resources.Count; + oldOverlay = drawOverlay = true; + refreshMap(); + return; + } + + if (drawOverlay) + { + oldOverlay = drawOverlay = false; + } + else + { + oldOverlay = drawOverlay = true; + refreshMap(); + } + } + } + + private void overlayToggle(int id) + { + drawOverlay = GUILayout.Toggle(drawOverlay, "Draw Overlay", SCANskins.SCAN_settingsToggle); + } + + private void overlayOptions(int id) + { + if (!drawOverlay) + return; + + if (GUILayout.Button("Refresh")) + refreshMap(); + + if (!biomeMode) + { + growE(); + GUILayout.Label("Coverage Transparency:", SCANskins.SCAN_labelSmallLeft); + + if (GUILayout.Button("-", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + transparency = Mathf.Max(0f, transparency - 0.1f); + refreshMap(); + } + GUILayout.Label(transparency.ToString("P0"), SCANskins.SCAN_labelSmall); + if (GUILayout.Button("+", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + transparency = Mathf.Min(1f, transparency + 0.1f); + refreshMap(); + } + stopE(); + } + } + + private void resourceSettings(int id) + { + fillS(); + if (GUILayout.Button("Resource Settings")) + { + SCANcontroller.controller.resourceSettings.Visible = !SCANcontroller.controller.resourceSettings.Visible; + } + + //if (GUILayout.Button("Biome Summary")) + //{ + // foreach (ResourceCache.AbundanceSummary a in ResourceCache.Instance.AbundanceCache) + // { + // 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); + // } + + + //} + } + + public void refreshMap(float t, int height, int interp) + { + transparency = t; + mapHeight = height; + interpolationScale = interp; + if (drawOverlay) + refreshMap(); + } + + private void refreshMap() + { + if (biomeMode) + body.SetResourceMap(SCANuiUtil.drawBiomeMap(biomeOverlay, data, transparency, mapHeight * 2)); + else + body.SetResourceMap(SCANuiUtil.drawResourceTexture(mapOverlay, mapHeight, data, currentResource, interpolationScale, transparency)); + } + + private void setBody(CelestialBody B) + { + body = B; + data = SCANUtil.getData(body); + if (data == null) + { + data = new SCANdata(body); + SCANcontroller.controller.addToBodyData(body, data); + } + + if (currentResource == null) + { + if (resources.Count > 0) + { + currentResource = resources[0]; + currentResource.CurrentBodyConfig(body.name); + } + } + else + { + currentResource.CurrentBodyConfig(body.name); + } + + if (drawOverlay) + refreshMap(); + + + //resourceFractions = ResourceMap.Instance.GetResourceItemList(HarvestTypes.Planetary, body); + //if (resources.Count > 0) + //{ + // currentResource = resources[0]; + // currentResource.CurrentBodyConfig(body.name); + + // //foreach (SCANresourceGlobal r in resources) + // //{ + // // SCANresourceBody b = r.getBodyConfig(body.name, false); + // // if (b != null) + // // { + // // b.Fraction = resourceFractions.FirstOrDefault(a => a.resourceName == r.Name).fraction; + // // } + // //} + //} + } + } +} diff --git a/SCANsat/SCAN_UI/SCANresourceSettings.cs b/SCANsat/SCAN_UI/SCANresourceSettings.cs new file mode 100644 index 000000000..f6ac97e70 --- /dev/null +++ b/SCANsat/SCAN_UI/SCANresourceSettings.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using SCANsat.SCAN_Data; +using SCANsat.SCAN_UI.UI_Framework; +using SCANsat.SCAN_Platform; +using UnityEngine; +using palette = SCANsat.SCAN_UI.UI_Framework.SCANpalette; + +namespace SCANsat.SCAN_UI +{ + class SCANresourceSettings : SCAN_MBW + { + internal readonly static Rect defaultRect = new Rect(300, 200, 300, 300); + private static Rect sessionRect = defaultRect; + private int mapHeight = 256; + private float transparency = 0f; + private int interpolationScale = 8; + private bool popup, warningResource, warningStockResource, controlLock; + private const string lockID = "resourceSettingLockID"; + private Rect warningRect; + + protected override void Awake() + { + WindowCaption = "S.C.A.N. Resources Settings"; + WindowRect = sessionRect; + WindowStyle = SCANskins.SCAN_window; + WindowOptions = new GUILayoutOption[2] { GUILayout.Width(350), GUILayout.Height(300) }; + Visible = false; + DragEnabled = true; + ClampToScreenOffset = new RectOffset(-200, -200, -200, -200); + + SCAN_SkinsLibrary.SetCurrent("SCAN_Unity"); + } + + internal void removeControlLocks() + { + InputLockManager.RemoveControlLock(lockID); + controlLock = false; + } + + protected override void DrawWindowPre(int id) + { + //Lock space center click through + if (HighLogic.LoadedScene == 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(); + } + } + + //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) + { + InputLockManager.RemoveControlLock(lockID); + controlLock = false; + } + } + + if (!popup) + { + warningResource = false; + warningStockResource = false; + } + } + + protected override void DrawWindow(int id) + { + versionLabel(id); /* Standard version label and close button */ + closeBox(id); + + resourceController(id); + resourceSettings(id); + overlayOptions(id); + + warningBox(id); + } + + protected override void DrawWindowPost(int id) + { + if (popup && Event.current.type == EventType.mouseDown && !warningRect.Contains(Event.current.mousePosition)) + { + popup = false; + } + + sessionRect = WindowRect; + } + + //Draw the version label in the upper left corner + private void versionLabel(int id) + { + Rect r = new Rect(4, 0, 50, 18); + GUI.Label(r, SCANmainMenuLoader.SCANsatVersion, SCANskins.SCAN_whiteReadoutLabel); + } + + //Draw the close button in the upper right corner + private void closeBox(int id) + { + Rect r = new Rect(WindowRect.width - 20, 1, 18, 18); + if (GUI.Button(r, SCANcontroller.controller.closeBox, SCANskins.SCAN_closeButton)) + { + Visible = false; + } + } + + private void resourceController(int id) + { + if (SCANcontroller.controller.resourceOverlay == null) + return; + + if (GUILayout.Button("Planetary Overlay Window")) + { + SCANcontroller.controller.resourceOverlay.Visible = !SCANcontroller.controller.resourceOverlay.Visible; + } + } + + 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); + stopE(); + growE(); + fillS(); + SCANcontroller.controller.needsNarrowBand = GUILayout.Toggle(SCANcontroller.controller.needsNarrowBand, "Zoom 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(); + stopE(); + if (popup) + { + GUILayout.Label("Reset SCANsat Resource Coverage", SCANskins.SCAN_button); + if (SCANcontroller.controller.disableStockResource) + { + fillS(8); + GUILayout.Label("Reset Stock Resource Scanning", SCANskins.SCAN_button); + } + } + else + { + if (GUILayout.Button("Reset SCANsat Resource Coverage")) + { + popup = !popup; + warningResource = !warningResource; + } + if (SCANcontroller.controller.disableStockResource) + { + fillS(8); + if (GUILayout.Button("Reset Stock Resource Scanning")) + { + popup = !popup; + warningStockResource = !warningStockResource; + } + } + } + } + + private void overlayOptions(int id) + { + growE(); + GUILayout.Label("Interpolation:", SCANskins.SCAN_labelSmallLeft); + + fillS(); + + if (GUILayout.Button("-", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + interpolationScale = Math.Max(2, interpolationScale / 2); + refreshMap(); + } + GUILayout.Label(interpolationScale.ToString(), SCANskins.SCAN_labelSmall, GUILayout.Width(36)); + if (GUILayout.Button("+", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + interpolationScale = Math.Min(32, interpolationScale * 2); + refreshMap(); + } + stopE(); + + growE(); + GUILayout.Label("Map Height:", SCANskins.SCAN_labelSmallLeft); + + fillS(); + + if (GUILayout.Button("-", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + mapHeight = Math.Max(64, mapHeight / 2); + refreshMap(); + } + GUILayout.Label(mapHeight.ToString(), SCANskins.SCAN_labelSmall, GUILayout.Width(36)); + if (GUILayout.Button("+", SCANskins.SCAN_buttonSmall, GUILayout.Width(18))) + { + mapHeight = Math.Min(1024, mapHeight * 2); + refreshMap(); + } + stopE(); + } + + //Confirmation boxes for map resets + private void warningBox(int id) + { + if (popup) + { + if (warningResource) + { + CelestialBody thisBody = getTargetBody(); + + if (thisBody == null) + { + popup = false; + return; + } + warningRect = new Rect(WindowRect.width - (WindowRect.width / 2) - 150, WindowRect.height - 125, 300, 90); + GUI.Box(warningRect, ""); + Rect r = new Rect(warningRect.x + 10, warningRect.y + 5, 280, 40); + GUI.Label(r, "Erase SCANsat resource data for " + thisBody.theName + "?", SCANskins.SCAN_headlineSmall); + r.x += 90; + r.y += 45; + r.width = 80; + r.height = 30; + if (GUI.Button(r, "Confirm", SCANskins.SCAN_buttonWarning)) + { + popup = false; + warningResource = false; + SCANdata data = SCANUtil.getData(thisBody); + if (data != null) + data.resetResources(); + } + } + else if (warningStockResource) + { + CelestialBody thisBody = getTargetBody(); + + if (thisBody == null) + { + popup = false; + return; + } + + warningRect = new Rect(WindowRect.width - (WindowRect.width / 2) - 150, WindowRect.height - 125, 300, 110); + GUI.Box(warningRect, ""); + Rect r = new Rect(warningRect.x + 10, warningRect.y + 5, 280, 60); + GUI.Label(r, "Erase stock resource data for " + thisBody.theName + "?", SCANskins.SCAN_headlineSmall); + r.x += 90; + r.y += 65; + r.width = 80; + r.height = 30; + if (GUI.Button(r, "Confirm", SCANskins.SCAN_buttonWarning)) + { + popup = false; + warningStockResource = false; + var resources = ResourceScenario.Instance.gameSettings.GetPlanetScanInfo(); + resources.RemoveAll(a => a.PlanetId == thisBody.flightGlobalsIndex); + } + } + else + popup = false; + } + } + + private void refreshMap() + { + if (SCANcontroller.controller.resourceOverlay == null) + return; + + SCANcontroller.controller.resourceOverlay.refreshMap(transparency, mapHeight, interpolationScale); + } + + private CelestialBody getTargetBody() + { + switch (HighLogic.LoadedScene) + { + case GameScenes.FLIGHT: + return FlightGlobals.currentMainBody; + case GameScenes.SPACECENTER: + return Planetarium.fetch.Home; + case GameScenes.TRACKSTATION: + return SCANUtil.getTargetBody(MapView.MapCamera.target); + default: + return null; + } + } + + + } +} diff --git a/SCANsat/SCAN_UI/SCANsatRPM.cs b/SCANsat/SCAN_UI/SCANsatRPM.cs index b5e8714d2..865853d77 100644 --- a/SCANsat/SCAN_UI/SCANsatRPM.cs +++ b/SCANsat/SCAN_UI/SCANsatRPM.cs @@ -22,6 +22,7 @@ using System.Globalization; using SCANsat.SCAN_Map; using SCANsat.SCAN_Data; +using SCANsat.SCAN_PartModules; using SCANsat.SCAN_UI.UI_Framework; namespace SCANsat.SCAN_UI @@ -109,7 +110,7 @@ public class JSISCANsatRPM: InternalModule private SCANanomaly[] localAnomalies; private List localWaypoints; private Material iconMaterial; - private SCANsat sat; + private SCANsat.SCAN_PartModules.SCANsat sat; internal RPMPersistence persist; private string persistentVarName; private double pixelsPerKm; @@ -667,7 +668,7 @@ private void Start() persistentVarName = "scansat" + internalProp.propID; try { - sat = part.FindModulesImplementing().First(); + sat = part.FindModulesImplementing().First(); } 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"); diff --git a/SCANsat/SCAN_UI/SCANsettingsUI.cs b/SCANsat/SCAN_UI/SCANsettingsUI.cs index d08d45044..d4e87e74c 100644 --- a/SCANsat/SCAN_UI/SCANsettingsUI.cs +++ b/SCANsat/SCAN_UI/SCANsettingsUI.cs @@ -32,7 +32,7 @@ class SCANsettingsUI: SCAN_MBW /* UI: time warp names and settings */ private string[] twnames = { "Off", "Low", "Medium", "High" }; private int[] twvals = { 1, 6, 9, 15 }; - private bool popup, warningResource, warningBoxOne, warningBoxAll, controlLock; + private bool popup, warningBoxOne, warningBoxAll, controlLock; private Rect warningRect; private const string lockID = "settingLockID"; private bool oldTooltips, stockToolbar; @@ -111,7 +111,6 @@ protected override void DrawWindowPre(int id) { warningBoxOne = false; warningBoxAll = false; - warningResource = false; } } @@ -121,11 +120,11 @@ protected override void DrawWindow(int id) closeBox(id); growS(); + gui_settings_resources(id); /* resource scanning options */ gui_settings_xmarks(id); /* X marker selection */ gui_settings_toggle_body_scanning(id); /* background and body scanning toggles */ gui_settings_timewarp(id); /* time warp resolution settings */ gui_settings_numbers(id); /* sensor/scanning statistics */ - gui_settings_resources(id); /* resource scanning options */ gui_settings_window_resets_tooltips(id);/* reset windows and positions and toggle tooltips*/ gui_settings_data_resets(id); /* reset data and/or reset resources */ # if DEBUG @@ -275,13 +274,8 @@ private void gui_settings_numbers(int id) //Reset databases private void gui_settings_data_resets(int id) { - CelestialBody thisBody = null; - if (HighLogic.LoadedSceneIsFlight) - thisBody = FlightGlobals.currentMainBody; - else if (HighLogic.LoadedScene == GameScenes.SPACECENTER) - thisBody = Planetarium.fetch.Home; - else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) - thisBody = getTargetBody(MapView.MapCamera.target); + CelestialBody thisBody = getTargetBody(); + if (thisBody == null) return; @@ -309,24 +303,6 @@ private void gui_settings_data_resets(int id) fillS(8); } - private CelestialBody getTargetBody(MapObject target) - { - if (target.type == MapObject.MapObjectType.CELESTIALBODY) - { - return target.celestialBody; - } - 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; - } - //Resets all window positions, tooltip toggle private void gui_settings_window_resets_tooltips(int id) { @@ -369,27 +345,12 @@ private void gui_settings_window_resets_tooltips(int id) private void gui_settings_resources(int id) { - GUILayout.Label("Resource Settings", SCANskins.SCAN_headline); - growE(); - SCANcontroller.controller.resourceBiomeLock = GUILayout.Toggle(SCANcontroller.controller.resourceBiomeLock, "Resource Biome Lock", SCANskins.SCAN_settingsToggle); - 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, "Zoom Requires Narrow Band Scanner", SCANskins.SCAN_settingsToggle); - fillS(); - stopE(); - if (popup) - { - GUILayout.Label("Reset Resource Coverage", SCANskins.SCAN_button); - } - else + if (SCANcontroller.controller.resourceSettings == null) + return; + + if (GUILayout.Button("Resource Settings Window")) { - if (GUILayout.Button("Reset Resource Coverage")) - { - popup = !popup; - warningResource = !warningResource; - } + SCANcontroller.controller.resourceSettings.Visible = !SCANcontroller.controller.resourceSettings.Visible; } } @@ -397,13 +358,8 @@ private void gui_settings_resources(int id) private void gui_settings_window_mapFill(int id) { growE(); - CelestialBody thisBody = null; - if (HighLogic.LoadedSceneIsFlight) - thisBody = FlightGlobals.currentMainBody; - else if (HighLogic.LoadedScene == GameScenes.SPACECENTER) - thisBody = Planetarium.fetch.Home; - else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) - thisBody = getTargetBody(MapView.MapCamera.target); + CelestialBody thisBody = getTargetBody(); + if (thisBody == null) return; if (GUILayout.Button("Fill SCAN map of " + thisBody.theName)) @@ -440,15 +396,14 @@ private void warningBox(int id) { if (warningBoxOne) { - CelestialBody thisBody = null; - if (HighLogic.LoadedSceneIsFlight) - thisBody = FlightGlobals.currentMainBody; - else if (HighLogic.LoadedScene == GameScenes.SPACECENTER) - thisBody = Planetarium.fetch.Home; - else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) - thisBody = getTargetBody(MapView.MapCamera.target); + CelestialBody thisBody = getTargetBody(); + if (thisBody == null) + { + popup = false; return; + } + warningRect = new Rect(WindowRect.width - (WindowRect.width / 2) - 150, WindowRect.height - 125, 300, 90); GUI.Box(warningRect, ""); Rect r = new Rect(warningRect.x + 10, warningRect.y + 5, 280, 40); @@ -486,38 +441,25 @@ private void warningBox(int id) } } } - else if (warningResource) - { - CelestialBody thisBody = null; - if (HighLogic.LoadedSceneIsFlight) - thisBody = FlightGlobals.currentMainBody; - else if (HighLogic.LoadedScene == GameScenes.SPACECENTER) - thisBody = Planetarium.fetch.Home; - else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) - thisBody = getTargetBody(MapView.MapCamera.target); - if (thisBody == null) - return; - warningRect = new Rect(WindowRect.width - (WindowRect.width / 2) - 150, WindowRect.height - 125, 300, 90); - GUI.Box(warningRect, ""); - Rect r = new Rect(warningRect.x + 10, warningRect.y + 5, 280, 40); - GUI.Label(r, "Erase resource data for " + thisBody.theName + "?", SCANskins.SCAN_headlineSmall); - r.x += 90; - r.y += 45; - r.width = 80; - r.height = 30; - if (GUI.Button(r, "Confirm", SCANskins.SCAN_buttonWarning)) - { - popup = false; - warningResource = false; - SCANdata data = SCANUtil.getData(thisBody); - if (data != null) - data.resetResources(); - } - } else popup = false; } } + private CelestialBody getTargetBody() + { + switch (HighLogic.LoadedScene) + { + case GameScenes.FLIGHT: + return FlightGlobals.currentMainBody; + case GameScenes.SPACECENTER: + return Planetarium.fetch.Home; + case GameScenes.TRACKSTATION: + return SCANUtil.getTargetBody(MapView.MapCamera.target); + default: + return null; + } + } + } } diff --git a/SCANsat/SCAN_UI/SCANzoomWindow.cs b/SCANsat/SCAN_UI/SCANzoomWindow.cs index f93d488e9..9e8a21f26 100644 --- a/SCANsat/SCAN_UI/SCANzoomWindow.cs +++ b/SCANsat/SCAN_UI/SCANzoomWindow.cs @@ -173,8 +173,6 @@ private double inc(double d) private void checkForScanners() { - //DateTime duration = DateTime.Now; - narrowBand = false; foreach (Vessel vessel in FlightGlobals.Vessels) { @@ -261,29 +259,16 @@ where nodes.GetValue("name") == "ModuleResourceScanner" if (!narrowBand) spotmap.Resource = null; - - //SCANUtil.SCANdebugLog("Loop Time: {0}", duration - DateTime.Now); } - private int timer; - protected override void Update() { if (Visible) { - if (SCANcontroller.controller.needsNarrowBand && SCANconfigLoader.GlobalResource) - { - if (SCANcontroller.controller.map_ResourceOverlay && timer >= 60) - checkForScanners(); - } - else + if (!SCANcontroller.controller.needsNarrowBand && SCANconfigLoader.GlobalResource) narrowBand = true; - timer++; - if (timer > 60) - timer = 0; - - if (HighLogic.LoadedSceneIsFlight) + if (HighLogic.LoadedSceneIsFlight && FlightGlobals.ready) v = FlightGlobals.ActiveVessel; else if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) { @@ -316,6 +301,11 @@ protected override void DrawWindowPre(int id) else if (resizeH > WindowSize_Max.y) resizeH = WindowSize_Max.y; + if ((int)resizeW % 2 != 0) + resizeW += 1; + if ((int)resizeH % 2 != 0) + resizeH += 1; + spotmap.setSize((int)resizeW, (int)resizeH); spotmap.MapScale = scale; spotmap.centerAround(spotmap.CenteredLong, spotmap.CenteredLat); diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs b/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs index 32583a5b8..bddea87f1 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANpalette.cs @@ -26,9 +26,12 @@ public class SCANpalette // SCANsat) public static Color black = Color.black; public static Color white = Color.white; + public static Color32 White = (Color32)white; public static Color red = Color.red; public static Color grey = Color.grey; + public static Color32 Grey = (Color32)grey; public static Color clear = Color.clear; + public static Color32 Clear = new Color32(0, 0, 0, 0); public static Color magenta = Color.magenta; public static Color yellow = Color.yellow; public static Color cyan = Color.cyan; @@ -40,6 +43,11 @@ public static Color lerp (Color a, Color b, float t) { return Color.Lerp (a,b,t); } + public static Color32 lerp(Color32 a, Color32 b, float t) + { + return Color32.Lerp(a, b, t); + } + // XKCD Colors // (these are collected here for the same reason) @@ -116,15 +124,14 @@ public static Color heightToColor(float val, int scheme, SCANdata data) if (data.TerrainConfig.PalRev) c = data.TerrainConfig.ColorPal.colorsReverse; if (scheme == 0) - return heightToColor(val, data.TerrainConfig.MaxTerrain, data.TerrainConfig.MinTerrain, data.TerrainConfig.ClampTerrain, data.TerrainConfig.PalDis, c); + return heightToColor(val, data.TerrainConfig.MaxTerrain, data.TerrainConfig.MinTerrain, data.TerrainConfig.TerrainRange, data.TerrainConfig.ClampTerrain, data.TerrainConfig.PalDis, c); else - return heightToColor(val, data.TerrainConfig.MaxTerrain, data.TerrainConfig.MinTerrain, data.TerrainConfig.PalDis); + return heightToColor(val, data.TerrainConfig.MaxTerrain, data.TerrainConfig.MinTerrain, data.TerrainConfig.TerrainRange, data.TerrainConfig.PalDis); } - private static Color heightToColor(float val, float max, float min, bool discrete) + private static Color heightToColor(float val, float max, float min, float range, bool discrete) { Color c = black; - float range = max - min; val -= min; if (discrete) { @@ -143,7 +150,7 @@ private static Color heightToColor(float val, float max, float min, bool discret return c; } - internal static Color heightToColor(float val, float max, float min, float? clamp, bool discrete, Color32[] p) + internal static Color heightToColor(float val, float max, float min, float range, float? clamp, bool discrete, Color32[] p) { Color c = black; if (clamp != null) @@ -183,7 +190,6 @@ internal static Color heightToColor(float val, float max, float min, float? clam } else { - float range = max - min; val -= min; if (discrete) { diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs b/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs index b7012d3d7..8afb49c1b 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANskins.cs @@ -52,6 +52,13 @@ class SCANskins: SCAN_MBE internal static GUIStyle SCAN_insWhiteLabel; internal static GUIStyle SCAN_anomalyOverlay; + //Resource controller styles + internal static GUIStyle SCAN_labelLeft; + internal static GUIStyle SCAN_labelRight; + internal static GUIStyle SCAN_labelSmall; + internal static GUIStyle SCAN_labelLeftActive; + internal static GUIStyle SCAN_buttonSmall; + //Settings menu styles internal static GUIStyle SCAN_headline; internal static GUIStyle SCAN_headlineSmall; @@ -100,6 +107,7 @@ class SCANskins: SCAN_MBE internal static Texture2D SCAN_InstrumentIcon; internal static Texture2D SCAN_SmallMapIcon; internal static Texture2D SCAN_BigMapIcon; + internal static Texture2D SCAN_OverlayIcon; //Zoom Window Textures internal static Texture2D SCAN_ZoomOutIcon; @@ -149,6 +157,7 @@ private static void initializeTextures() SCAN_WaypointIcon = GameDatabase.Instance.GetTexture("SCANsat/Icons/SCAN_WayPointIcon", false); SCAN_MechJebIcon = GameDatabase.Instance.GetTexture("SCANsat/Icons/SCAN_MechJebIcon", false); SCAN_TargetIcon = GameDatabase.Instance.GetTexture("SCANsat/Icons/SCAN_TargetIcon", false); + SCAN_OverlayIcon = GameDatabase.Instance.GetTexture("SCANsat/Icons/SCAN_Overlay_Icon", false); } private static void initializeColors() @@ -271,6 +280,28 @@ private static void initializeSkins() SCAN_anomalyOverlay.fontStyle = FontStyle.Bold; SCAN_anomalyOverlay.normal.textColor = palette.cb_skyBlue; + //Resource Control settings + SCAN_labelLeft = new GUIStyle(SCAN_texButton); + SCAN_labelLeft.fontSize = 12; + SCAN_labelLeft.hover.textColor = palette.cb_bluishGreen; + SCAN_labelLeft.alignment = TextAnchor.MiddleLeft; + + SCAN_labelLeftActive = new GUIStyle(SCAN_labelLeft); + SCAN_labelLeftActive.normal.textColor = palette.cb_bluishGreen; + + SCAN_labelRight = new GUIStyle(SCAN_labelLeft); + SCAN_labelRight.alignment = TextAnchor.MiddleRight; + + SCAN_labelSmall = new GUIStyle(SCAN_whiteReadoutLabel); + SCAN_labelSmall.fontSize = 10; + SCAN_labelSmall.alignment = TextAnchor.MiddleCenter; + SCAN_labelSmall.fontStyle = FontStyle.Bold; + + SCAN_buttonSmall = new GUIStyle(SCAN_SkinsLibrary.DefUnitySkin.button); + SCAN_buttonSmall.fontSize = 10; + SCAN_buttonSmall.alignment = TextAnchor.MiddleLeft; + SCAN_buttonSmall.fontStyle = FontStyle.Bold; + //Initialize settings menu styles SCAN_headline = new GUIStyle(SCAN_SkinsLibrary.DefUnitySkin.label); SCAN_headline.name = "SCAN_Headline"; diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs b/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs index 6ffe90b0c..baa146f24 100644 --- a/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs +++ b/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.Text.RegularExpressions; +using System.Linq; using FinePrint; using SCANsat.SCAN_Platform; using SCANsat.SCAN_Data; @@ -157,10 +158,11 @@ internal static void mouseOverInfo(double lon, double lat, SCANmap mapObj, SCANd if (SCANcontroller.controller.map_ResourceOverlay && SCANconfigLoader.GlobalResource && mapObj.Resource != null) //Adds selected resource amount to big map legend { + string label = ""; + if (SCANUtil.isCovered(lon, lat, data, mapObj.Resource.SType)) { - double amount = SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body); - string label; + double amount = SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body, SCANcontroller.controller.resourceBiomeLock); if (amount < 0) label = "Unknown"; else @@ -171,6 +173,12 @@ internal static void mouseOverInfo(double lon, double lat, SCANmap mapObj, SCANd } info += palette.colored(mapObj.Resource.MaxColor, mapObj.Resource.Name + ": " + label + " "); } + 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 + " "); + } } if (SCANcontroller.controller.map_waypoints && WaypointManager.Instance() != null) @@ -235,10 +243,10 @@ internal static void mouseOverInfoSimple(double lon, double lat, SCANmap mapObj, if (SCANcontroller.controller.map_ResourceOverlay && SCANconfigLoader.GlobalResource && mapObj.Resource != null) //Adds selected resource amount to big map legend { + string label = ""; if (SCANUtil.isCovered(lon, lat, data, mapObj.Resource.SType)) { - double amount = SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body); - string label; + double amount = SCANUtil.ResourceOverlay(lat, lon, mapObj.Resource.Name, mapObj.Body, SCANcontroller.controller.resourceBiomeLock); if (amount < 0) label = "Unknown"; else @@ -249,6 +257,12 @@ internal static void mouseOverInfoSimple(double lon, double lat, SCANmap mapObj, } info += palette.colored(mapObj.Resource.MaxColor, mapObj.Resource.Name + ": " + label + " "); } + 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 + " "); + } } if (SCANcontroller.controller.map_waypoints && WaypointManager.Instance() != null) @@ -1348,78 +1362,331 @@ private static void GLVertexMap(Vector3d pos) #region Planet Overlay Textures - internal static void drawResourceTexture(int height, ref int step, SCANdata data, SCANresourceGlobal resource) + private static double fixLon(double Lon) { - Color[] pix; + if (Lon <= 180) + Lon = 180 - Lon; + else + Lon = (Lon - 180) * -1; + Lon -= 90; + if (Lon < -180) + Lon += 360; + + return Lon; + } + + internal static Texture2D drawResourceTexture(Texture2D map, int height, SCANdata data, SCANresourceGlobal resource, int stepScale = 8, float transparency = 0f) + { + int width = height * 2; + float[,] abundanceValues = new float[width, height]; + Color32[] pix = new Color32[width * height]; float scale = height / 180f; - if (resource.MapOverlay == null) + if (map == null || map.height != height) { - resource.MapOverlay = new Texture2D(height * 2, height, TextureFormat.ARGB32, true); - pix = resource.MapOverlay.GetPixels(); - for (int i = 0; i < pix.Length; i++) - pix[i] = palette.clear; - resource.MapOverlay.SetPixels(pix); + map = new Texture2D(width, height, TextureFormat.ARGB32, true); } - else if (step >= resource.MapOverlay.height) + + System.Random r = new System.Random(ResourceScenario.Instance.gameSettings.Seed); + + for (int j = 0; j < height; j += stepScale) { - return; + for (int i = 0; i < width; i += stepScale) + { + double lon = fixLon(i / scale); + double lat = (j / scale) - 90; + + abundanceValues[i, j] = SCANUtil.ResourceOverlay(lat, lon, resource.Name, data.Body, SCANcontroller.controller.resourceBiomeLock) * 100; + + pix[j * width + i] = resourceToColor32(palette.Clear, resource, abundanceValues[i, j], data, lon, lat, transparency); + } + } + + for (int i = stepScale / 2; i >= 1; i /= 2) + { + interpolate(pix, abundanceValues, height, i, i, i, resource, transparency, data, r); + interpolate(pix, abundanceValues, height, 0, i, i, resource, transparency, data, r); + interpolate(pix, abundanceValues, height, i, 0, i, resource, transparency, data, r); } - pix = resource.MapOverlay.GetPixels(0, step, resource.MapOverlay.width, 1); + map.SetPixels32(pix); + map.Apply(); + + return map; + } + + internal static Texture2D drawBiomeMap(Texture2D map, SCANdata data, float transparency, int height = 256, bool useStock = false, bool whiteBorder = false) + { + if (!useStock && !whiteBorder) + return drawBiomeMap(map, data, transparency, height); + + int width = height * 2; + float scale = (width * 1f) / 360f; + double[] mapline = new double[width]; + Color32[] pix = new Color32[height * width]; - for (int i = 0; i < pix.Length; i++) + if (map == null || map.height != height) { - double lon = (i / scale); - double lat = (step / scale) - 90; + map = new Texture2D(width, height, TextureFormat.ARGB32, true); + } - if (lon <= 180) - lon = 180 - lon; - else - lon = (lon - 180) * -1; - lon -= 90; - if (lon < -180) - lon += 360; + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width; i++) + { + double lon = fixLon(i / scale); + double lat = (j / scale) - 90; + + if (!SCANUtil.isCovered(lon, lat, data, SCANtype.Biome)) + { + pix[j * width + i] = palette.lerp(palette.Clear, palette.Grey, transparency); + continue; + } + + float biomeIndex = (float)SCANUtil.getBiomeIndexFraction(data.Body, lon, lat); + + if (whiteBorder && ((i > 0 && mapline[i - 1] != biomeIndex) || (j > 0 && mapline[i] != biomeIndex))) + { + pix[j * width + i] = palette.White; + } + else if (useStock) + { + pix[j * width + i] = palette.lerp((Color32)SCANUtil.getBiome(data.Body, lon, lat).mapColor, palette.Clear, SCANcontroller.controller.biomeTransparency / 100f); + } + else + { + pix[j * width + i] = palette.lerp(palette.lerp((Color32)SCANcontroller.controller.lowBiomeColor, (Color32)SCANcontroller.controller.highBiomeColor, biomeIndex), palette.Clear, SCANcontroller.controller.biomeTransparency / 100f); + } + } + } + + map.SetPixels32(pix); + map.Apply(); + + return map; + } + + private static Texture2D drawBiomeMap(Texture2D m, SCANdata d, float t, int h) + { + if (d.Body.BiomeMap == null) + return null; + + if (m == null) + { + m = new Texture2D(h * 2, h, TextureFormat.RGBA32, true); + } + + Color32[] pix = new Color32[m.width * m.height]; + float scale = m.width / 360f; + + for (int j = 0; j < m.height; j++) + { + for (int i = 0; i < m.width; i++) + { + double lon = fixLon(i / scale); + double lat = (j / scale) - 90; + + 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); + + pix[j *m.width + i] = c; + } + } + + m.SetPixels32(pix); + m.Apply(); + + return m; + } + + private static float getLerp(System.Random rand, int l) + { + if (l == 0) + return 0.5f; + + return (float)l / 100f + (float)rand.Next(100 - (l / 2)) / 100f; + } + + private static void interpolate(Color32[] c, float[,] v, int height, int x, int y, int step, SCANresourceGlobal r, float t, SCANdata d, System.Random rand) + { + int width = height * 2; + float scale = width / 360f; + for (int j = y; j < height + y; j += 2 * step) + { + for (int i = x; i < width + x; i += 2 * step) + { + double lon = fixLon(i / scale); + double lat = (j / scale) - 90; + + int xpos1 = i - step; + if (xpos1 < 0) + xpos1 += width; + int xpos2 = i + step; + if (xpos2 >= width) + xpos2 -= width; - pix[i] = resourceToColor(lon, lat, data, palette.clear, resource, 0.05f); + int ypos1 = j - step; + if (ypos1 < 0) + ypos1 = 0; + int ypos2 = j + step; + if (ypos2 >= height) + ypos2 = height - 1; + + float avgX = 0; + float avgY = 0; + + float lerp = getLerp(rand, step * 2); + + if (x == y) + { + avgX = Mathf.Lerp(v[xpos1, ypos1], v[xpos2, ypos2], lerp); + avgY = Mathf.Lerp(v[xpos1, ypos2], v[xpos2, ypos1], lerp); + } + else + { + avgX = Mathf.Lerp(v[xpos1, j], v[xpos2, j], lerp); + avgY = Mathf.Lerp(v[i, ypos2], v[i, ypos1], lerp); + } + + float avgFinal = Mathf.Lerp(avgX, avgY, lerp); + + v[i, j] = avgFinal; + + c[j * width + i] = resourceToColor32(palette.Clear, r, v[i, j], d, lon, lat, t); + } } + } + + internal static void interpolate(float[,] v, int yStart, int height, int width, int x, int y, int step, System.Random r, bool edges) + { + for (int j = yStart + y; j < height + y + yStart; j += 2 * step) + { + for (int i = x; i < width + x; i += 2 * step) + { + int xpos1 = i - step; + if (xpos1 < 0) + xpos1 += width; + int xpos2 = i + step; + if (xpos2 >= width) + xpos2 -= width; + + int ypos1 = j - step; + if (ypos1 < 0) + ypos1 = 0; + int ypos2 = j + step; + if (ypos2 >= height) + ypos2 = height - 1; + + float avgX = 0; + float avgY = 0; + + float lerp = 0.5f; + if (!edges) + lerp = getLerp(r, step * 2); + + if (x == y) + { + avgX = Mathf.Lerp(v[xpos1, ypos1], v[xpos2, ypos2], lerp); + avgY = Mathf.Lerp(v[xpos1, ypos2], v[xpos2, ypos1], lerp); + } + else + { + avgX = Mathf.Lerp(v[xpos1, j], v[xpos2, j], lerp); + avgY = Mathf.Lerp(v[i, ypos2], v[i, ypos1], lerp); + } - resource.MapOverlay.SetPixels(0, step, resource.MapOverlay.width, 1, pix); - step++; - if (step % 10 == 0 || step >= height) - resource.MapOverlay.Apply(); + float avgFinal = Mathf.Lerp(avgX, avgY, lerp); + + v[i, j] = avgFinal; + } + } + } + + internal static void interpolate(float[,] v, int yStart, int width, int x, int step, System.Random r) + { + + for (int i = x; i < width + x; i += 2 * step) + { + int xpos1 = i - step; + if (xpos1 < 0) + xpos1 += width; + int xpos2 = i + step; + if (xpos2 >= width) + xpos2 -= width; + + float lerp = getLerp(r, step * 2); + + float avgX = Mathf.Lerp(v[xpos1, yStart], v[xpos2, yStart], lerp); + + v[i, yStart] = avgX; + } } - private static double resourceMapValue(double Lon, double Lat, SCANdata Data, SCANresourceGlobal resource) + /* Converts resource amount to pixel color */ + internal static Color resourceToColor(Color BaseColor, SCANresourceGlobal Resource, float Abundance, SCANdata Data, double Lon, double Lat) { - double amount = 0; - if (SCANUtil.isCovered(Lon, Lat, Data, resource.SType)) + if (SCANUtil.isCovered(Lon, Lat, Data, Resource.SType)) + { + if (Abundance >= Resource.CurrentBody.MinValue) + { + if (Abundance > Resource.CurrentBody.MaxValue) + Abundance = Resource.CurrentBody.MaxValue; + } + else + Abundance = 0; + } + else if (SCANUtil.isCovered(Lon, Lat, Data, SCANtype.FuzzyResources)) { - amount = SCANUtil.ResourceOverlay(Lat, Lon, resource.Name, Data.Body); - amount *= 100; - if (amount >= resource.CurrentBody.MinValue) + Abundance = Mathf.RoundToInt(Abundance); + if (Abundance >= Resource.CurrentBody.MinValue) { - if (amount > resource.CurrentBody.MaxValue) - amount = resource.CurrentBody.MaxValue; + if (Abundance > Resource.CurrentBody.MaxValue) + Abundance = Resource.CurrentBody.MaxValue; } else - amount = 0; + Abundance = 0; } else - amount = -1; - return amount; + return BaseColor; + + 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); } - /* Converts resource amount to pixel color */ - internal static Color resourceToColor(double Lon, double Lat, SCANdata Data, Color BaseColor, SCANresourceGlobal Resource, float Transparency = 0.4f) + private static Color32 resourceToColor32(Color32 BaseColor, SCANresourceGlobal Resource, float Abundance, SCANdata Data, double Lon, double Lat, float Transparency = 0.3f) { - double amount = resourceMapValue(Lon, Lat, Data, Resource); - if (amount < 0) + if (SCANUtil.isCovered(Lon, Lat, Data, Resource.SType)) + { + if (Abundance >= Resource.CurrentBody.MinValue) + { + if (Abundance > Resource.CurrentBody.MaxValue) + Abundance = Resource.CurrentBody.MaxValue; + } + else + Abundance = 0; + } + else if (SCANUtil.isCovered(Lon, Lat, Data, SCANtype.FuzzyResources)) + { + Abundance = Mathf.RoundToInt(Abundance); + if (Abundance >= Resource.CurrentBody.MinValue) + { + if (Abundance > Resource.CurrentBody.MaxValue) + Abundance = Resource.CurrentBody.MaxValue; + } + else + Abundance = 0; + } + else return BaseColor; - else if (amount == 0) - return palette.lerp(BaseColor, palette.grey, Transparency); + + if (Abundance == 0) + return palette.lerp(BaseColor, palette.Grey, Transparency); else - return palette.lerp(palette.lerp(Resource.MinColor, Resource.MaxColor, (float)amount / (Resource.CurrentBody.MaxValue - Resource.CurrentBody.MinValue)), BaseColor, Resource.Transparency / 100f); + return palette.lerp(palette.lerp(Resource.MinColor32, Resource.MaxColor32, Abundance / (Resource.CurrentBody.MaxValue - Resource.CurrentBody.MinValue)), BaseColor, Resource.Transparency / 100f); } #endregion diff --git a/SCANsat/SCANcontroller.cs b/SCANsat/SCANcontroller.cs index 1fff5ac90..47c37bb0f 100644 --- a/SCANsat/SCANcontroller.cs +++ b/SCANsat/SCANcontroller.cs @@ -115,6 +115,10 @@ public static SCANcontroller controller public bool easyModeScanning = true; [KSPField(isPersistant = true)] public bool needsNarrowBand = true; + [KSPField(isPersistant = true)] + public bool biomeBorder = true; + [KSPField(isPersistant = true)] + public bool disableStockResource = false; /* Biome and slope colors can't be serialized properly as a KSP Field */ public Color lowBiomeColor = new Color(0, 0.46f, 0.02345098f, 1); @@ -155,6 +159,8 @@ public static SCANcontroller controller internal SCANBigMap BigMap; internal SCANkscMap kscMap; internal SCANcolorSelection colorManager; + internal SCANoverlayController resourceOverlay; + internal SCANresourceSettings resourceSettings; /* App launcher object */ internal SCANappLauncher appLauncher; @@ -762,6 +768,8 @@ private void Start() instrumentsWindow = gameObject.AddComponent(); colorManager = gameObject.AddComponent(); BigMap = gameObject.AddComponent(); + resourceOverlay = gameObject.AddComponent(); + resourceSettings = gameObject.AddComponent(); } catch (Exception e) { @@ -777,6 +785,11 @@ private void Start() kscMap = gameObject.AddComponent(); settingsWindow = gameObject.AddComponent(); colorManager = gameObject.AddComponent(); + if (HighLogic.LoadedScene == GameScenes.TRACKSTATION) + { + resourceOverlay = gameObject.AddComponent(); + resourceSettings = gameObject.AddComponent(); + } } catch (Exception e) { @@ -843,7 +856,7 @@ private void Update() if (!HighLogic.LoadedSceneIsFlight && HighLogic.LoadedScene != GameScenes.TRACKSTATION) return; - if (!easyModeScanning) + if (!easyModeScanning || disableStockResource) return; if (body == null) @@ -912,6 +925,10 @@ private void OnDestroy() Destroy(kscMap); if (BigMap != null) Destroy(BigMap); + if (resourceOverlay != null) + Destroy(resourceOverlay); + if (resourceSettings != null) + Destroy(resourceSettings); if (appLauncher != null) Destroy(appLauncher); } @@ -924,12 +941,12 @@ private void drawTarget() if (!MapView.MapIsEnabled) return; - Vessel v = FlightGlobals.ActiveVessel; + CelestialBody b = SCANUtil.getTargetBody(MapView.MapCamera.target); - if (v == null) + if (b == null) return; - SCANdata d = getData(v.mainBody.name); + SCANdata d = getData(b.name); if (d == null) return; @@ -939,7 +956,7 @@ private void drawTarget() if (target == null) return; - SCANuiUtil.drawTargetOverlay(v.mainBody, target.Latitude, target.Longitude, XKCDColors.DarkGreen); + SCANuiUtil.drawTargetOverlay(b, target.Latitude, target.Longitude, XKCDColors.DarkGreen); } private void removeVessel(Vessel v) @@ -953,7 +970,7 @@ private void removeVessel(Vessel v) private void addVessel(Vessel v) { - foreach (SCANsat s in v.FindPartModulesImplementing()) + foreach (SCANsat.SCAN_PartModules.SCANsat s in v.FindPartModulesImplementing()) { if (s.scanningNow()) registerSensor(v.id, (SCANtype)s.sensorType, s.fov, s.min_alt, s.max_alt, s.best_alt); @@ -1394,7 +1411,7 @@ private void doScanPass(SCANvessel vessel, double UT, double startUT, double las if (alt < ba) fov = (alt / ba) * fov; else sensor.bestRange = true; - double surfscale = 600000d / v.mainBody.Radius; + double surfscale = Planetarium.fetch.Home.Radius / v.mainBody.Radius; if (surfscale < 1) surfscale = 1; surfscale = Math.Sqrt(surfscale); fov *= surfscale; diff --git a/SCANsat/SCANresourceScanner.cs b/SCANsat/SCANresourceScanner.cs deleted file mode 100644 index 47534042b..000000000 --- a/SCANsat/SCANresourceScanner.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using SCANsat.SCAN_Data; - - -namespace SCANsat -{ - public class ModuleSCANresourceScanner : SCANsat, IAnimatedModule - { - [KSPField] - public bool activeModule = false; - [KSPField] - public bool forceActive = false; - - private ModuleOrbitalSurveyor mSurvey; - private ModuleResourceScanner mScanner; - - public override void OnStart(PartModule.StartState state) - { - base.OnStart(state); - - mSurvey = findSurvey(); - mScanner = findScanner(); - - if (!forceActive) - this.isEnabled = false; - else - this.isEnabled = true; - } - - public override string GetInfo() - { - string info = base.GetInfo(); - info += "Resource Scan: " + (SCANtype)sensorType + "\n"; - info += "Active Scanner: " + activeModule + "\n"; - - return info; - } - - private ModuleResourceScanner findScanner() - { - ModuleResourceScanner r = vessel.FindPartModulesImplementing().FirstOrDefault(); - return r; - } - - private ModuleOrbitalSurveyor findSurvey() - { - ModuleOrbitalSurveyor s = vessel.FindPartModulesImplementing().FirstOrDefault(); - return s; - } - - private void updateEvents() - { - base.Events["startScan"].active = !scanning; - base.Events["stopScan"].active = scanning; - } - - public override void OnUpdate() - { - if (activeModule) - { - base.OnUpdate(); - - if (!HighLogic.LoadedSceneIsFlight) - return; - - if (SCANcontroller.controller == null) - return; - - if (!SCANcontroller.controller.easyModeScanning) - updateEvents(); - else - { - base.Events["startScan"].active = false; - base.Events["stopScan"].active = false; - if (scanning) - unregisterScanner(); - } - } - else - { - base.Events["startScan"].active = false; - base.Events["stopScan"].active = false; - } - } - - public void DisableModule() - { - if (!forceActive) - { - this.isEnabled = false; - unregisterScanner(); - } - } - - public void EnableModule() - { - if (!forceActive) - this.isEnabled = true; - } - - public bool IsSituationValid() - { - return true; - } - - public bool ModuleIsActive() - { - return isEnabled; - } - } -} diff --git a/SCANsat/SCANsat.csproj b/SCANsat/SCANsat.csproj index e58707acb..63d716afa 100644 --- a/SCANsat/SCANsat.csproj +++ b/SCANsat/SCANsat.csproj @@ -47,7 +47,6 @@ - @@ -61,6 +60,9 @@ + + + Code @@ -92,6 +94,8 @@ + + @@ -102,7 +106,6 @@ - diff --git a/SCANsat/SCANutil.cs b/SCANsat/SCANutil.cs index ed6ce1b78..48e74adf1 100644 --- a/SCANsat/SCANutil.cs +++ b/SCANsat/SCANutil.cs @@ -142,6 +142,54 @@ public static SCANdata getData(string BodyName) return SCANcontroller.controller.getData(BodyName); } + /// + /// Do SCANsat maps automatically update with the stock, instant-scan orbital surveys? + /// + /// Returns true if instant scan is enabled + public static bool instantResourceScanEnabled() + { + if (SCANcontroller.controller == null) + return true; + + return SCANcontroller.controller.easyModeScanning; + } + + /// + /// Are the stock resource scanner functions disabled; prevents orbital resource surveys? + /// + /// Returns true if stock resource scanning is available + public static bool stockResourceScanEnabled() + { + if (SCANcontroller.controller == null) + return true; + + return !SCANcontroller.controller.disableStockResource; + } + + /// + /// Is the stock resource biome lock enabled; reduced resource abundace accuracy if enabled? + /// + /// Returns true if the biome lock is enabled + public static bool resourceBiomeLockEnabled() + { + if (SCANcontroller.controller == null) + return true; + + return SCANcontroller.controller.resourceBiomeLock; + } + + /// + /// Does the zoom map resource overlay require a narrow-band scanner in orbit? + /// + /// Returns true if a narrow-band scanner is required + public static bool zoomWindowResourceRestrictionEnabled() + { + if (SCANcontroller.controller == null) + return true; + + return SCANcontroller.controller.needsNarrowBand; + } + #endregion #region Internal Utilities @@ -214,6 +262,33 @@ internal static double fixLon(double lon) return (lon + 360 + 180) % 360; } + internal static Vector2d fixRetardCoordinates(Vector2d coords) + { + if (coords.y < -90) + { + while (coords.y < -90) + coords.y += 90; + coords.y = -90 + Math.Abs(coords.y); + coords.x = fixLonShift(coords.x + 180); + + return coords; + } + + if (coords.y > 90) + { + while (coords.y > 90) + coords.y -= 90; + coords.y = 90 - Math.Abs(coords.y); + coords.x = fixLonShift(coords.x - 180); + + return coords; + } + + coords.x = fixLonShift(coords.x); + + return coords; + } + internal static double getElevation(CelestialBody body, double lon, double lat) { if (body.pqsController == null) return 0; @@ -243,7 +318,7 @@ internal static double getElevation(this CelestialBody body, Vector3d worldPosit return ret; } - internal static float ResourceOverlay(double lat, double lon, string name, CelestialBody body) + internal static float ResourceOverlay(double lat, double lon, string name, CelestialBody body, bool biomeLock) { float amount = 0f; var aRequest = new AbundanceRequest @@ -254,7 +329,7 @@ internal static float ResourceOverlay(double lat, double lon, string name, Celes ResourceName = name, ResourceType = HarvestTypes.Planetary, Altitude = 0, - CheckForLock = SCANcontroller.controller.resourceBiomeLock, + CheckForLock = biomeLock, BiomeName = getBiomeName(body, lon, lat), ExcludeVariance = false, }; @@ -263,7 +338,7 @@ internal static float ResourceOverlay(double lat, double lon, string name, Celes return amount; } - internal static int getBiomeIndex(CelestialBody body, double lon , double lat) + private static int getBiomeIndex(CelestialBody body, double lon , double lat) { if (body.BiomeMap == null) return -1; double u = fixLon(lon); @@ -290,6 +365,8 @@ internal static CBAttributeMapSO.MapAttribute getBiome(CelestialBody body, doubl { if (body.BiomeMap == null) return null; int i = getBiomeIndex(body, lon , lat); + if (i == -1) + return null; return body.BiomeMap.Attributes [i]; } @@ -341,6 +418,24 @@ internal static Palette paletteLoader(string name, int size) } } + internal static CelestialBody getTargetBody(MapObject target) + { + if (target.type == MapObject.MapObjectType.CELESTIALBODY) + { + return target.celestialBody; + } + 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 void SCANlog(string log, params object[] stringObjects) { log = string.Format(log, stringObjects);