├── .gitattributes ├── .gitignore ├── README.md ├── X-Science ├── BiomeMapper.cs ├── Body.cs ├── BodySituationFilter.cs ├── Buttons │ ├── AppLauncherButton.cs │ ├── BlizzysToolbarButton.cs │ ├── IToolbarButton.cs │ ├── ToolbarWrapper.cs │ └── UnifiedButton.cs ├── CelestialBodyFilters.cs ├── Config.cs ├── DMagic.cs ├── DisplayMode.cs ├── ExperimentFilter.cs ├── GameData │ └── [x] Science! │ │ ├── CHANGES.md │ │ ├── LICENSE.txt │ │ ├── MiniAVC.dll │ │ ├── PluginData │ │ └── [x] Science! │ │ │ └── settings.cfg │ │ ├── README.md │ │ ├── [x] Science!.version │ │ ├── bubbles.wav │ │ └── science.cfg ├── GameHelper.cs ├── HelpWindow.cs ├── Lib │ ├── Logger.cs │ ├── Logging.cs │ ├── StreamEx.cs │ ├── TextureHelper.cs │ ├── Utilities.cs │ └── Window.cs ├── Libraries │ └── MiniAVC-1.0.3.0 │ │ ├── CHANGES.txt │ │ ├── LICENSE.txt │ │ ├── MiniAVC.dll │ │ └── README.htm ├── NewSelectionData.cs ├── NewSituationData.cs ├── Noise.cs ├── Properties │ └── AssemblyInfo.cs ├── ScienceChecklistAddon.cs ├── ScienceContext.cs ├── ScienceInstance.cs ├── ScienceWindow.cs ├── SettingsWindow.cs ├── ShipState.cs ├── Situation.cs ├── StatusWindow.cs ├── ToDo.txt ├── UnlockedInstrumentList.cs ├── WindowSettings.cs ├── [x] Science!.csproj ├── [x] Science!.sln ├── icons │ ├── OLD_settings.png │ ├── all.png │ ├── audio-alert-off.png │ ├── audio-alert.png │ ├── clearSearch.png │ ├── close.png │ ├── currentSituation.png │ ├── currentVessel.png │ ├── help.png │ ├── icon-small.png │ ├── icon-status-red.png │ ├── icon-status-small-red.png │ ├── icon-status-small.png │ ├── icon-status.png │ ├── icon.png │ ├── maximize.png │ ├── minimize.png │ ├── report-x.png │ ├── report.png │ ├── resize.png │ ├── runExperimentSmall.png │ ├── runExperimentsAll.png │ ├── runExperimentsOnce.png │ ├── runIncompleteExperimentsAll.png │ ├── runIncompleteExperimentsOnce.png │ ├── scienceComplete.png │ ├── scienceCompleteCompact.png │ ├── scienceProgress.png │ ├── scienceProgressCompact.png │ ├── search.png │ ├── settings.png │ ├── stored.png │ ├── time-warp-x.png │ ├── time-warp.png │ └── unlocked.png └── xScienceEventHandler.cs └── from-bitbucket.org ├── Bodrick-x-science-4d6001ced421.zip └── readme.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | /X-Science/*.user 4 | /X-Science/*.suo 5 | .svn -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Z-Key Aerospace has rebuilt this KSP Mod for KSP V1.0 onwards 2 | [X] Science! was by Brodrick and is released under "Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license" 3 | 4 | As of V4.1 it is rebuilt and fixed by Z-Key Aerospace. 5 | 6 | 7 | 8 | Brodrick's readme follows... 9 | 10 | 11 | 12 | [x] Science! 13 | ============ 14 | 15 | Tired of wondering whether you need to go back to Minmus to get an EVA report while landed on the Greater Flats? Then **[x] Science!** is the mod for you! 16 | 17 | **[x] Science!** is a science checklist plugin for Kerbal Space Program. It allows you to see what science experiments you have left to perform - and how much science you'll get for doing them. 18 | 19 | Installation 20 | ------------ 21 | 22 | Simply copy the GameData folder into your KSP directory. 23 | 24 | License 25 | ------ 26 | 27 | **[x] Science!** is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license][1]. 28 | 29 | You are free to: 30 | 31 | * **Share** - copy and redistribute the material in any medium or format 32 | 33 | * **Adapt** - remix, transform, and build upon the material 34 | 35 | As long as: 36 | 37 | * **Attribution** - You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 38 | 39 | * **NonCommercial** - You may not use the material for commercial purposes. 40 | 41 | * **ShareAlike** - If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 42 | 43 | 44 | Version Checking 45 | --- 46 | 47 | This mod includes version checking using [MiniAVC][2]. If you opt-in, it will use the internet to check whether there is a new version available. Data is only read from the internet and no personal information is sent. For a more comprehensive version checking experience, please download the [KSP-AVC Plugin][2]. 48 | 49 | [1]:http://creativecommons.org/licenses/by-nc-sa/4.0/ 50 | [2]:http://forum.kerbalspaceprogram.com/threads/79745 -------------------------------------------------------------------------------- /X-Science/BiomeMapper.cs: -------------------------------------------------------------------------------- 1 | /* Nicked from contract configurator by Nightingale. 2 | 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Text.RegularExpressions; 10 | using UnityEngine; 11 | using KSP; 12 | using Contracts; 13 | 14 | namespace ContractConfigurator 15 | { 16 | [KSPScenario(ScenarioCreationOptions.AddToExistingCareerGames | ScenarioCreationOptions.AddToNewCareerGames, 17 | GameScenes.FLIGHT, GameScenes.TRACKSTATION, GameScenes.SPACECENTER)] 18 | public class BiomeTracker : ScenarioModule 19 | { 20 | private class BiomeData 21 | { 22 | public string name; 23 | public int landCount; 24 | public int waterCount; 25 | 26 | public double landRatio 27 | { 28 | get 29 | { 30 | return (double)landCount / (landCount + waterCount); 31 | } 32 | } 33 | 34 | public List landLocations = new List(); 35 | public List waterLocations = new List(); 36 | 37 | public BiomeData(string name) 38 | { 39 | this.name = name; 40 | } 41 | 42 | public void Save(ConfigNode node) 43 | { 44 | node.AddValue("name", name); 45 | node.AddValue("landCount", landCount); 46 | node.AddValue("waterCount", waterCount); 47 | 48 | foreach (Vector2d v in landLocations) 49 | { 50 | ConfigNode location = new ConfigNode("LAND_LOCATION"); 51 | node.AddNode(location); 52 | location.AddValue("lat", v.y); 53 | location.AddValue("lon", v.x); 54 | } 55 | 56 | foreach (Vector2d v in waterLocations) 57 | { 58 | ConfigNode location = new ConfigNode("WATER_LOCATION"); 59 | node.AddNode(location); 60 | location.AddValue("lat", v.y); 61 | location.AddValue("lon", v.x); 62 | } 63 | } 64 | 65 | public static BiomeData Load(ConfigNode node) 66 | { 67 | BiomeData biomeData = new BiomeData(ConfigNodeUtil.ParseValue(node, "name")); 68 | biomeData.landCount = ConfigNodeUtil.ParseValue(node, "landCount"); 69 | biomeData.waterCount = ConfigNodeUtil.ParseValue(node, "waterCount"); 70 | 71 | foreach (ConfigNode location in node.GetNodes("LAND_LOCATION")) 72 | { 73 | Vector2d v = new Vector2d(); 74 | v.y = ConfigNodeUtil.ParseValue(location, "lat"); 75 | v.x = ConfigNodeUtil.ParseValue(location, "lon"); 76 | biomeData.landLocations.Add(v); 77 | } 78 | 79 | foreach (ConfigNode location in node.GetNodes("WATER_LOCATION")) 80 | { 81 | Vector2d v = new Vector2d(); 82 | v.y = ConfigNodeUtil.ParseValue(location, "lat"); 83 | v.x = ConfigNodeUtil.ParseValue(location, "lon"); 84 | biomeData.waterLocations.Add(v); 85 | } 86 | 87 | return biomeData; 88 | } 89 | } 90 | private static BiomeTracker Instance; 91 | private Dictionary> bodyInfo = new Dictionary>(); 92 | 93 | private bool loaded = false; 94 | 95 | void Start() 96 | { 97 | DontDestroyOnLoad(this); 98 | Instance = this; 99 | 100 | StartCoroutine(LoadAllBodyInfo()); 101 | } 102 | 103 | void Destroy() 104 | { 105 | } 106 | 107 | void Update() 108 | { 109 | // Load all the contract configurator configuration 110 | if (HighLogic.LoadedScene == GameScenes.MAINMENU && !loaded) 111 | { 112 | loaded = true; 113 | } 114 | } 115 | 116 | IEnumerator LoadAllBodyInfo() 117 | { 118 | foreach (YieldInstruction ins in FlightGlobals.Bodies.SelectMany(LoadBodyInfo)) 119 | { 120 | yield return ins; 121 | } 122 | } 123 | 124 | IEnumerable LoadBodyInfo(CelestialBody body) 125 | { 126 | if (body == null || body.pqsController == null || !body.ocean || bodyInfo.ContainsKey(body)) 127 | { 128 | yield break; 129 | } 130 | 131 | Dictionary biomeData = new Dictionary(); 132 | 133 | int biomeCount = body.BiomeMap.Attributes.Length; 134 | float startTime = Time.realtimeSinceStartup; 135 | float timeStep = 0.01f; 136 | int maxCount = 1000; 137 | 138 | int w = 4096; 139 | int h = 2048; 140 | int bu = 0; 141 | int bv = 0; 142 | 143 | LoggingUtil.LogInfo(this, "Starting background load of " + body.name + " biome data."); 144 | int count = 0; 145 | for (int i = 0; i < w; i++) 146 | { 147 | bu = (bu + 977) % w; 148 | 149 | double lonRads = 2.0 * Math.PI * ((bu + 0.5) / w); 150 | double cosLon = Math.Cos(lonRads); 151 | double sinLon = Math.Sin(lonRads); 152 | 153 | for (int j = 0; j < h; j++) 154 | { 155 | count++; 156 | bv = (bv + 239) % h; 157 | 158 | double latRads = Math.PI * (0.5 - (bv + 0.5) / h); 159 | double cosLat = Math.Cos(latRads); 160 | double sinLat = Math.Sin(latRads); 161 | 162 | // Get biome data 163 | string biome = body.BiomeMap.GetAtt(latRads, lonRads).name.Replace(" ", ""); 164 | BiomeData bd; 165 | biomeData.TryGetValue(biome, out bd); 166 | if (bd == null) 167 | { 168 | bd = biomeData[biome] = new BiomeData(biome); 169 | } 170 | 171 | if (bd.landCount + bd.waterCount < maxCount || bd.landLocations.Count < 3 || bd.waterLocations.Count < 3) 172 | { 173 | Vector3d radialVector = new Vector3d(cosLat * cosLon, sinLat, cosLat * sinLon); 174 | double height = body.pqsController.GetSurfaceHeight(radialVector) - body.pqsController.radius; 175 | 176 | if (height > 0.0) 177 | { 178 | bd.landCount++; 179 | if (bd.landLocations.Count < 3) 180 | { 181 | double lon = lonRads * 180.0 / Math.PI; 182 | double lat = latRads * 180.0 / Math.PI; 183 | if (!bd.landLocations.Any(v => Math.Abs(v.x - lon) < 2.0 || Math.Abs(v.y - lat) < 2.0)) 184 | { 185 | bd.landLocations.Add(new Vector2d(lon, latRads * 180.0 / Math.PI)); 186 | } 187 | } 188 | } 189 | else 190 | { 191 | bd.waterCount++; 192 | if (bd.waterLocations.Count < 3) 193 | { 194 | double lon = lonRads * 180.0 / Math.PI; 195 | double lat = latRads * 180.0 / Math.PI; 196 | if (!bd.waterLocations.Any(v => Math.Abs(v.x - lon) < 2.0 || Math.Abs(v.y - lat) < 2.0)) 197 | { 198 | bd.waterLocations.Add(new Vector2d(lon, latRads * 180.0 / Math.PI)); 199 | } 200 | } 201 | } 202 | } 203 | 204 | // Take a break 205 | if (Time.realtimeSinceStartup >= startTime + timeStep) 206 | { 207 | yield return null; 208 | startTime = Time.realtimeSinceStartup; 209 | } 210 | } 211 | 212 | // Check for completion after every "row" 213 | if (biomeData.Count == biomeCount && 214 | biomeData.All(pair => pair.Value.landCount + pair.Value.waterCount >= maxCount && 215 | pair.Value.landLocations.Count >= 3 && pair.Value.waterLocations.Count >= 3)) 216 | { 217 | break; 218 | } 219 | } 220 | 221 | // Build a color => name map 222 | Dictionary nameMap = new Dictionary(); 223 | for (int i = 0; i < body.BiomeMap.Attributes.Length; i++) 224 | { 225 | nameMap[body.BiomeMap.Attributes[i].mapColor.ToString()] = body.BiomeMap.Attributes[i].name; 226 | } 227 | 228 | // Save the biomData that was collected 229 | bodyInfo[body] = biomeData; 230 | 231 | LoggingUtil.LogInfo(this, "Completed background load of " + body.name + " biome data."); 232 | } 233 | 234 | public override void OnLoad(ConfigNode node) 235 | { 236 | try 237 | { 238 | foreach (ConfigNode bodyNode in node.GetNodes("CELESTIAL_BODY")) 239 | { 240 | int version = ConfigNodeUtil.ParseValue(bodyNode, "version", 1); 241 | 242 | if (version == 2) 243 | { 244 | CelestialBody body; 245 | try 246 | { 247 | body = ConfigNodeUtil.ParseValue(bodyNode, "body"); 248 | } 249 | // Check for invalidated celestial bodies, and ignore those entries 250 | catch (ArgumentException e) 251 | { 252 | if (e.Message.Contains("not a valid CelestialBody")) 253 | { 254 | continue; 255 | } 256 | else 257 | { 258 | throw; 259 | } 260 | } 261 | Dictionary biomeDetails = bodyInfo[body] = new Dictionary(); 262 | 263 | foreach (ConfigNode biomeNode in bodyNode.GetNodes("BIOME")) 264 | { 265 | BiomeData biomeData = BiomeData.Load(biomeNode); 266 | biomeDetails.Add(biomeData.name, biomeData); 267 | } 268 | } 269 | } 270 | } 271 | catch (Exception e) 272 | { 273 | LoggingUtil.LogError(this, "Error loading BiomeTracker from persistance file!"); 274 | LoggingUtil.LogException(e); 275 | ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_LOAD, e, "BiomeTracker"); 276 | } 277 | } 278 | 279 | public override void OnSave(ConfigNode node) 280 | { 281 | try 282 | { 283 | foreach (KeyValuePair> pair in bodyInfo) 284 | { 285 | ConfigNode bodyNode = new ConfigNode("CELESTIAL_BODY"); 286 | node.AddNode(bodyNode); 287 | bodyNode.AddValue("body", pair.Key.name); 288 | bodyNode.AddValue("version", 2); 289 | 290 | foreach (BiomeData biomeData in pair.Value.Values) 291 | { 292 | ConfigNode biomeNode = new ConfigNode("BIOME"); 293 | bodyNode.AddNode(biomeNode); 294 | biomeData.Save(biomeNode); 295 | } 296 | } 297 | } 298 | catch (Exception e) 299 | { 300 | LoggingUtil.LogError(this, "Error saving BiomeTracker to persistance file!"); 301 | LoggingUtil.LogException(e); 302 | ExceptionLogWindow.DisplayFatalException(ExceptionLogWindow.ExceptionSituation.SCENARIO_MODULE_SAVE, e, "BiomeTracker"); 303 | } 304 | } 305 | 306 | public static bool IsDifficult(CelestialBody body, string biome, ExperimentSituations situation) 307 | { 308 | if (body == null || !body.ocean || body.pqsController == null || 309 | (situation != ExperimentSituations.SrfLanded && situation != ExperimentSituations.SrfSplashed)) 310 | { 311 | return false; 312 | } 313 | 314 | if (Instance == null || !Instance.bodyInfo.ContainsKey(body)) 315 | { 316 | return true; 317 | } 318 | 319 | // Handles KSC biomes 320 | if (!Instance.bodyInfo[body].ContainsKey(biome)) 321 | { 322 | return situation == ExperimentSituations.SrfSplashed; 323 | } 324 | 325 | double landRatio = Instance.bodyInfo[body][biome].landRatio; 326 | return landRatio > 0.95 && situation == ExperimentSituations.SrfSplashed || 327 | landRatio < 0.05 && situation == ExperimentSituations.SrfLanded; 328 | } 329 | 330 | public static IEnumerable GetDifficultLocations(CelestialBody body, string biome) 331 | { 332 | if (body == null || Instance == null || !Instance.bodyInfo.ContainsKey(body) || 333 | !Instance.bodyInfo[body].ContainsKey(biome)) 334 | { 335 | yield break; 336 | } 337 | 338 | double landRatio = Instance.bodyInfo[body][biome].landRatio; 339 | List list = landRatio > 0.95 ? Instance.bodyInfo[body][biome].waterLocations : 340 | landRatio < 0.05 ? Instance.bodyInfo[body][biome].landLocations : new List(); 341 | foreach (Vector2d v in list) 342 | { 343 | yield return v; 344 | } 345 | } 346 | } 347 | } 348 | */ -------------------------------------------------------------------------------- /X-Science/Body.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | 4 | 5 | namespace ScienceChecklist 6 | { 7 | public sealed class Body 8 | { 9 | // private readonly Logger _logger; 10 | private string[ ] _biomes; 11 | private bool _hasBiomes; 12 | private bool _hasAtmosphere; 13 | private bool _hasOxygen; 14 | private bool _hasOcean; 15 | private bool _hasSurface; 16 | private bool _isHome; 17 | private double? _Reached; // Or null, if player hasn't reached it yet 18 | 19 | private bool _isPlanet; 20 | private bool _isStar; 21 | private bool _isMoon; 22 | private bool _isGasGiant; // No surface but isn't a star 23 | 24 | private CelestialBody _parent; // Note: flightGlobalsIndex or null for the sun 25 | 26 | private string _type; 27 | private string _name; 28 | private CelestialBody _celestialBody; 29 | 30 | 31 | 32 | public string[ ] Biomes { get { return _biomes; } } 33 | public bool HasBiomes { get { return _hasBiomes; } } 34 | public bool HasAtmosphere { get { return _hasAtmosphere; } } 35 | public bool HasOxygen { get { return _hasOxygen; } } 36 | public bool HasOcean { get { return _hasOcean; } } 37 | public bool HasSurface { get { return _hasSurface; } } 38 | public bool IsHome { get { return _isHome; } } 39 | public double? Reached { get { return _Reached; } } 40 | public bool IsPlanet { get { return _isPlanet; } } 41 | public bool IsStar { get { return _isStar; } } 42 | public bool IsGasGiant { get { return _isGasGiant; } } 43 | public bool IsMoon { get { return _isMoon; } } 44 | public string Type { get { return _type; } } 45 | public string Name { get { return _name; } } 46 | public CelestialBody Parent { get { return _parent; } } 47 | public CelestialBody CelestialBody { get { return _celestialBody; } } 48 | 49 | 50 | 51 | // This could fail if some mode changes celestial bodies on the fly 52 | // Just don't want to stick too much stuff into Update() 53 | public Body( CelestialBody Body ) 54 | { 55 | // Init 56 | // _logger = new Logger( "Body: " + Body.name ); 57 | 58 | // Store this! 59 | _celestialBody = Body; 60 | 61 | // Name 62 | _name = _celestialBody.name; 63 | 64 | // Biomes 65 | _hasBiomes = false; 66 | if( _celestialBody.BiomeMap != null ) 67 | _biomes = _celestialBody.BiomeMap.Attributes.Select( y => y.name ).ToArray( ); 68 | else 69 | _biomes = new string[ 0 ]; 70 | if( _biomes.Length > 0 ) 71 | _hasBiomes = true; 72 | 73 | // Surface 74 | _hasSurface = _celestialBody.pqsController != null; 75 | 76 | // Atmosphere 77 | _hasAtmosphere = _celestialBody.atmosphere; 78 | _hasOxygen = _celestialBody.atmosphereContainsOxygen; 79 | 80 | // Ocean 81 | _hasOcean = _celestialBody.ocean; 82 | 83 | // Homeworld 84 | _isHome = _celestialBody.isHomeWorld; 85 | 86 | // Star detection 87 | _isStar = Sun.Instance.sun == Body; 88 | 89 | // GasGiant detection 90 | _isGasGiant = !_isStar && !_hasSurface; 91 | 92 | 93 | // Moon detection + Parent 94 | _parent = null; // No parent - a star 95 | _isPlanet = _isMoon = false; 96 | if( _celestialBody.orbit != null && _celestialBody.orbit.referenceBody != null ) // Otherwise it is the sun 97 | { 98 | _parent = _celestialBody.orbit.referenceBody; 99 | if( _celestialBody.orbit.referenceBody == Sun.Instance.sun ) 100 | _isPlanet = true; 101 | else 102 | _isMoon = true; // A moon - parent isn't the sun 103 | } 104 | 105 | // Type 106 | _type = FigureOutType( ); 107 | 108 | 109 | // Progress tracking changes 110 | Update( ); 111 | } 112 | 113 | private string FigureOutType( ) 114 | { 115 | if( _isGasGiant ) 116 | return "Gas Giant"; 117 | if( _isStar ) 118 | return "Star"; 119 | if( _isPlanet ) 120 | return "Planet"; 121 | if( _isMoon ) 122 | return "Moon"; 123 | return "Unknown"; 124 | } 125 | 126 | public void Update( ) 127 | { 128 | // Reached - bit of a palaver but Body.DiscoveryInfo isn't useful 129 | _Reached = null; // Not reached yet 130 | if( _isHome ) // KSP says you have to launch your first vessel to reach the homeworld 131 | _Reached = 1; // I say the homeworld is always reached. 132 | else 133 | { 134 | // If we are here then it's reached 135 | // ProgressTracking node is slow to react. 136 | // Maybe you need to change vessels to force the save 137 | if( HighLogic.LoadedScene == GameScenes.FLIGHT ) 138 | { 139 | if( FlightGlobals.ActiveVessel.mainBody == CelestialBody ) 140 | _Reached = 1; 141 | } 142 | } 143 | 144 | 145 | 146 | // Do this whatever happened above then the "1" can be overwritten 147 | // by the real thing 148 | if( HighLogic.CurrentGame != null ) 149 | { 150 | var node = new ConfigNode( ); 151 | var Progress = HighLogic.CurrentGame.scenarios.Find( s => s.moduleName == "ProgressTracking" ); 152 | Progress.Save( node ); 153 | 154 | ConfigNode[] P = node.GetNodes( "Progress" ); 155 | if( P.Length > 0 ) 156 | { 157 | ConfigNode[] B = P[ 0 ].GetNodes( _name ); 158 | if( B.Length > 0 ) 159 | { 160 | var V = B[ 0 ].GetValue( "reached" ); 161 | if( !string.IsNullOrEmpty( V ) ) 162 | { 163 | double R; 164 | if( double.TryParse( V, out R ) ) 165 | _Reached = R; 166 | } 167 | } 168 | } 169 | } 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /X-Science/BodySituationFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | 6 | 7 | namespace ScienceChecklist 8 | { 9 | internal sealed class BodySituationFilter 10 | { 11 | // private readonly Logger _logger; 12 | 13 | 14 | public BodySituationFilter( ) 15 | { 16 | // Init 17 | // _logger = new Logger( this ); 18 | } 19 | 20 | 21 | 22 | public void Filter( List BodyList, List SituationList, String FilterString ) 23 | { 24 | List Filters = FilterString.Split( ',' ).Select( s => s.Trim( ) ).ToList( ); 25 | for( var x = 0; x < Filters.Count; x++ ) 26 | { 27 | // _logger.Trace( Filters[ x ] ); 28 | ApplyOneFilter( BodyList, SituationList, Filters[ x ] ); 29 | } 30 | } 31 | 32 | 33 | 34 | public bool TextFilter( ScienceInstance S ) 35 | { 36 | string[] Filters = CelestialBodyFilters.TextFilters.GetValues( "TEXT_FILTER" ); 37 | string Description = S.Description.ToLowerInvariant( ); 38 | 39 | 40 | 41 | for( int FilterIndex = 0; FilterIndex < Filters.Length; FilterIndex++ ) 42 | { 43 | string FilterText = Filters[ FilterIndex ]; 44 | 45 | string[] Words = FilterText.Split( ' ' ); 46 | bool WordResult = true; 47 | for( int WordIndex = 0; WordIndex < Words.Length; WordIndex++ ) 48 | { 49 | string[] Options = Words[ WordIndex ].Split( '|' ); 50 | bool OptionResult = false; 51 | for( int OptionIndex = 0; OptionIndex < Options.Length; OptionIndex++ ) 52 | { 53 | string ThisOption = Options[ OptionIndex ].ToLowerInvariant( ); 54 | var negate = false; 55 | if( ThisOption.StartsWith( "-", StringComparison.InvariantCultureIgnoreCase ) ) 56 | { 57 | negate = true; 58 | ThisOption = ThisOption.Substring( 1 ); 59 | } 60 | 61 | bool Result = ( Description.Contains( ThisOption ) == !negate ); 62 | if( Result ) 63 | { 64 | // _logger.Log( "Option: " + Description + " WITH " + ThisOption ); 65 | OptionResult = true; // Matched one of the options 66 | break; 67 | } 68 | } 69 | if( !OptionResult ) // None of the options matched, so this word is not in the description 70 | { 71 | // _logger.Log( "Word: " + Description + " Doesn't contain " + Words[ WordIndex ] ); 72 | WordResult = false; 73 | break; 74 | } 75 | } 76 | if( WordResult ) // Matched all words in a filter 77 | { 78 | // _logger.Log( "TEXT_FILTER: " + Description + " WITH " + FilterText ); 79 | return false; 80 | } 81 | 82 | } 83 | 84 | 85 | return true; 86 | } 87 | 88 | 89 | 90 | private void ApplyOneFilter( List BodyList, List SituationList, String FilterName ) 91 | { 92 | switch( FilterName ) 93 | { 94 | case "NeedsAll": 95 | // Do nuffinc! 96 | break; 97 | case "AvoidAll": 98 | BodyList.Clear( ); 99 | break; 100 | 101 | 102 | 103 | case "NeedsOxygen": 104 | BodyList.RemoveAll( x => x.HasOxygen == false ); 105 | break; 106 | case "AvoidOxygen": 107 | BodyList.RemoveAll( x => x.HasOxygen == true ); 108 | break; 109 | 110 | 111 | 112 | case "NeedsAtmosphere": 113 | BodyList.RemoveAll( x => x.HasAtmosphere == false ); 114 | break; 115 | case "AvoidAtmosphere": 116 | BodyList.RemoveAll( x => x.HasAtmosphere == true ); 117 | break; 118 | 119 | 120 | 121 | case "NeedsPlanet": 122 | BodyList.RemoveAll( x => x.IsPlanet == false ); 123 | break; 124 | case "AvoidPlanet": 125 | BodyList.RemoveAll( x => x.IsPlanet == true ); 126 | break; 127 | 128 | 129 | 130 | case "NeedsMoon": 131 | BodyList.RemoveAll( x => x.IsMoon == false ); 132 | break; 133 | case "AvoidMoon": 134 | BodyList.RemoveAll( x => x.IsMoon == true ); 135 | break; 136 | 137 | 138 | 139 | case "NeedsStar": 140 | BodyList.RemoveAll( x => x.IsStar == false ); 141 | break; 142 | case "AvoidStar": 143 | BodyList.RemoveAll( x => x.IsStar == true ); 144 | break; 145 | 146 | 147 | 148 | case "NeedsGasGiant": 149 | BodyList.RemoveAll( x => x.IsGasGiant == false ); 150 | break; 151 | case "AvoidGasGiant": 152 | BodyList.RemoveAll( x => x.IsGasGiant == true ); 153 | break; 154 | 155 | 156 | 157 | case "NeedsHomeWorld": 158 | BodyList.RemoveAll( x => x.IsHome == false ); 159 | break; 160 | case "AvoidHomeWorld": 161 | BodyList.RemoveAll( x => x.IsHome == true ); 162 | break; 163 | 164 | 165 | 166 | case "NeedsOcean": 167 | BodyList.RemoveAll( x => x.HasOcean == false ); 168 | break; 169 | case "AvoidOcean": 170 | BodyList.RemoveAll( x => x.HasOcean == true ); 171 | break; 172 | 173 | 174 | 175 | case "NeedsSurface": 176 | BodyList.RemoveAll( x => x.HasSurface == false ); 177 | break; 178 | case "AvoidSurface": 179 | BodyList.RemoveAll( x => x.HasSurface == true ); 180 | break; 181 | 182 | 183 | 184 | // --- Situation filters ------------------------------------- 185 | case "NeedsSrfLanded": 186 | SituationList.RemoveAll( x => x != ExperimentSituations.SrfLanded ); 187 | break; 188 | case "AvoidSrfLanded": 189 | SituationList.RemoveAll( x => x == ExperimentSituations.SrfLanded ); 190 | break; 191 | 192 | case "NeedsSrfSplashed": 193 | SituationList.RemoveAll( x => x != ExperimentSituations.SrfSplashed ); 194 | break; 195 | case "AvoidSrfSplashed": 196 | SituationList.RemoveAll( x => x == ExperimentSituations.SrfSplashed ); 197 | break; 198 | 199 | case "NeedsFlyingLow": 200 | SituationList.RemoveAll( x => x != ExperimentSituations.FlyingLow ); 201 | break; 202 | case "AvoidFlyingLow": 203 | SituationList.RemoveAll( x => x == ExperimentSituations.FlyingLow ); 204 | break; 205 | 206 | case "NeedsFlyingHigh": 207 | SituationList.RemoveAll( x => x != ExperimentSituations.FlyingHigh ); 208 | break; 209 | case "AvoidFlyingHigh": 210 | SituationList.RemoveAll( x => x == ExperimentSituations.FlyingHigh ); 211 | break; 212 | 213 | case "NeedsInSpaceLow": 214 | SituationList.RemoveAll( x => x != ExperimentSituations.InSpaceLow ); 215 | break; 216 | case "AvoidInSpaceLow": 217 | SituationList.RemoveAll( x => x == ExperimentSituations.InSpaceLow ); 218 | break; 219 | 220 | case "NeedsInSpaceHigh": 221 | SituationList.RemoveAll( x => x != ExperimentSituations.InSpaceHigh ); 222 | break; 223 | case "AvoidInSpaceHigh": 224 | SituationList.RemoveAll( x => x == ExperimentSituations.InSpaceHigh ); 225 | break; 226 | } 227 | } 228 | 229 | 230 | 231 | public bool DifficultScienceFilter( ScienceInstance S ) 232 | { 233 | // For stars don't show any flying situations. Block EVA in space near 'cos the Kerbals just explode 234 | if( S.Situation.Body.IsStar ) 235 | { 236 | if( S.Situation.ExperimentSituation == ExperimentSituations.FlyingHigh || S.Situation.ExperimentSituation == ExperimentSituations.FlyingLow ) 237 | return false; 238 | if( S.Situation.ExperimentSituation == ExperimentSituations.InSpaceLow && S.ScienceExperiment.id == "evaReport" ) 239 | return false; 240 | } 241 | 242 | // For gas-giants don't show any flying low. 243 | if( S.Situation.Body.IsGasGiant ) 244 | { 245 | if( S.Situation.ExperimentSituation == ExperimentSituations.FlyingLow ) 246 | return false; 247 | } 248 | 249 | // If the AstronautComplex isn't upgraded then block all non-homeworld EVA. 250 | // Also EVA on homeworld that isn't splashed or landed or flying-low. 251 | float AstroLevel = ScenarioUpgradeableFacilities.GetFacilityLevel( SpaceCenterFacility.AstronautComplex ); 252 | if( AstroLevel == 0f ) 253 | { 254 | if( S.ScienceExperiment.id == "evaReport" ) 255 | { 256 | if( S.Situation.Body.IsHome ) 257 | { 258 | if( S.Situation.ExperimentSituation == ExperimentSituations.InSpaceHigh || 259 | S.Situation.ExperimentSituation == ExperimentSituations.InSpaceLow || 260 | S.Situation.ExperimentSituation == ExperimentSituations.FlyingHigh 261 | ) 262 | return false; 263 | } 264 | else 265 | return false; 266 | } 267 | } 268 | 269 | return true; 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /X-Science/Buttons/AppLauncherButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using KSP.UI.Screens; 4 | 5 | 6 | 7 | 8 | namespace ScienceChecklist 9 | { 10 | /// 11 | /// A button that is rendered to the KSP toolbar. 12 | /// 13 | public sealed class AppLauncherButton : IToolbarButton 14 | { 15 | public Texture2D _Texture; 16 | public ApplicationLauncher.AppScenes _Visibility; 17 | 18 | 19 | /// 20 | /// Creates a new instance of the AppLauncherButton class. 21 | /// 22 | public AppLauncherButton( Texture2D Texture, ApplicationLauncher.AppScenes Visibility ) 23 | { 24 | _logger = new Logger( this ); 25 | _Texture = Texture; 26 | _Visibility = Visibility; 27 | } 28 | 29 | 30 | 31 | /// 32 | /// Called when the button is toggled on. 33 | /// 34 | public event EventHandler Open; 35 | /// 36 | /// Called when the button is toggled off. 37 | /// 38 | public event EventHandler Close; 39 | 40 | public event EventHandler RightClick; 41 | 42 | 43 | 44 | /// 45 | /// Adds the button to the KSP toolbar. 46 | /// 47 | public void Add( ) 48 | { 49 | // _logger.Trace("Add"); 50 | if (_button != null) { 51 | _logger.Debug("Button already added"); 52 | return; 53 | } 54 | 55 | 56 | 57 | // _logger.Info("Adding button"); 58 | _button = ApplicationLauncher.Instance.AddModApplication( 59 | OnToggleOn, 60 | OnToggleOff, 61 | null, 62 | null, 63 | null, 64 | null, 65 | _Visibility, 66 | _Texture); 67 | _button.onRightClick += OnRightClick; 68 | } 69 | 70 | 71 | 72 | /// 73 | /// Removes the button from the KSP toolbar. 74 | /// 75 | public void Remove () { 76 | // _logger.Trace("Remove"); 77 | if (_button == null) { 78 | _logger.Debug("Button already removed"); 79 | return; 80 | } 81 | 82 | // _logger.Info("Removing button"); 83 | ApplicationLauncher.Instance.RemoveModApplication(_button); 84 | _button = null; 85 | } 86 | 87 | 88 | 89 | public void SetOn( ) 90 | { 91 | _button.SetTrue( false ); 92 | // _logger.Debug( "SetOn" ); 93 | } 94 | public void SetOff( ) 95 | { 96 | _button.SetFalse( false ); 97 | // _logger.Debug( "SetOff" ); 98 | } 99 | 100 | public void SetEnabled( ) 101 | { 102 | // this.Log( "Launcher Button Enabled" ); 103 | _button.Enable( false ); 104 | } 105 | 106 | public void SetDisabled( ) 107 | { 108 | // this.Log( "Launcher Button Disabled" ); 109 | _button.Disable( false ); 110 | } 111 | 112 | public bool IsEnabled( ) 113 | { 114 | return _button.IsEnabled; 115 | } 116 | 117 | 118 | /// 119 | /// Called when the button is toggled on. 120 | /// 121 | private void OnToggleOn( ) 122 | { 123 | // _logger.Trace("OnToggleOn"); 124 | OnOpen( EventArgs.Empty ); 125 | } 126 | 127 | /// 128 | /// Called when the button is toggled off. 129 | /// 130 | private void OnToggleOff( ) 131 | { 132 | // _logger.Trace("OnToggleOff"); 133 | OnClose( EventArgs.Empty ); 134 | } 135 | 136 | private void OnRightClick( ) 137 | { 138 | OnRightClick( EventArgs.Empty ); 139 | } 140 | 141 | 142 | 143 | /// 144 | /// Raises the Open event. 145 | /// 146 | /// The EventArgs of this event. 147 | private void OnOpen (EventArgs e) { 148 | // _logger.Trace("OnOpen"); 149 | if (Open != null) { 150 | Open(this, e); 151 | } 152 | } 153 | 154 | /// 155 | /// Raises the Close event. 156 | /// 157 | /// The EventArgs of this event. 158 | private void OnClose (EventArgs e) { 159 | // _logger.Trace("OnClose"); 160 | if (Close != null) { 161 | Close(this, e); 162 | } 163 | } 164 | 165 | /// 166 | /// Raises the RightClick event. 167 | /// 168 | /// The EventArgs of this event. 169 | private void OnRightClick( EventArgs e ) 170 | { 171 | // _logger.Trace("OnRightClick"); 172 | if( RightClick != null ) 173 | { 174 | RightClick( this, e ); 175 | } 176 | } 177 | 178 | 179 | private ApplicationLauncherButton _button; 180 | private readonly Logger _logger; 181 | 182 | 183 | } 184 | } -------------------------------------------------------------------------------- /X-Science/Buttons/BlizzysToolbarButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using ScienceChecklist; 3 | 4 | 5 | 6 | namespace ScienceChecklist 7 | { 8 | internal sealed class BlizzysToolbarButton : IToolbarButton 9 | { 10 | private IButton _button; 11 | private bool _open; 12 | private string _Namespace; 13 | private string _ButtonId; 14 | private string _ButtonToolTip; 15 | private string _ButtonText; 16 | private string _TexturePath; 17 | private GameScenesVisibility _Visibility; 18 | private readonly Logger _logger; 19 | 20 | 21 | 22 | /// 23 | /// Creates a new instance of the BlizzysToolbarButton class. 24 | /// 25 | public BlizzysToolbarButton( string Namespace, string ButtonId, string ButtonToolTip, string ButtonText, string TexturePath, GameScenesVisibility Visibility ) 26 | { 27 | _logger = new Logger( this ); 28 | _Namespace = Namespace; 29 | _ButtonId = ButtonId; 30 | _ButtonToolTip = ButtonToolTip; 31 | _ButtonText = ButtonText; 32 | _TexturePath = TexturePath; 33 | _Visibility = Visibility; 34 | } 35 | 36 | 37 | 38 | /// 39 | /// Called when the button is toggled on. 40 | /// 41 | public event EventHandler Open; 42 | /// 43 | /// Called when the button is toggled off. 44 | /// 45 | public event EventHandler Close; 46 | 47 | /// 48 | /// Called when the button is right clicked. 49 | /// 50 | public event EventHandler RightClick; 51 | 52 | 53 | 54 | /// 55 | /// Returns whether Blizzy's toolbar is available. 56 | /// 57 | public static bool IsAvailable { get { return ToolbarManager.ToolbarAvailable; } } 58 | 59 | /// 60 | /// Adds the button to the toolbar. 61 | /// 62 | public void Add () { 63 | // _logger.Trace("Add"); 64 | if (!IsAvailable) { 65 | _logger.Info("Blizzy's toolbar not available."); 66 | return; 67 | } 68 | 69 | if (_button != null) { 70 | _logger.Info("Button already added."); 71 | return; 72 | } 73 | 74 | _button = ToolbarManager.Instance.add( _Namespace, _ButtonId ); 75 | _button.ToolTip = _ButtonToolTip; 76 | _button.Text = _ButtonText; 77 | _button.TexturePath = _TexturePath; 78 | _button.Visibility = _Visibility; 79 | _button.OnClick += OnClick; 80 | _button.Enabled = true; 81 | } 82 | 83 | /// 84 | /// Handler for the OnClick event on _button. 85 | /// 86 | /// The ClickEventArgs of the event. 87 | public void OnClick( ClickEvent e ) 88 | { 89 | /// Is 0 for left mouse button, 1 for right mouse button, and 2 for middle mouse button. 90 | if( e.MouseButton == 0 ) 91 | { 92 | _open = !_open; 93 | if( _open ) 94 | OnOpen( EventArgs.Empty ); 95 | else 96 | OnClose( EventArgs.Empty ); 97 | } 98 | else 99 | OnRightClick( EventArgs.Empty ); 100 | 101 | } 102 | 103 | /// 104 | /// Removes the button from the toolbar. 105 | /// 106 | public void Remove () { 107 | // _logger.Trace("Remove"); 108 | if (!IsAvailable) { 109 | _logger.Info("Blizzy's toolbar not available."); 110 | return; 111 | } 112 | 113 | if (_button == null) { 114 | _logger.Info("Button already removed."); 115 | return; 116 | } 117 | 118 | _button.Destroy(); 119 | _button = null; 120 | } 121 | 122 | public void SetOn( ) 123 | { 124 | _open = true; 125 | } 126 | public void SetOff( ) 127 | { 128 | _open = false; 129 | } 130 | 131 | public void SetEnabled( ) 132 | { 133 | // this.Log( "Launcher Button Enabled" ); 134 | _button.Enabled = true; 135 | } 136 | 137 | public void SetDisabled( ) 138 | { 139 | // this.Log( "Launcher Button Disabled" ); 140 | _button.Enabled = false; 141 | } 142 | public bool IsEnabled( ) 143 | { 144 | return _button.Enabled; 145 | } 146 | 147 | /// 148 | /// Raises the Open event. 149 | /// 150 | /// The EventArgs to raise. 151 | private void OnOpen (EventArgs e) { 152 | if (Open != null) { 153 | Open(this, e); 154 | } 155 | } 156 | 157 | /// 158 | /// Raises the Close event. 159 | /// 160 | /// The EventArgs to raise. 161 | private void OnClose (EventArgs e) { 162 | if (Close != null) { 163 | Close(this, e); 164 | } 165 | } 166 | 167 | /// 168 | /// Raises the RightClick event. 169 | /// 170 | /// The EventArgs to raise. 171 | private void OnRightClick( EventArgs e ) 172 | { 173 | if( RightClick != null ) 174 | RightClick( this, e ); 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /X-Science/Buttons/IToolbarButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | 4 | 5 | namespace ScienceChecklist 6 | { 7 | internal interface IToolbarButton 8 | { 9 | /// 10 | /// Called when the button is toggled on. 11 | /// 12 | event EventHandler Open; 13 | 14 | 15 | 16 | /// 17 | /// Called when the button is toggled off. 18 | /// 19 | event EventHandler Close; 20 | 21 | /// 22 | /// Called when the button is right clicked. 23 | /// 24 | event EventHandler RightClick; 25 | 26 | 27 | 28 | /// 29 | /// Adds the button to the toolbar. 30 | /// 31 | void Add( ); 32 | 33 | 34 | 35 | /// 36 | /// Removes the button from the toolbar. 37 | /// 38 | void Remove( ); 39 | 40 | 41 | 42 | /// 43 | /// Force button to on state 44 | /// 45 | void SetOn( ); 46 | 47 | 48 | /// 49 | /// Force button to off state 50 | /// 51 | void SetOff( ); 52 | 53 | void SetEnabled( ); 54 | void SetDisabled( ); 55 | 56 | bool IsEnabled( ); 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /X-Science/Buttons/UnifiedButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using KSP.UI.Screens; 4 | 5 | 6 | 7 | namespace ScienceChecklist 8 | { 9 | class UnifiedButton 10 | { 11 | // Members 12 | private IToolbarButton _button; 13 | 14 | public event EventHandler ButtonOn; 15 | public event EventHandler ButtonOff; 16 | public event EventHandler RightClick; 17 | 18 | public bool UseBlizzyIfPossible; 19 | 20 | public Texture2D LauncherTexture; 21 | public ApplicationLauncher.AppScenes LauncherVisibility; 22 | 23 | 24 | public string BlizzyNamespace; 25 | public string BlizzyButtonId; 26 | public string BlizzyTexturePath; 27 | public GameScenesVisibility BlizzyVisibility; 28 | public string BlizzyToolTip; 29 | public string BlizzyText; 30 | private readonly Logger _logger; 31 | 32 | 33 | 34 | // Constructor 35 | public UnifiedButton( ) 36 | { 37 | _logger = new Logger( this ); 38 | // _logger.Info( "Made a button" ); 39 | } 40 | 41 | public void Add( ) 42 | { 43 | // _logger.Info( "Add" ); 44 | InitializeButton( ); 45 | } 46 | public void Remove( ) 47 | { 48 | // _logger.Info( "Remove" ); 49 | if( _button != null ) 50 | { 51 | _button.Open -= OnButtonOn; 52 | _button.Close -= OnButtonOff; 53 | _button.RightClick -= OnRightClick; 54 | _button.Remove( ); 55 | _button = null; 56 | } 57 | } 58 | /// 59 | /// Force button to on state 60 | /// 61 | public void SetOn( ) 62 | { 63 | _button.SetOn( ); 64 | } 65 | 66 | /// 67 | /// Force button to off state 68 | /// 69 | public void SetOff( ) 70 | { 71 | _button.SetOff( ); 72 | } 73 | 74 | /// 75 | /// Force button to enabled state 76 | /// 77 | public void SetEnabled( ) 78 | { 79 | _button.SetEnabled( ); 80 | // this.Log( "Enabled" ); 81 | } 82 | 83 | /// 84 | /// Force button to disabled state 85 | /// 86 | public void SetDisabled( ) 87 | { 88 | _button.SetDisabled( ); 89 | // this.Log( "Disabled" ); 90 | } 91 | 92 | public bool IsEnabled( ) 93 | { 94 | return _button.IsEnabled( ); 95 | } 96 | 97 | 98 | private void InitializeButton( ) 99 | { 100 | // _logger.Info( "InitializeButton" ); 101 | if( _button != null ) 102 | Remove( ); 103 | 104 | if( UseBlizzyIfPossible && BlizzysToolbarButton.IsAvailable ) 105 | _button = new BlizzysToolbarButton 106 | ( 107 | BlizzyNamespace, BlizzyButtonId, BlizzyToolTip, BlizzyText, BlizzyTexturePath, BlizzyVisibility 108 | ); 109 | else 110 | _button = new AppLauncherButton( LauncherTexture, LauncherVisibility ); 111 | 112 | _button.Open += OnButtonOn; 113 | _button.Close += OnButtonOff; 114 | _button.RightClick += OnRightClick; 115 | _button.Add( ); 116 | } 117 | 118 | 119 | 120 | private void OnButtonOn( object sender, EventArgs e ) 121 | { 122 | // _logger.Info( "Button_Open" ); 123 | if( ButtonOn != null ) 124 | ButtonOn( this, e ); 125 | } 126 | 127 | 128 | 129 | private void OnButtonOff( object sender, EventArgs e ) 130 | { 131 | // _logger.Info( "Button_Close" ); 132 | if( ButtonOff != null ) 133 | ButtonOff( this, e ); 134 | } 135 | 136 | private void OnRightClick( object sender, EventArgs e ) 137 | { 138 | if( RightClick != null ) 139 | RightClick( this, e ); 140 | } 141 | 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /X-Science/CelestialBodyFilters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | 5 | 6 | 7 | /* 8 | * THIS IS A STATIC CLASS 9 | */ 10 | 11 | 12 | 13 | namespace ScienceChecklist 14 | { 15 | internal static class CelestialBodyFilters 16 | { 17 | private static readonly Logger _logger = new Logger( "CelestialBodyFilters" ); 18 | public static ConfigNode Filters { get; set; } 19 | public static ConfigNode TextFilters { get; set; } 20 | static CelestialBodyFilters( ) 21 | { 22 | Load( ); 23 | } 24 | 25 | 26 | 27 | public static void Load( ) 28 | { 29 | try 30 | { 31 | string assemblyPath = Path.GetDirectoryName( typeof( ScienceChecklistAddon ).Assembly.Location ); 32 | string filePath = Path.Combine( assemblyPath, "science.cfg" ); 33 | 34 | // _logger.Trace( "Loading settings file:" + filePath ); 35 | if( File.Exists( filePath ) ) 36 | { 37 | var node = ConfigNode.Load( filePath ); 38 | var root = node.GetNode( "ScienceChecklist" ); 39 | Filters = root.GetNode( "CelestialBodyFilters" ); 40 | TextFilters = root.GetNode( "TextFilters" ); 41 | } 42 | // _logger.Trace( "DONE Loading settings file" ); 43 | } 44 | catch( Exception e ) 45 | { 46 | _logger.Info( "Unable to load filters: " + e.ToString( ) ); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /X-Science/Config.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | 5 | 6 | 7 | namespace ScienceChecklist { 8 | public sealed class Config 9 | { 10 | // Locals 11 | private readonly Logger _logger; 12 | private readonly string _assemblyPath = Path.GetDirectoryName( typeof( ScienceChecklistAddon ).Assembly.Location ); 13 | private readonly string _file = KSP.IO.IOUtils.GetFilePathFor( typeof( ScienceChecklistAddon ), "settings.cfg" ); 14 | private Dictionary> _windowSettings = new Dictionary>( ); 15 | 16 | private bool _hideCompleteExperiments; 17 | private bool _useBlizzysToolbar; 18 | private bool _completeWithoutRecovery; 19 | private bool _checkDebris; 20 | private bool _allFilter; 21 | private bool _stopTimeWarp; 22 | private bool _playNoise; 23 | private bool _showResultsWindow; 24 | private bool _filterDifficultScience; 25 | private float _uiScale; 26 | private bool _musicStartsMuted; 27 | private bool _righClickMutesMusic; 28 | private bool _selectedObjectWindow; 29 | 30 | 31 | 32 | // Members 33 | public bool HideCompleteExperiments { get { return _hideCompleteExperiments; } set { if( _hideCompleteExperiments != value ) { _hideCompleteExperiments = value; OnHideCompleteEventsChanged( ); } } } 34 | public bool UseBlizzysToolbar { get { return _useBlizzysToolbar; } set { if( _useBlizzysToolbar != value ) { _useBlizzysToolbar = value; OnUseBlizzysToolbarChanged( ); } } } 35 | public bool CompleteWithoutRecovery { get { return _completeWithoutRecovery; } set { if( _completeWithoutRecovery != value ) { _completeWithoutRecovery = value; OnCompleteWithoutRecoveryChanged( ); } } } 36 | public bool CheckDebris { get { return _checkDebris; } set { if( _checkDebris != value ) { _checkDebris = value; OnCheckDebrisChanged( ); } } } 37 | public bool AllFilter { get { return _allFilter; } set { if( _allFilter != value ) { _allFilter = value; OnAllFilterChanged( ); } } } 38 | public bool StopTimeWarp { get { return _stopTimeWarp; } set { if( _stopTimeWarp != value ) { _stopTimeWarp = value; OnStopTimeWarpChanged( ); } } } 39 | public bool PlayNoise { get { return _playNoise; } set { if( _playNoise != value ) { _playNoise = value; OnPlayNoiseChanged( ); } } } 40 | public bool ShowResultsWindow { get { return _showResultsWindow; } set { if( _showResultsWindow != value ) { _showResultsWindow = value; OnShowResultsWindowChanged( ); } } } 41 | public bool FilterDifficultScience { get { return _filterDifficultScience; } set { if( _filterDifficultScience != value ) { _filterDifficultScience = value; OnFilterDifficultScienceChanged( ); } } } 42 | public float UiScale { get { return _uiScale; } set { if (_uiScale != value) { _uiScale = value; OnUiScaleChanged(); } } } 43 | public bool MusicStartsMuted { get { return _musicStartsMuted; } set { if( _musicStartsMuted != value ) { _musicStartsMuted = value; OnMusicStartsMutedChanged( ); } } } 44 | public bool RighClickMutesMusic { get { return _righClickMutesMusic; } 45 | set { 46 | if( _righClickMutesMusic != value ) 47 | { 48 | _righClickMutesMusic = value; 49 | OnRighClickMutesMusicChanged( ); 50 | if( _righClickMutesMusic == false ) 51 | { 52 | if( _musicStartsMuted == true ) 53 | { 54 | _musicStartsMuted = false; 55 | OnMusicStartsMutedChanged( ); 56 | } 57 | } 58 | } 59 | } 60 | } 61 | public bool SelectedObjectWindow { get { return _selectedObjectWindow; } set { if( _selectedObjectWindow != value ) { _selectedObjectWindow = value; OnSelectedObjectWindowChanged( ); } } } 62 | 63 | 64 | 65 | // Get notified when settings change 66 | public event EventHandler UseBlizzysToolbarChanged; 67 | public event EventHandler HideCompleteEventsChanged; 68 | public event EventHandler CompleteWithoutRecoveryChanged; 69 | public event EventHandler CheckDebrisChanged; 70 | public event EventHandler AllFilterChanged; 71 | public event EventHandler StopTimeWarpChanged; 72 | public event EventHandler PlayNoiseChanged; 73 | public event EventHandler ShowResultsWindowChanged; 74 | public event EventHandler FilterDifficultScienceChanged; 75 | public event EventHandler UiScaleChanged; 76 | public event EventHandler MusicStartsMutedChanged; 77 | public event EventHandler RighClickMutesMusicChanged; 78 | public event EventHandler SelectedObjectWindowChanged; 79 | 80 | 81 | 82 | // For triggering events 83 | private void OnUseBlizzysToolbarChanged( ) 84 | { 85 | if( UseBlizzysToolbarChanged != null ) 86 | { 87 | UseBlizzysToolbarChanged( this, EventArgs.Empty ); 88 | } 89 | } 90 | 91 | private void OnHideCompleteEventsChanged( ) 92 | { 93 | if( HideCompleteEventsChanged != null ) 94 | { 95 | HideCompleteEventsChanged( this, EventArgs.Empty ); 96 | } 97 | } 98 | 99 | private void OnCompleteWithoutRecoveryChanged( ) 100 | { 101 | if( CompleteWithoutRecoveryChanged != null ) 102 | { 103 | CompleteWithoutRecoveryChanged( this, EventArgs.Empty ); 104 | } 105 | } 106 | 107 | private void OnCheckDebrisChanged( ) 108 | { 109 | if( CheckDebrisChanged != null ) 110 | { 111 | CheckDebrisChanged( this, EventArgs.Empty ); 112 | } 113 | } 114 | 115 | private void OnAllFilterChanged( ) 116 | { 117 | if( AllFilterChanged != null ) 118 | { 119 | AllFilterChanged( this, EventArgs.Empty ); 120 | } 121 | } 122 | 123 | private void OnStopTimeWarpChanged( ) 124 | { 125 | if( StopTimeWarpChanged != null ) 126 | { 127 | StopTimeWarpChanged( this, EventArgs.Empty ); 128 | } 129 | } 130 | 131 | private void OnPlayNoiseChanged( ) 132 | { 133 | if( PlayNoiseChanged != null ) 134 | { 135 | PlayNoiseChanged( this, EventArgs.Empty ); 136 | } 137 | } 138 | 139 | private void OnShowResultsWindowChanged( ) 140 | { 141 | if( ShowResultsWindowChanged != null ) 142 | { 143 | ShowResultsWindowChanged( this, EventArgs.Empty ); 144 | } 145 | } 146 | 147 | private void OnFilterDifficultScienceChanged( ) 148 | { 149 | if( FilterDifficultScienceChanged != null ) 150 | { 151 | FilterDifficultScienceChanged( this, EventArgs.Empty ); 152 | } 153 | } 154 | 155 | private void OnUiScaleChanged( ) 156 | { 157 | if( UiScaleChanged != null ) 158 | { 159 | UiScaleChanged(this, EventArgs.Empty); 160 | } 161 | } 162 | 163 | private void OnMusicStartsMutedChanged( ) 164 | { 165 | if( MusicStartsMutedChanged != null ) 166 | { 167 | MusicStartsMutedChanged( this, EventArgs.Empty ); 168 | } 169 | } 170 | 171 | private void OnRighClickMutesMusicChanged( ) 172 | { 173 | if( RighClickMutesMusicChanged != null ) 174 | { 175 | RighClickMutesMusicChanged( this, EventArgs.Empty ); 176 | } 177 | } 178 | 179 | private void OnSelectedObjectWindowChanged( ) 180 | { 181 | if( SelectedObjectWindowChanged != null ) 182 | { 183 | SelectedObjectWindowChanged( this, EventArgs.Empty ); 184 | } 185 | } 186 | 187 | public Config( ) 188 | { 189 | _logger = new Logger( this ); 190 | } 191 | 192 | 193 | 194 | public WindowSettings GetWindowConfig( string Name, GameScenes Scene ) 195 | { 196 | WindowSettings W = null; 197 | 198 | // _logger.Trace( "Getting " + Name + " For " + Scene.ToString( ) ); 199 | 200 | if( _windowSettings.ContainsKey( Scene ) ) 201 | { 202 | if( _windowSettings[ Scene ].ContainsKey( Name ) ) 203 | W = _windowSettings[ Scene ][ Name ]; 204 | } 205 | 206 | if( W == null ) 207 | W = new WindowSettings( Name ); 208 | W.TestPosition( ); 209 | 210 | /* bool TempVisible = false; 211 | TempVisible = W.GetBool( "Visible", false ); 212 | if( TempVisible ) 213 | _logger.Info( Scene.ToString( ) + " Window Open" ); 214 | else 215 | _logger.Info( Scene.ToString( ) + " Window Closed" ); 216 | */ 217 | return W; 218 | } 219 | 220 | 221 | 222 | public void SetWindowConfig( WindowSettings W ) 223 | { 224 | W.TestPosition( ); 225 | 226 | 227 | 228 | // Write 229 | if( !_windowSettings.ContainsKey( W._scene ) ) 230 | _windowSettings.Add( W._scene, new Dictionary( ) ); 231 | _windowSettings[ W._scene ][ W._windowName ] = W; 232 | 233 | 234 | // _logger.Trace( "Setting " + W._windowName + " For " + W._scene.ToString( ) ); 235 | 236 | 237 | /* bool TempVisible = false; 238 | TempVisible = W.GetBool( "Visible", false ); 239 | if( TempVisible ) 240 | _logger.Info( "visible" ); 241 | else 242 | _logger.Info( "closed!" ); 243 | */ 244 | Save( ); 245 | } 246 | 247 | 248 | 249 | public void Save( ) 250 | { 251 | // _logger.Trace( "Save" ); 252 | var node = new ConfigNode( ); 253 | var root = node.AddNode( "ScienceChecklist" ); 254 | var settings = root.AddNode( "Config" ); 255 | var windowSettings = root.AddNode( "Windows" ); 256 | 257 | 258 | 259 | settings.AddValue( "HideCompleteExperiments", _hideCompleteExperiments ); 260 | settings.AddValue( "UseBlizzysToolbar", _useBlizzysToolbar ); 261 | settings.AddValue( "CompleteWithoutRecovery", _completeWithoutRecovery ); 262 | settings.AddValue( "CheckDebris", _checkDebris ); 263 | settings.AddValue( "AllFilter", _allFilter ); 264 | settings.AddValue( "StopTimeWarp", _stopTimeWarp ); 265 | settings.AddValue( "PlayNoise", _playNoise ); 266 | settings.AddValue( "ShowResultsWindow", _showResultsWindow ); 267 | settings.AddValue( "FilterDifficultScience", _filterDifficultScience ); 268 | settings.AddValue( "UiScale", _uiScale ); 269 | settings.AddValue( "MusicStartsMuted", _musicStartsMuted ); 270 | settings.AddValue( "RighClickMutesMusic", _righClickMutesMusic ); 271 | settings.AddValue( "SelectedObjectWindow", _selectedObjectWindow ); 272 | 273 | 274 | 275 | foreach( var V in _windowSettings ) 276 | { 277 | var SceneNode = windowSettings.AddNode( V.Key.ToString( ) ); 278 | foreach( var W in V.Value ) 279 | { 280 | var WindowNode = SceneNode.AddNode( W.Key ); 281 | foreach( var S in W.Value._settings ) 282 | { 283 | WindowNode.AddValue( S.Key, S.Value ); 284 | } 285 | } 286 | } 287 | 288 | 289 | 290 | // _logger.Trace( "Saving to" + _file ); 291 | node.Save( _file ); 292 | } 293 | 294 | 295 | 296 | public void Load( ) 297 | { 298 | _hideCompleteExperiments = false; 299 | _useBlizzysToolbar = false; 300 | _completeWithoutRecovery = false; 301 | _checkDebris = false; 302 | _allFilter = true; 303 | _stopTimeWarp = true; 304 | _playNoise = true; 305 | _showResultsWindow = true; 306 | _filterDifficultScience = true; 307 | _uiScale = 1f; 308 | _musicStartsMuted = false; 309 | _righClickMutesMusic = true; 310 | _selectedObjectWindow = true; 311 | 312 | 313 | 314 | try 315 | { 316 | if( File.Exists( _file ) ) 317 | { 318 | var node = ConfigNode.Load( _file ); 319 | if( node == null ) return; 320 | var root = node.GetNode( "ScienceChecklist" ); 321 | if( root == null ) return; 322 | var settings = root.GetNode( "Config" ); 323 | if( settings == null ) return; 324 | 325 | 326 | 327 | var V = settings.GetValue( "HideCompleteExperiments" ); 328 | if( V != null ) 329 | _hideCompleteExperiments = bool.Parse( V ); 330 | 331 | V = settings.GetValue( "UseBlizzysToolbar" ); 332 | if( V != null ) 333 | _useBlizzysToolbar = bool.Parse( V ); 334 | 335 | V = settings.GetValue( "CompleteWithoutRecovery" ); 336 | if( V != null ) 337 | _completeWithoutRecovery = bool.Parse( V ); 338 | 339 | V = settings.GetValue( "CheckDebris" ); 340 | if( V != null ) 341 | _checkDebris = bool.Parse( V ); 342 | 343 | V = settings.GetValue( "AllFilter" ); 344 | if( V != null ) 345 | _allFilter = bool.Parse( V ); 346 | 347 | V = settings.GetValue( "StopTimeWarp" ); 348 | if( V != null ) 349 | _stopTimeWarp = bool.Parse( V ); 350 | 351 | V = settings.GetValue( "PlayNoise" ); 352 | if( V != null ) 353 | _playNoise = bool.Parse( V ); 354 | 355 | V = settings.GetValue( "ShowResultsWindow" ); 356 | if( V != null ) 357 | _showResultsWindow = bool.Parse( V ); 358 | 359 | V = settings.GetValue( "FilterDifficultScience" ); 360 | if( V != null ) 361 | _filterDifficultScience = bool.Parse( V ); 362 | 363 | V = settings.GetValue( "UiScale" ); 364 | if (V != null) 365 | _uiScale = float.Parse(V); 366 | 367 | V = settings.GetValue( "MusicStartsMuted" ); 368 | if( V != null ) 369 | _musicStartsMuted = bool.Parse( V ); 370 | 371 | V = settings.GetValue( "RighClickMutesMusic" ); 372 | if( V != null ) 373 | _righClickMutesMusic = bool.Parse( V ); 374 | 375 | V = settings.GetValue( "SelectedObjectWindow" ); 376 | if( V != null ) 377 | _selectedObjectWindow = bool.Parse( V ); 378 | 379 | 380 | 381 | var windowSettings = root.GetNode( "Windows" ); 382 | if( windowSettings == null ) return; 383 | foreach( var N in windowSettings.nodes ) 384 | { 385 | // _logger.Trace( "Window Node" ); 386 | if( N.GetType( ) == typeof( ConfigNode ) ) 387 | { 388 | ConfigNode SceneNode = (ConfigNode)N; 389 | GameScenes Scene = (GameScenes)Enum.Parse( typeof( GameScenes ), SceneNode.name, true ); 390 | 391 | if( !_windowSettings.ContainsKey( Scene ) ) 392 | _windowSettings.Add( Scene, new Dictionary( ) ); 393 | 394 | foreach( var W in SceneNode.nodes ) 395 | { 396 | if( W.GetType( ) == typeof( ConfigNode ) ) 397 | { 398 | ConfigNode WindowNode = (ConfigNode)W; 399 | string WindowName = WindowNode.name; 400 | 401 | // _logger.Trace( "Loading " + WindowName + " For " + Scene.ToString( ) ); 402 | 403 | WindowSettings NewWindowSetting = new WindowSettings( WindowName ); 404 | 405 | 406 | for( int x = 0; x < WindowNode.CountValues; x++ ) 407 | { 408 | NewWindowSetting._settings[ WindowNode.values[ x ].name ] = WindowNode.values[ x ].value; 409 | } 410 | 411 | 412 | _windowSettings[ Scene ][ NewWindowSetting._windowName ] = NewWindowSetting; 413 | } 414 | } 415 | } 416 | } 417 | 418 | // _logger.Info( "Loaded successfully." ); 419 | return; // <--- Return from here -------------------------------------- 420 | } 421 | } 422 | catch( Exception e ) 423 | { 424 | _logger.Info( "Unable to load config: " + e.ToString( ) ); 425 | } 426 | } 427 | 428 | } 429 | } 430 | -------------------------------------------------------------------------------- /X-Science/DMagic.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | 5 | 6 | namespace ScienceChecklist 7 | { 8 | /// 9 | /// Class to access the DMagic API via reflection so we don't have to recompile when the DMagic mod updates. If the DMagic API changes, we will need to modify this code. 10 | /// 11 | 12 | 13 | 14 | public class DMagicFactory 15 | { 16 | // private readonly Logger _logger; 17 | private bool _isInstalled; 18 | private Type _tDMModuleScienceAnimate; 19 | private Type _tDMModuleScienceAnimateGeneric; 20 | private Type _tDMBasicScienceModule; 21 | private Type _tDMAPI; 22 | 23 | private DMAPI _DMAPI; 24 | private DMModuleScienceAnimateGeneric _DMModuleScienceAnimateGeneric; 25 | 26 | 27 | 28 | public DMagicFactory( ) 29 | { 30 | // _logger = new Logger( this ); 31 | // _logger.Trace( "DMagic API Start" ); 32 | _isInstalled = false; 33 | 34 | 35 | 36 | _tDMAPI = getType( "DMagic.DMAPI" ); 37 | _tDMModuleScienceAnimate = getType( "DMagic.Part_Modules.DMModuleScienceAnimate" ); 38 | _tDMModuleScienceAnimateGeneric = getType( "DMagic.Part_Modules.DMModuleScienceAnimateGeneric" ); 39 | _tDMBasicScienceModule = getType( "DMagic.Part_Modules.DMBasicScienceModule" ); 40 | 41 | 42 | 43 | if( _tDMAPI != null ) 44 | { 45 | // _logger.Trace( "DMAPI Available" ); 46 | _isInstalled = true; 47 | _DMAPI = new DMAPI( _tDMAPI ); 48 | } 49 | 50 | /* if( _tDMModuleScienceAnimate != null ) // Don't actually seem to be using this one 51 | _logger.Trace( "DMModuleScienceAnimate Available" ); 52 | */ 53 | if( _tDMModuleScienceAnimateGeneric != null ) 54 | { 55 | // _logger.Trace( "DMModuleScienceAnimateGeneric Available" ); 56 | _isInstalled = true; 57 | _DMModuleScienceAnimateGeneric = new DMModuleScienceAnimateGeneric( _tDMModuleScienceAnimateGeneric ); 58 | } 59 | 60 | /* if( _tDMBasicScienceModule != null ) // Don't actually seem to be using this one 61 | _logger.Trace( "DMBasicScienceModule Available" ); 62 | 63 | if( _isInstalled ) 64 | _logger.Trace( "DMagic API Installed" ); 65 | else 66 | _logger.Trace( "DMagic API Not Found" ); 67 | */ 68 | } 69 | 70 | 71 | 72 | internal static Type getType( string name ) 73 | { 74 | Type type = null; 75 | AssemblyLoader.loadedAssemblies.TypeOperation( t => { 76 | if( t.FullName == name ) 77 | { 78 | type = t; 79 | } 80 | }); 81 | return type; 82 | } 83 | 84 | 85 | 86 | public bool inheritsFromOrIsDMModuleScienceAnimate( object o ) 87 | { 88 | if( _tDMModuleScienceAnimate == null ) 89 | return false; 90 | return ((o.GetType().IsSubclassOf(_tDMModuleScienceAnimate) || o.GetType() == _tDMModuleScienceAnimate)); 91 | } 92 | 93 | 94 | 95 | public bool inheritsFromOrIsDMModuleScienceAnimateGeneric( object o ) 96 | { 97 | if( _tDMModuleScienceAnimateGeneric == null ) 98 | return false; 99 | return ((o.GetType().IsSubclassOf(_tDMModuleScienceAnimateGeneric) || o.GetType() == _tDMModuleScienceAnimateGeneric)); 100 | } 101 | 102 | 103 | 104 | public bool inheritsFromOrIsDMBasicScienceModule( object o ) 105 | { 106 | if( _tDMBasicScienceModule == null ) 107 | return false; 108 | return ((o.GetType().IsSubclassOf(_tDMBasicScienceModule) || o.GetType() == _tDMBasicScienceModule)); 109 | } 110 | 111 | 112 | 113 | public DMAPI GetDMAPI( ) 114 | { 115 | if( _DMAPI != null ) 116 | return _DMAPI; 117 | return null; 118 | } 119 | 120 | 121 | 122 | public DMModuleScienceAnimateGeneric GetDMModuleScienceAnimateGeneric( ) 123 | { 124 | if( _DMModuleScienceAnimateGeneric != null ) 125 | return _DMModuleScienceAnimateGeneric; 126 | return null; 127 | } 128 | } 129 | 130 | 131 | 132 | 133 | // Wrapper for DMagic API 134 | public class DMAPI 135 | { 136 | private MethodInfo _MIexperimentCanConduct; 137 | private MethodInfo _MIdeployDMExperiment; 138 | private MethodInfo _MIgetExperimentSituation; 139 | private MethodInfo _MIgetBiome; 140 | private readonly Logger _logger; 141 | 142 | 143 | 144 | public DMAPI( Type tDMAPI ) 145 | { 146 | _logger = new Logger( this ); 147 | 148 | 149 | 150 | 151 | // _logger.Trace( "DMagic API found. Validating Methods." ); 152 | ParameterInfo[] p; 153 | 154 | _MIexperimentCanConduct = tDMAPI.GetMethod( "experimentCanConduct", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy ); 155 | p = _MIexperimentCanConduct.GetParameters(); 156 | if (!((p.Length == 1) && (p[0].ParameterType == typeof(IScienceDataContainer)) && _MIexperimentCanConduct.ReturnType == typeof(bool))) 157 | { 158 | _logger.Info( "DMAPI.experimentCanConduct method signature has changed. [x] Science may not work for DMagic experiments" ); 159 | _MIexperimentCanConduct = null; 160 | } 161 | 162 | 163 | 164 | _MIdeployDMExperiment = tDMAPI.GetMethod("deployDMExperiment", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); 165 | p = _MIdeployDMExperiment.GetParameters(); 166 | if (!((p.Length == 2) && (p[0].ParameterType == typeof(IScienceDataContainer)) && (p[1].ParameterType == typeof(bool)) && _MIdeployDMExperiment.ReturnType == typeof(bool))) 167 | { 168 | _logger.Info( "DMAPI.deployDMExperiment method signature has changed. [x] Science may not work for DMagic experiments" ); 169 | _MIdeployDMExperiment = null; 170 | } 171 | 172 | 173 | 174 | _MIgetExperimentSituation = tDMAPI.GetMethod("getExperimentSituation", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); 175 | p = _MIgetExperimentSituation.GetParameters(); 176 | if (!((p.Length == 1) && (p[0].ParameterType == typeof(ModuleScienceExperiment)) && _MIgetExperimentSituation.ReturnType == typeof(ExperimentSituations))) 177 | { 178 | _logger.Info( "DMAPI.getExperimentSituation method signature has changed. [x] Science may not work for DMagic experiments" ); 179 | _MIgetExperimentSituation = null; 180 | } 181 | 182 | 183 | 184 | _MIgetBiome = tDMAPI.GetMethod("getBiome", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy); 185 | p = _MIgetBiome.GetParameters(); 186 | if (!((p.Length == 2) && (p[0].ParameterType == typeof(ModuleScienceExperiment)) && (p[1].ParameterType == typeof(ExperimentSituations)) && _MIgetBiome.ReturnType == typeof(string))) 187 | { 188 | _logger.Info( "DMAPI.getBiome method signature has changed. [x] Science may not work for DMagic experiments" ); 189 | _MIgetBiome = null; 190 | } 191 | 192 | } 193 | 194 | 195 | 196 | public bool experimentCanConduct(IScienceDataContainer isc) 197 | { 198 | if (_MIexperimentCanConduct == null) 199 | return false; 200 | return (bool)_MIexperimentCanConduct.Invoke(null, new object[] { isc }); 201 | } 202 | 203 | 204 | 205 | public bool deployDMExperiment(IScienceDataContainer isc, bool HideResultsWindow ) 206 | { 207 | if (_MIdeployDMExperiment == null) 208 | return false; 209 | return (bool)_MIdeployDMExperiment.Invoke(null, new object[] { isc, HideResultsWindow }); 210 | } 211 | 212 | 213 | 214 | public ExperimentSituations getExperimentSituation(ModuleScienceExperiment mse) 215 | { 216 | if (_MIgetExperimentSituation == null) 217 | return ExperimentSituations.InSpaceHigh; 218 | return (ExperimentSituations)_MIgetExperimentSituation.Invoke(null, new object[] { mse }); 219 | } 220 | 221 | 222 | 223 | public string getBiome(ModuleScienceExperiment mse, ExperimentSituations sit) 224 | { 225 | if (_MIgetBiome == null) 226 | return ""; 227 | return (string)_MIgetBiome.Invoke(null, new object[] { mse, sit }); 228 | } 229 | } 230 | 231 | 232 | 233 | // Wrapper for DMagic new API 234 | public class DMModuleScienceAnimateGeneric 235 | { 236 | private MethodInfo _MIcanConduct; 237 | private MethodInfo _MIgatherScienceData; 238 | private MethodInfo _MIgetSituation; 239 | private MethodInfo _MIgetBiome; 240 | private readonly Logger _logger; 241 | private Type _tDMModuleScienceAnimateGeneric; 242 | 243 | 244 | 245 | public DMModuleScienceAnimateGeneric( Type tDMModuleScienceAnimateGeneric ) 246 | { 247 | _logger = new Logger( this ); 248 | _tDMModuleScienceAnimateGeneric = tDMModuleScienceAnimateGeneric; 249 | 250 | 251 | 252 | if( _tDMModuleScienceAnimateGeneric != null ) 253 | { 254 | // _logger.Trace( "DMModuleScienceAnimateGeneric found. Validating Methods." ); 255 | ParameterInfo[] p; 256 | 257 | _MIcanConduct = _tDMModuleScienceAnimateGeneric.GetMethod("canConduct", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); 258 | p = _MIcanConduct.GetParameters(); 259 | if (!((p.Length == 0) && _MIcanConduct.ReturnType == typeof(bool))) 260 | { 261 | _logger.Info( "DMModuleScienceAnimateGeneric.canConduct method signature has changed. [x] Science may not work for DMModuleScienceAnimateGeneric experiments" ); 262 | _MIcanConduct = null; 263 | } 264 | 265 | _MIgatherScienceData = _tDMModuleScienceAnimateGeneric.GetMethod("gatherScienceData", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); 266 | p = _MIgatherScienceData.GetParameters(); 267 | if (!((p.Length == 1) && (p[0].ParameterType == typeof(bool)) && _MIgatherScienceData.ReturnType == typeof(void))) 268 | { 269 | _logger.Info( "DMModuleScienceAnimateGeneric.gatherScienceData method signature has changed. [x] Science may not work for DMModuleScienceAnimateGeneric experiments" ); 270 | _MIgatherScienceData = null; 271 | } 272 | 273 | _MIgetSituation = _tDMModuleScienceAnimateGeneric.GetMethod("getSituation", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); 274 | p = _MIgetSituation.GetParameters(); 275 | if (!((p.Length == 0) && _MIgetSituation.ReturnType == typeof(ExperimentSituations))) 276 | { 277 | _logger.Info( "DMModuleScienceAnimateGeneric.getSituation method signature has changed. [x] Science may not work for DMModuleScienceAnimateGeneric experiments" ); 278 | _MIgetSituation = null; 279 | } 280 | 281 | _MIgetBiome = _tDMModuleScienceAnimateGeneric.GetMethod("getBiome", BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); 282 | p = _MIgetBiome.GetParameters(); 283 | if (!((p.Length == 1) && (p[0].ParameterType == typeof(ExperimentSituations)) && _MIgetBiome.ReturnType == typeof(string))) 284 | { 285 | _logger.Info( "DMModuleScienceAnimateGeneric.getSituation method signature has changed. [x] Science may not work for DMModuleScienceAnimateGeneric experiments" ); 286 | _MIgetBiome = null; 287 | } 288 | } 289 | } 290 | 291 | 292 | 293 | public bool canConduct(ModuleScienceExperiment mse) 294 | { 295 | if (_MIcanConduct == null) 296 | return false; 297 | return (bool)_MIcanConduct.Invoke(mse, new object[] { }); 298 | } 299 | 300 | 301 | 302 | public void gatherScienceData( ModuleScienceExperiment mse, bool HideResultsWindow ) 303 | { 304 | if (_MIgatherScienceData == null) return; 305 | _MIgatherScienceData.Invoke(mse, new object[] { HideResultsWindow }); 306 | } 307 | 308 | 309 | 310 | public ExperimentSituations getSituation(ModuleScienceExperiment mse) 311 | { 312 | if (_MIgetSituation == null) 313 | return ExperimentSituations.InSpaceHigh; 314 | return (ExperimentSituations)_MIgetSituation.Invoke(mse, new object[] { }); 315 | } 316 | 317 | 318 | 319 | public string getBiome(ModuleScienceExperiment mse, ExperimentSituations sit) 320 | { 321 | if (_MIgetBiome == null) 322 | return ""; 323 | return (string)_MIgetBiome.Invoke(mse, new object[] { sit }); 324 | } 325 | } 326 | } -------------------------------------------------------------------------------- /X-Science/DisplayMode.cs: -------------------------------------------------------------------------------- 1 |  2 | 3 | namespace ScienceChecklist { 4 | /// 5 | /// Enum to control which experiments should be displayed in the ScienceWindow. 6 | /// 7 | public enum DisplayMode { 8 | /// 9 | /// Only show experiments that can be performed in the current situation. 10 | /// 11 | CurrentSituation = 0, 12 | /// 13 | /// Only show experiments that can be performed on the active vessel. 14 | /// 15 | ActiveVessel = 1, 16 | /// 17 | /// Only show experiments that have been unlocked in the tech tree. 18 | /// 19 | Unlocked = 2, 20 | /// 21 | /// Show all experiments. 22 | /// 23 | All = 3, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /X-Science/ExperimentFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | 6 | 7 | namespace ScienceChecklist { 8 | /// 9 | /// Stores a cache of experiments available in the game, and provides methods to manipulate a filtered view of this collection. 10 | /// 11 | internal sealed class ExperimentFilter { 12 | private ScienceChecklistAddon _parent; 13 | private DisplayMode _displayMode; 14 | private string _text; 15 | private Situation _situation; 16 | // private readonly Logger _logger; 17 | 18 | 19 | 20 | /// 21 | /// Creates a new instance of the ExperimentFilter class. 22 | /// 23 | public ExperimentFilter( ScienceChecklistAddon Parent ) 24 | { 25 | _parent = Parent; 26 | // _logger = new Logger(this); 27 | _displayMode = DisplayMode.Unlocked; 28 | _text = string.Empty; 29 | DisplayScienceInstances = new List( ); 30 | CompleteCount = TotalCount = 0; 31 | EnforceLabLanderMode = false; 32 | TotalScience = CompletedScience = OutstandingScience = 0; 33 | } 34 | 35 | 36 | /// 37 | /// Gets the experiments that should currently be displayed in the experiment list. 38 | /// 39 | public IList DisplayScienceInstances { get; private set; } 40 | /// 41 | /// Gets the number of display experiments that are complete. 42 | /// 43 | public int CompleteCount { get; private set; } 44 | public bool EnforceLabLanderMode { get; set; } 45 | /// 46 | /// Gets the total number of display experiments. 47 | /// 48 | public int TotalCount { get; private set; } 49 | 50 | public float TotalScience { get; private set; } 51 | public float CompletedScience { get; private set; } 52 | public float OutstandingScience { get; private set; } 53 | 54 | /// 55 | /// Gets or sets a value indicating the current mode of the filter. 56 | /// 57 | public DisplayMode DisplayMode { 58 | get { 59 | return _displayMode; 60 | } set { 61 | if( _displayMode != value ) 62 | { 63 | _displayMode = value; 64 | UpdateFilter( ); 65 | } 66 | } 67 | } 68 | 69 | 70 | 71 | /// 72 | /// Gets or sets a string to be used for filtering experiments. 73 | /// 74 | public string Text { 75 | get { 76 | return _text; 77 | } set { 78 | if( _text != value ) 79 | { 80 | _text = value; 81 | UpdateFilter( ); 82 | } 83 | } 84 | } 85 | 86 | 87 | 88 | /// 89 | /// Gets or sets the current situation. 90 | /// 91 | public Situation CurrentSituation { 92 | get { 93 | return _situation; 94 | } set { 95 | if (_situation != value) { 96 | _situation = value; 97 | UpdateFilter(); 98 | } 99 | } 100 | } 101 | 102 | 103 | 104 | /// 105 | /// Recalculates the experiments to be displayed. 106 | /// 107 | public void UpdateFilter () { 108 | var StartTime = DateTime.Now; 109 | // _logger.Trace("UpdateFilter"); 110 | var query = _parent.Science.AllScienceInstances.AsEnumerable( ); 111 | switch (_displayMode) { 112 | case DisplayMode.All: 113 | break; 114 | case DisplayMode.Unlocked: 115 | query = query.Where(x => x.IsUnlocked == true); 116 | break; 117 | case DisplayMode.ActiveVessel: 118 | query = ApplyActiveVesselFilter(query); 119 | break; 120 | case DisplayMode.CurrentSituation: 121 | query = ApplyCurrentSituationFilter(query); 122 | break; 123 | default: 124 | break; 125 | } 126 | 127 | string[] Words = Text.Split(' '); 128 | for(int x = 0; x < Words.Count(); x++ ) 129 | { 130 | var options = Words[x].Split('|'); 131 | query = query.Where(sci_inst => options.Any(o => { 132 | var s = o; 133 | var negate = false; 134 | if (o.StartsWith("-", StringComparison.InvariantCultureIgnoreCase)) { 135 | negate = true; 136 | s = o.Substring(1); 137 | } 138 | 139 | return sci_inst.Description.ToLowerInvariant().Contains(s.ToLowerInvariant()) == !negate; 140 | })); 141 | } 142 | 143 | query = query.OrderBy( x => x.TotalScience ); 144 | TotalCount = query.Count( ); 145 | 146 | 147 | 148 | bool CompleteWithoutRecovery; 149 | bool HideCompleteExperiments; 150 | if( EnforceLabLanderMode ) 151 | { 152 | CompleteWithoutRecovery = true; 153 | HideCompleteExperiments = true; 154 | } 155 | else 156 | { 157 | CompleteWithoutRecovery = _parent.Config.CompleteWithoutRecovery; 158 | HideCompleteExperiments = _parent.Config.HideCompleteExperiments; 159 | } 160 | 161 | 162 | 163 | if( CompleteWithoutRecovery ) // Lab lander mode. Complete is a green bar ( Recovered+OnBoard ) 164 | { 165 | DisplayScienceInstances = query.Where( x => !HideCompleteExperiments || !x.IsCollected ).ToList( ); 166 | 167 | IList RemainingExperiments = new List( ); 168 | RemainingExperiments = query.Where( x => !x.IsCollected ).ToList( ); 169 | CompleteCount = TotalCount - RemainingExperiments.Count( ); 170 | TotalScience = RemainingExperiments.Sum( x => x.TotalScience ) - RemainingExperiments.Sum( x => x.OnboardScience ); ; 171 | CompletedScience = RemainingExperiments.Sum( x => x.CompletedScience ); 172 | } 173 | else // Normal mode, must recover/transmit to KSC 174 | { 175 | DisplayScienceInstances = query.Where( x => !HideCompleteExperiments || !x.IsComplete ).ToList( ); 176 | 177 | IList RemainingExperiments = new List( ); 178 | RemainingExperiments = query.Where( x => !x.IsComplete ).ToList( ); 179 | CompleteCount = TotalCount - RemainingExperiments.Count( ); 180 | TotalScience = RemainingExperiments.Sum( x => x.TotalScience ); 181 | CompletedScience = RemainingExperiments.Sum( x => x.CompletedScience ); 182 | } 183 | 184 | 185 | 186 | var Elapsed = DateTime.Now - StartTime; 187 | // _logger.Trace( "UpdateFilter Done - " + Elapsed.ToString( ) + "ms" ); 188 | } 189 | 190 | 191 | 192 | /// 193 | /// Filters a collection of experiments to only return ones that can be performed on the current vessel. 194 | /// 195 | /// The source experiment collection. 196 | /// A filtered collection of experiments that can be performed on the current vessel. 197 | private IEnumerable ApplyActiveVesselFilter (IEnumerable src) { 198 | switch (HighLogic.LoadedScene) { 199 | case GameScenes.FLIGHT: 200 | var vessel = FlightGlobals.ActiveVessel; 201 | return vessel == null 202 | ? Enumerable.Empty () 203 | : ApplyPartFilter(src, vessel.FindPartModulesImplementing(), vessel.GetCrewCount() > 0); 204 | case GameScenes.EDITOR: 205 | return EditorLogic.SortedShipList == null 206 | ? Enumerable.Empty () 207 | : ApplyPartFilter(src, EditorLogic.SortedShipList.SelectMany(x => x.Modules.OfType ()), EditorLogic.SortedShipList.Any (x => x != null && x.CrewCapacity > 0)); 208 | case GameScenes.CREDITS: 209 | case GameScenes.LOADING: 210 | case GameScenes.LOADINGBUFFER: 211 | case GameScenes.MAINMENU: 212 | case GameScenes.PSYSTEM: 213 | case GameScenes.SETTINGS: 214 | case GameScenes.SPACECENTER: 215 | case GameScenes.TRACKSTATION: 216 | default: 217 | // No active vessel for these scenes. 218 | return Enumerable.Empty (); 219 | } 220 | } 221 | 222 | 223 | 224 | /// 225 | /// Filters a collection of experiments to only return ones that can be performed on a vessel made from the given modules. 226 | /// 227 | /// The source experiment collection. 228 | /// The available modules. 229 | /// A flag indicating whether the modules currently have crew onboard. 230 | /// A filtered collection of experiments that can be performed on a vessel made from the given modules. 231 | private IEnumerable ApplyPartFilter (IEnumerable src, IEnumerable modules, bool hasCrew) { 232 | var experiments = modules 233 | .Select(x => x.experimentID) 234 | .Distinct(); 235 | return src.Where( x => x.IsUnlocked ).Where(x => 236 | (x.ScienceExperiment.id != "crewReport" && experiments.Contains(x.ScienceExperiment.id)) || // unmanned - crewReport needs to be explicitly ignored as we need crew for that experiment even though it's a module on the capsules. 237 | (hasCrew && experiments.Contains("crewReport") && x.ScienceExperiment.id == "crewReport") || // manned crewReport 238 | (hasCrew && (x.ScienceExperiment.id == "surfaceSample" || x.ScienceExperiment.id == "evaReport"))); // manned 239 | } 240 | 241 | 242 | 243 | /// 244 | /// Filters a collection of experiments to only return ones that can be performed in the current situation. 245 | /// 246 | /// The source experiment collection 247 | /// A filtered collection of experiments that can be performed in the current situation. 248 | private IEnumerable ApplyCurrentSituationFilter (IEnumerable src) { 249 | if (HighLogic.LoadedScene != GameScenes.FLIGHT || CurrentSituation == null) { 250 | return Enumerable.Empty(); 251 | } 252 | 253 | var vessel = FlightGlobals.ActiveVessel; 254 | if (vessel == null) { 255 | return Enumerable.Empty(); 256 | } 257 | 258 | src = ApplyActiveVesselFilter(src); 259 | 260 | return src 261 | .Where(x => x.Situation.Body.CelestialBody == CurrentSituation.Body.CelestialBody ) 262 | .Where(x => string.IsNullOrEmpty(x.Situation.Biome) || x.Situation.Biome == CurrentSituation.Biome) 263 | .Where(x => x.Situation.SubBiome == CurrentSituation.SubBiome) 264 | .Where(x => x.Situation.ExperimentSituation == CurrentSituation.ExperimentSituation); 265 | } 266 | 267 | 268 | 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/CHANGES.md: -------------------------------------------------------------------------------- 1 | [x] Science! 2 | ============ 3 | 4 | 5 | 6 | 5.17 7 | ---- 8 | 06-Aug-2018 Built against KSP V1.4.5 9 | * Recompiled for KSP V1.4.5 10 | 11 | 12 | 13 | 5.16 14 | ---- 15 | 06-June-2018 Built against KSP V1.4.4 16 | * Recompiled for KSP V1.4.4 17 | * edit science.cfg - Ignoring Nehemiah Engineering Orbital Science 18 | 19 | 20 | 21 | 5.15 22 | ---- 23 | 30-Apr-2018 Built against KSP V1.4.3 24 | * Recompiled for KSP V1.4.3, no other changes 25 | 26 | 27 | 28 | 5.14 29 | ---- 30 | 03-Apr-2018 Built against KSP V1.4.2 31 | * Recompiled for KSP V1.4.2, no other changes 32 | 33 | 34 | 35 | 5.13 36 | ---- 37 | 16-Mar-2018 Built against KSP V1.4.1 38 | * Recompiled for KSP V1.4.1, no other changes 39 | 40 | 41 | 42 | 5.12 43 | ---- 44 | 07-Mar-2018 Built against KSP V1.4.0 45 | * Recompiled for KSP V1.4.0, no other changes 46 | 47 | 48 | 49 | 5.11 50 | ---- 51 | 07-Oct-2017 Built against KSP V1.3.1 52 | * Recompiled for KSP V1.3.1, no other changes 53 | 54 | 55 | 56 | 5.10 57 | ---- 58 | 14-Aug-2017 Built against KSP V1.3.0 59 | * Only pop if experiments are runnable, I excluded Kerbal experiments from the check 60 | 61 | 62 | 63 | 5.9 64 | --- 65 | 20-July-2017 Built against KSP V1.3.0 66 | * Rewrote window settings 67 | * Added selected object information window to tracking station scene 68 | * Added body information to selected object window 69 | * Added vehicle information to selected object window - based on "Resource Details in Tracking Center" by avivey 70 | * Setting to turn off selected object window 71 | * Added StationScience experiments to science.cfg as requested 72 | * Bug fix - Checklist window didn't open on KSC screen after loading saved game. 73 | Calling GameSceneSwitch event after mod becomes "_active=true" to enforce visibility 74 | 75 | 76 | 77 | 5.8 78 | --- 79 | 28-June-2017 Built against KSP V1.3.0 80 | * Save windows settings more often 81 | * Window settings for Here&Now 82 | * New icons on Here&Now window 83 | * Changed button code to allow right clicks 84 | * Right click to mute music 85 | * Right click to open Here&Now 86 | * Hide Here&Now icon when using right click 87 | * Option for mute music at start 88 | 89 | 90 | 91 | 5.7 92 | --- 93 | 26-May-2017 Built against KSP V1.3.0 94 | 95 | 96 | 97 | 5.6 98 | --- 99 | 04-Apr-2017 Built against KSP V1.2.2 100 | * Situation bug on checklist window in KSC scene, now correctly becomes blank. 101 | * Reading stored setting for checklist filter button correctly 102 | * Orbital Science support for Here&Now trigger buttons 103 | * Only using stock calls for triggering science if we can't use DMagic ones (seems to be best) 104 | 105 | 106 | 107 | 5.5 108 | --- 109 | 09-Mar-2017 Built against KSP V1.2.2 110 | * Ui Scaling contributed by jsmcconn 111 | * Text Filters in science.cfg 112 | * Difficult science filter 113 | * Updated help 114 | 115 | 116 | 117 | 5.4 118 | --- 119 | 07-Dec-2016 Built against KSP V1.2.2 120 | 121 | 122 | 123 | 5.3 124 | --- 125 | 03-Nov-2016 Built against KSP V1.2.1 126 | * Bug fix - Icons invisible after going to MAIN MENU 127 | * Bug fix - science.cfg - changing "scopeScan" into "dmReconScan", as the radial telescope uses normal biomes. 128 | * Display situation on Here&Now Window + MouseOver - number of experiments stored 129 | * Progress bars for experiments on Here&Now window. 130 | * Message when entering a new biome. 131 | 132 | 133 | 5.2 134 | --- 135 | 24-Oct-2016 Built against KSP V1.2.0 136 | * Fix for Contract Configurator 137 | * Don't rely on KSC being in Kerbin+Shores 138 | * Works with LTech 139 | 140 | 5.1 141 | --- 142 | 13-Oct-2016 Built against KSP V1.2.0 143 | * Rebuilt for KSP 1.2 144 | * Bug fixes 145 | * New settings, without Gui 146 | 147 | 5.0 148 | --- 149 | 11-Sept-2016 Built against KSP V1.1.3 150 | * New window a bit like Science Alert 151 | 152 | 4.20 153 | --- 154 | 22-June-2016 Built against KSP V1.1.3 155 | * Fix for science.cfg not applying to KSC baby biomes 156 | * Fix for remaining science tooltip. 157 | 158 | 4.19 159 | --- 160 | 20-June-2016 Built against KSP V1.1.2 161 | * New button code to handle multiple buttons - ready for V5 162 | * New artwork for icons 163 | * New title bar icons 164 | * Compact mode use same icons as maximised mode 165 | * Separate settings window 166 | * New help window 167 | * New resizable window class - not on main window 168 | * Science totals tool tip contains onboard science 169 | * Filter text + state in settings 170 | 171 | 4.18 172 | --- 173 | 24-May-2016 Built against KSP V1.1.2 174 | * Remembers window positions 175 | * Changed location of settings file 176 | * New tool tip for experiment count and value 177 | * Current situation text word-wraps 178 | * Removed coroutines - refreshes from Update() 179 | * New event handler class 180 | 181 | 4.17 182 | --- 183 | 03-May-2016 Built against KSP V1.1.2 184 | * Built against KSP V1.1.2 185 | 186 | 4.16 187 | --- 188 | 29-Apr-2016 Built against KSP V1.1.1 189 | * Built against KSP V1.1.1 190 | 191 | 4.15 192 | --- 193 | 20-Apr-2016 Built against KSP V1.1.0 194 | * Built against KSP V1.1.0 195 | 196 | 197 | 4.14 198 | --- 199 | 26-Jan-2016 Minor GUI changes KSP V1.0.5 200 | * Supports F2 201 | * More tooltips 202 | * Close button z-sorts correctly 203 | 204 | 205 | 4.12 206 | --- 207 | 26-Nov-2015 Bug fix version KSP V1.0.5 208 | * Only initialise if we need to. Avoids an exception when moving scene from settings to main menu 209 | 210 | 211 | 4.11 212 | --- 213 | 10-Nov-2015 Updated for KSP V1.0.5 214 | * New situation filters 215 | * Recompiled for KSP V1.0.5 216 | 217 | 218 | 4.10 219 | --- 220 | 4-Oct-2015 Bug fix version for KSP V1.0.4 221 | * Fix bug where situation filters aren't applied to KSC baby biomes 222 | 223 | 224 | 4.9 225 | --- 226 | 29-Sept-2015 Celestial Body filters for KSP V1.0.4 227 | * A fairly major code reorganisation 228 | * A new config file for filtering science according to the properties of celestial bodies 229 | 230 | 231 | 4.8 232 | --- 233 | 03-Aug-2015 Bug fixes + modified filters for KSP V1.0.4 234 | * Loading settings is a bit more robust 235 | * Fixed an exception if Blizzy78's toolbar is missing 236 | * Better analysis of planet's properties, should work better with modified solar system. 237 | * Filtered results includes only biomes of visited bodies 238 | * Option to hide the "Show All" button to prevent discovery of biomes on unexplored bodies 239 | 240 | 241 | 4.7 242 | --- 243 | 3-July-2015 New settings for KSP V1.0.4 244 | * Option to check for science in debris 245 | * Option to consider science "completed" before recovery 246 | 247 | 248 | 4.6 249 | --- 250 | 24-June-2015 Gui bug fix for KSP V1.0.4 251 | * Completed experiments total is updated correctly when vehicles are recovered 252 | * Window is closed on main menu and certain other scenes 253 | * Added close button to window 254 | 255 | 256 | 4.5 257 | --- 258 | 12-June-2015 Speed increase and bug fix for KSP V1.0.2 259 | * Handles building upgrades in career mode - surface samples listed as appropriate, baby biomes appear and disappear as appropriate 260 | * Better use of indexed lists means it is much faster 261 | 262 | 263 | 4.4 264 | --- 265 | 15-May-2015 Speed increase for KSP V1.0.2 266 | * No longer checks for science stored in debris. 267 | * Only gets the science subjects once and indexes the list for efficient queries. 268 | 269 | 270 | 4.3 271 | --- 272 | 5-May-2015 Fix and rebuild for KSP V1.0.2 273 | * Changed blizzy icon text - doesn't say 'test' any more! 274 | 275 | 276 | 4.2 277 | --- 278 | 1-May-2015 Fix and rebuild for KSP V1.0.1 by Z-Key Aerospace 279 | 280 | 281 | 4.1 282 | --- 283 | 28-April-2015 Fix and rebuild for KSP V1.0 by Z-Key Aerospace 284 | 285 | 286 | 4.0 287 | --- 288 | * Added support for blizzy's toolbar - find the toggle in the settings menu if you've got it installed. 289 | * Changes to the settings are now saved across games. 290 | 291 | 3.1 292 | --- 293 | * Can now use the - symbol to do NOT searches e.g. "goo -Minmus". 294 | * Added compact mode. 295 | * Moved the complete experiment filter option to the settings panel. 296 | * Now only updates when the window is open. 297 | * Fixed ArgumentNullException when running alongside Karbonite (thanks Jaxx). 298 | * Fixed experiments not being detected in biomes with spaces in them (thanks Tahib). 299 | * Now refreshes the experiment cache far less frequently - only once per scene instead of whenever science is obtained or the active vessel is changed. 300 | 301 | 3.0 302 | --- 303 | * Added onboard science detection. 304 | * Added support for CustomBiomes. 305 | * Fixed experiments not showing up as complete correctly due to a floating point rounding error. 306 | 307 | 2.0 308 | --- 309 | * Implemented current situation detection and filter. 310 | * Added tooltips to buttons. 311 | * Completed experiment progress bars are now rendered in a different colour. 312 | * Replaced text on filter buttons with icons. 313 | * Fixed several memory leaks. 314 | * Fixed addon being loaded multiple times. 315 | 316 | 1.1 317 | --- 318 | * Mod now correctly disables itself in Sandbox mode (stops the VAB lockup bug). 319 | * Can now use the | symbol to do OR searches e.g. "goo Mun|Minmus". 320 | * Optimized experiment list rendering. 321 | * Will automatically detect OrbitalScience if installed, and add its experiments to the list. 322 | * Biomes are now displayed in the experiment list correctly. 323 | * Fixed some experiments not appearing in the list if they took biomes into account. 324 | * Fixed "while landed at sun" experiments appearing in the list. 325 | * Fixed science levels not taking game difficulty settings into account. 326 | 327 | 1.0 328 | --- 329 | * Added search bar. 330 | * Added science values to experiment progress bars. 331 | * Fixed window remaining hidden when returning to the main menu. 332 | 333 | 0.3 334 | --- 335 | * Recompiled for KSP 0.25.0. 336 | 337 | 0.2 338 | --- 339 | * Implemented active vessel detection. 340 | 341 | 0.1 342 | --- 343 | * Initial commit. 344 | -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/MiniAVC.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/GameData/[x] Science!/MiniAVC.dll -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/PluginData/[x] Science!/settings.cfg: -------------------------------------------------------------------------------- 1 | ScienceChecklist 2 | { 3 | Config 4 | { 5 | HideCompleteExperiments = False 6 | UseBlizzysToolbar = False 7 | CompleteWithoutRecovery = False 8 | CheckDebris = False 9 | AllFilter = True 10 | StopTimeWarp = True 11 | PlayNoise = True 12 | ShowResultsWindow = True 13 | FilterDifficultScience = True 14 | UiScale = 1.0 15 | MusicStartsMuted = False 16 | RighClickMutesMusic = True 17 | SelectedObjectWindow = True 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/README.md: -------------------------------------------------------------------------------- 1 | Z-Key Aerospace has rebuilt this KSP Mod for KSP V1.0 onwards 2 | [X] Science! was by Bodrick and is released under "Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license" 3 | 4 | As of V4.1 it is rebuilt and fixed by Z-Key Aerospace. 5 | 6 | 7 | 8 | Bodrick's readme follows... 9 | 10 | 11 | 12 | [x] Science! 13 | ============ 14 | 15 | Tired of wondering whether you need to go back to Minmus to get an EVA report while landed on the Greater Flats? Then **[x] Science!** is the mod for you! 16 | 17 | **[x] Science!** is a science checklist plugin for Kerbal Space Program. It allows you to see what science experiments you have left to perform - and how much science you'll get for doing them. 18 | 19 | Installation 20 | ------------ 21 | 22 | Simply copy the GameData folder into your KSP directory. 23 | 24 | License 25 | ------ 26 | 27 | **[x] Science!** is licensed under a [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International license][1]. 28 | 29 | You are free to: 30 | 31 | * **Share** - copy and redistribute the material in any medium or format 32 | 33 | * **Adapt** - remix, transform, and build upon the material 34 | 35 | As long as: 36 | 37 | * **Attribution** - You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 38 | 39 | * **NonCommercial** - You may not use the material for commercial purposes. 40 | 41 | * **ShareAlike** - If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 42 | 43 | 44 | Version Checking 45 | --- 46 | 47 | This mod includes version checking using [MiniAVC][2]. If you opt-in, it will use the internet to check whether there is a new version available. Data is only read from the internet and no personal information is sent. For a more comprehensive version checking experience, please download the [KSP-AVC Plugin][2]. 48 | 49 | [1]:http://creativecommons.org/licenses/by-nc-sa/4.0/ 50 | [2]:http://forum.kerbalspaceprogram.com/threads/79745 -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/[x] Science!.version: -------------------------------------------------------------------------------- 1 | { 2 | "NAME":"[x] Science!", 3 | "URL":"https://themoose.co.uk/ksp/%5Bx%5D%20Science!.version", 4 | "DOWNLOAD":"https://themoose.co.uk/ksp/downloads.html", 5 | "CHANGE_LOG_URL":"https://themoose.co.uk/ksp/CHANGES.md", 6 | "VERSION": 7 | { 8 | "MAJOR":5, 9 | "MINOR":17, 10 | "PATCH":0 11 | }, 12 | "KSP_VERSION": 13 | { 14 | "MAJOR":1, 15 | "MINOR":4, 16 | "PATCH":5 17 | } 18 | } -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/bubbles.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/GameData/[x] Science!/bubbles.wav -------------------------------------------------------------------------------- /X-Science/GameData/[x] Science!/science.cfg: -------------------------------------------------------------------------------- 1 | ScienceChecklist 2 | { 3 | CelestialBodyFilters 4 | { 5 | // --- DMagic Orbital Science --------------------- 6 | dmbiodrillscan = NeedsAtmosphere 7 | 8 | // [x] Science can't do custom biomes, just turn these off 9 | dmReconScan = AvoidAll 10 | dmSIGINT = AvoidAll 11 | dmbathymetryscan = AvoidAll 12 | 13 | 14 | 15 | // --- Solar Science ------------------------------ 16 | HMI = NeedsStar, NeedsInSpaceLow 17 | STEREO = NeedsStar, NeedsInSpaceLow 18 | 19 | 20 | 21 | // --- Sounding Rockets --------------------------- 22 | // Restrict to home world. 23 | SRExperiment01 = NeedsHomeWorld 24 | SRExperiment02 = NeedsHomeWorld 25 | SRExperiment03 = NeedsHomeWorld 26 | SRExperiment04 = NeedsHomeWorld 27 | 28 | 29 | 30 | // --- LTech -------------------------------------- 31 | // LTech contains some weird stub experiments that aren't supposed to show up 32 | hullcampicture = AvoidAll // WaitWhat = External camera 33 | error = AvoidAll // Error = SkyLab 34 | 35 | 36 | 37 | // --- M.O.L.E // WBI ----------------------------- 38 | // WBI experiments run over time 39 | WBISurfaceConstructionStudy = AvoidAll 40 | WBIKNUTS = AvoidAll 41 | WBIBRE = AvoidAll 42 | WBISAME = AvoidAll 43 | WBIOrbitalRecon = AvoidAll 44 | WBICryogenicRadiationStudy = AvoidAll 45 | WBICryogenicResourceStudy = AvoidAll 46 | WBICryogenicStudy = AvoidAll 47 | WBICrystalGrowth = AvoidAll 48 | WBIGooStudy = AvoidAll 49 | WBIIceCreamResearch = AvoidAll 50 | WBILongTermCryogenicMiniStudy = AvoidAll 51 | WBILongTermCryogenicStudy = AvoidAll 52 | WBIMESS = AvoidAll 53 | WBIConstructionTechniques = AvoidAll 54 | WBIPowerToolsEvaluation = AvoidAll 55 | WBISpaceAdaptionStudy = AvoidAll 56 | WBITemperatureStudy = AvoidAll 57 | WBIThermalStudy = AvoidAll 58 | 59 | 60 | 61 | // --- Station Science ---------------------------- 62 | // [x] Science should ignore StationScience 63 | plantGrowth = AvoidAll 64 | bioproducts = AvoidAll 65 | eccentricKuarqs = AvoidAll 66 | retrogradeKuarqs = AvoidAll 67 | progradeKuarqs = AvoidAll 68 | kuarqsBioproducts = AvoidAll 69 | 70 | 71 | 72 | // --- Nehemiah Engineering Orbital Science ------- 73 | // Ignore all NEOS experiments as they take time to complete 74 | // -- KEES - Kerbal Environmental Effects Studies - 75 | NE_KEES_TEST = AvoidAll 76 | NE_KEES_PPMD = AvoidAll 77 | NE_KEES_ODC = AvoidAll 78 | NE_KEES_POSA1 = AvoidAll 79 | NE_KEES_POSA2 = AvoidAll 80 | // -- KRP - Kemini Research Program -------------- 81 | NE_KeminiTEST = AvoidAll 82 | NE_KeminiD5 = AvoidAll 83 | NE_KeminiD8 = AvoidAll 84 | NE_KeminiMSC3 = AvoidAll 85 | NE_KeminiD10 = AvoidAll 86 | NE_KeminiD7 = AvoidAll 87 | // -- OMS - Orbital Material Science ------------- 88 | NE_Test = AvoidAll 89 | NE_FLEX = AvoidAll 90 | NE_CFI = AvoidAll 91 | NE_CCF = AvoidAll 92 | NE_CFE = AvoidAll 93 | NE_MEE1 = AvoidAll 94 | NE_MEE2 = AvoidAll 95 | NE_MIS1 = AvoidAll 96 | NE_MIS2 = AvoidAll 97 | NE_MIS3 = AvoidAll 98 | NE_CVB = AvoidAll 99 | NE_PACE = AvoidAll 100 | // -- KLS - Kerbal Life Science ------------------ 101 | NE_ADUM = AvoidAll 102 | NE_SpiU = AvoidAll 103 | } 104 | 105 | 106 | TextFilters 107 | { 108 | // --- Text Filters - Stock System----------------- 109 | // In the stock system these combinations are not possible 110 | TEXT_FILTER = Kerbin Splashed Mountains|Highlands 111 | 112 | // [x] Science! is assuming this is in Shores not Grasslands 113 | // probly need a special case in code, banning it for now. 114 | TEXT_FILTER = Baikerbanur 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /X-Science/GameHelper.cs: -------------------------------------------------------------------------------- 1 | using KSP.Localization; 2 | 3 | 4 | 5 | /* 6 | * THIS IS A STATIC CLASS 7 | */ 8 | 9 | namespace ScienceChecklist { 10 | /// 11 | /// Contains helper methods for the current game state. 12 | /// 13 | internal static class GameHelper { 14 | 15 | 16 | 17 | 18 | // All the Scenes, which ones are kosher? 19 | public static bool AllowChecklistWindow( GameScenes? Scene = null ) 20 | { 21 | if( Scene == null ) 22 | Scene = HighLogic.LoadedScene; 23 | switch( Scene ) 24 | { 25 | case GameScenes.LOADING: 26 | case GameScenes.LOADINGBUFFER: 27 | case GameScenes.MAINMENU: 28 | case GameScenes.SETTINGS: 29 | case GameScenes.CREDITS: 30 | return false; 31 | case GameScenes.SPACECENTER: 32 | case GameScenes.EDITOR: 33 | case GameScenes.FLIGHT: 34 | case GameScenes.TRACKSTATION: 35 | return true; 36 | case GameScenes.PSYSTEM: 37 | return false; 38 | default: 39 | return false; 40 | } 41 | } 42 | 43 | 44 | 45 | // All the Scenes, which ones are kosher? 46 | public static bool AllowStatusWindow( GameScenes? Scene = null ) 47 | { 48 | if( Scene == null ) 49 | Scene = HighLogic.LoadedScene; 50 | if( Scene == GameScenes.FLIGHT ) 51 | return true; 52 | return false; 53 | } 54 | 55 | 56 | 57 | public static void StopTimeWarp( ) 58 | { 59 | if( TimeWarp.CurrentRateIndex > 0 ) 60 | TimeWarp.SetRate( 0, true ); 61 | } 62 | 63 | public static string LocalizeBodyName( string input ) 64 | { 65 | return Localizer.Format("<<1>>", input); 66 | } 67 | 68 | 69 | 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /X-Science/HelpWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | 5 | 6 | namespace ScienceChecklist 7 | { 8 | class HelpWindow : Window 9 | { 10 | private GUIStyle labelStyle; 11 | private GUIStyle sectionStyle; 12 | private Vector2 scrollPosition; 13 | private readonly ScienceChecklistAddon _parent; 14 | 15 | 16 | 17 | public HelpWindow( ScienceChecklistAddon Parent ) 18 | : base("[x] Science! Help", 500, Screen.height * 0.75f / Parent.Config.UiScale ) 19 | { 20 | _parent = Parent; 21 | UiScale = _parent.Config.UiScale; 22 | scrollPosition = Vector2.zero; 23 | _parent.Config.UiScaleChanged += OnUiScaleChange; 24 | } 25 | 26 | 27 | 28 | protected override void ConfigureStyles( ) 29 | { 30 | base.ConfigureStyles(); 31 | 32 | if( labelStyle == null ) 33 | { 34 | labelStyle = new GUIStyle( _skin.label ); 35 | labelStyle.wordWrap = true; 36 | labelStyle.fontStyle = FontStyle.Normal; 37 | labelStyle.normal.textColor = Color.white; 38 | labelStyle.stretchWidth = true; 39 | labelStyle.stretchHeight = false; 40 | labelStyle.margin.bottom -= wScale( 2 ); 41 | labelStyle.padding.bottom -= wScale( 2 ); 42 | } 43 | 44 | if( sectionStyle == null ) 45 | { 46 | sectionStyle = new GUIStyle( labelStyle ); 47 | sectionStyle.fontStyle = FontStyle.Bold; 48 | } 49 | } 50 | 51 | 52 | 53 | private void OnUiScaleChange( object sender, EventArgs e ) 54 | { 55 | UiScale = _parent.Config.UiScale; 56 | labelStyle = null; 57 | sectionStyle = null; 58 | base.OnUiScaleChange( ); 59 | ConfigureStyles( ); 60 | } 61 | 62 | 63 | 64 | protected override void DrawWindowContents( int windowID ) 65 | { 66 | scrollPosition = GUILayout.BeginScrollView( scrollPosition ); 67 | GUILayout.BeginVertical( GUILayout.ExpandWidth( true ) ); 68 | 69 | GUILayout.Label( "[x] Science! by Z-Key Aerospace and Bodrick.", sectionStyle, GUILayout.ExpandWidth( true ) ); 70 | 71 | GUILayout.Space( wScale( 30 ) ); 72 | GUILayout.Label("About", sectionStyle, GUILayout.ExpandWidth(true)); 73 | GUILayout.Label( "[x] Science! creates a list of all possible science. Use the list to find what is possible, to see what is left to accomplish, to decide where your Kerbals are going next.", labelStyle, GUILayout.ExpandWidth( true ) ); 74 | 75 | GUILayout.Space( wScale( 20 ) ); 76 | GUILayout.Label( "The four filter buttons at the bottom of the window are", sectionStyle, GUILayout.ExpandWidth( true ) ); 77 | GUILayout.Label( "* Show experiments available right now – based on you current ship and its situation", labelStyle, GUILayout.ExpandWidth( true ) ); 78 | GUILayout.Label( "* Show experiments available on this vessel – based on your ship but including all known biomes", labelStyle, GUILayout.ExpandWidth( true ) ); 79 | GUILayout.Label( "* Show all unlocked experiments – based on instruments you have unlocked and celestial bodies you have visited.", labelStyle, GUILayout.ExpandWidth( true ) ); 80 | GUILayout.Label( "* Show all experiments – shows everything. You can hide this button", labelStyle, GUILayout.ExpandWidth( true ) ); 81 | 82 | GUILayout.Space( wScale( 20 ) ); 83 | GUILayout.Label( "The text filter", sectionStyle, GUILayout.ExpandWidth( true ) ); 84 | GUILayout.Label( "To narrow your search, you may enter text into the filter eg \"kerbin’s shores\"", labelStyle, GUILayout.ExpandWidth( true ) ); 85 | GUILayout.Label( "Use – to mean NOT eg \"mun space -near\"", labelStyle, GUILayout.ExpandWidth( true ) ); 86 | GUILayout.Label( "Use | to mean OR eg \"mun|minmus space\"", labelStyle, GUILayout.ExpandWidth( true ) ); 87 | GUILayout.Label( "Hover the mouse over the \"123/456 completed\" text. A pop-up will show more infromation.", labelStyle, GUILayout.ExpandWidth( true ) ); 88 | GUILayout.Label( "Press the X button to clear your text filter.", labelStyle, GUILayout.ExpandWidth( true ) ); 89 | 90 | GUILayout.Space( wScale( 20 ) ); 91 | GUILayout.Label( "The settings are", sectionStyle, GUILayout.ExpandWidth( true ) ); 92 | GUILayout.Label( "* Hide complete experiments – Any science with a full green bar is hidden. It just makes it easier to see what is left to do.", labelStyle, GUILayout.ExpandWidth( true ) ); 93 | GUILayout.Label( "* Complete without recovery – Consider science in your spaceships as if it has been recovered. You still need to recover to get the points. It just makes it easier to see what is left to do.", labelStyle, GUILayout.ExpandWidth( true ) ); 94 | GUILayout.Label( "* Check debris – Science that survived a crash will be visible. You may still be able to recover it.", labelStyle, GUILayout.ExpandWidth( true ) ); 95 | GUILayout.Label( "* Allow all filter – The \"All\" filter button shows science on planets you have never visited using instruments you have not invented yet. Some people may consider it overpowered. If you feel like a cheat, turn it off.", labelStyle, GUILayout.ExpandWidth( true ) ); 96 | GUILayout.Label( "* Filter difficult science – Hide science that is practically impossible. Flying at stars, that kinda thing.", labelStyle, GUILayout.ExpandWidth( true ) ); 97 | GUILayout.Label( "* Use blizzy78's toolbar – If you have blizzy78’s toolbar installed then place the [x] Science! button on that instead of the stock \"Launcher\" toolbar.", labelStyle, GUILayout.ExpandWidth( true ) ); 98 | GUILayout.Label( "* Right click [x] icon – Choose to open the Here and Now window by right clicking. Hides the second window. Otherwise mute music.", labelStyle, GUILayout.ExpandWidth( true ) ); 99 | GUILayout.Label( "* Music starts muted – Music is muted on load.", labelStyle, GUILayout.ExpandWidth( true ) ); 100 | GUILayout.Label( "* Adjust UI Size – Change the scaling of the UI.", labelStyle, GUILayout.ExpandWidth( true ) ); 101 | 102 | GUILayout.Space( wScale( 20 ) ); 103 | GUILayout.Label( "Here and Now Window", sectionStyle, GUILayout.ExpandWidth( true ) ); 104 | GUILayout.Label( "The Here and Now Window will stop time-warp, display an alert message and play a noise when you enter a new situation. To prevent this, close the window.", labelStyle, GUILayout.ExpandWidth( true ) ); 105 | GUILayout.Label( "The Here and Now Window will show all outstanding experiments for the current situation that are possible with the current ship.", labelStyle, GUILayout.ExpandWidth( true ) ); 106 | GUILayout.Label( "To run an experiment, click the button. If the button is greyed-out then you may need to reset the experiment or recover or transmit the science.", labelStyle, GUILayout.ExpandWidth( true ) ); 107 | GUILayout.Label( "To perform an EVA report or surface sample, first EVA your Kerbal. The window will react, allowing those buttons to be clicked.", labelStyle, GUILayout.ExpandWidth( true ) ); 108 | 109 | GUILayout.Space( wScale( 20 ) ); 110 | GUILayout.Label( "Did you know? (includes spoilers)", sectionStyle, GUILayout.ExpandWidth( true ) ); 111 | GUILayout.Label( "* In the VAB editor you can use the filter \"Show experiments available on this vessel\" to see what your vessel could collect before you launch it.", labelStyle, GUILayout.ExpandWidth( true ) ); 112 | GUILayout.Label( "* Does the filter \"mun space high\" show mun’s highlands? – use \"mun space –near\" instead.", labelStyle, GUILayout.ExpandWidth( true ) ); 113 | GUILayout.Label( "* Need more science? Go to Minmus. It’s a little harder to get to but your fuel will last longer. A single mission can collect thousands of science points before you have to come back.", labelStyle, GUILayout.ExpandWidth( true ) ); 114 | GUILayout.Label( "* Generally moons are easier - it is more efficient to collect science from the surface of Ike or Gilly than from Duna or Eve. That said - beware Tylo, it's big and you can't aerobrake.", labelStyle, GUILayout.ExpandWidth( true ) ); 115 | GUILayout.Label( "* Most of Kerbin’s biomes include both splashed and landed situations. Landed at Kerbin’s water? First build an aircraft carrier.", labelStyle, GUILayout.ExpandWidth( true ) ); 116 | 117 | GUILayout.EndVertical( ); 118 | GUILayout.EndScrollView( ); 119 | 120 | GUILayout.Space( wScale( 8 ) ); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /X-Science/Lib/Logger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | 4 | 5 | 6 | namespace ScienceChecklist 7 | { 8 | /// 9 | /// Class for helping with log messages. 10 | /// 11 | internal sealed class Logger { 12 | /// 13 | /// Creates a new instance of the Logger class. 14 | /// 15 | /// The owner of this logger. 16 | public Logger (object parent) { 17 | _ownerName = parent.GetType().Name; 18 | } 19 | 20 | /// 21 | /// Creates a new instance of the Logger class to be used by static classes. 22 | /// 23 | /// The name of the parent. 24 | public Logger (string parentName) { 25 | _ownerName = parentName; 26 | } 27 | 28 | #region METHODS (PUBLIC) 29 | 30 | /// 31 | /// Writes a log message at the Fatal level. 32 | /// 33 | /// The message to write. 34 | public void Fatal (string message) { 35 | WriteMessage(message, LogLevel.Fatal); 36 | } 37 | 38 | /// 39 | /// Writes a log message at the Error level. 40 | /// 41 | /// The message to write. 42 | public void Error (string message) { 43 | WriteMessage(message, LogLevel.Error); 44 | } 45 | 46 | /// 47 | /// Writes a log message at the Warning level. 48 | /// 49 | /// The message to write. 50 | public void Warning (string message) { 51 | WriteMessage(message, LogLevel.Warning); 52 | } 53 | 54 | /// 55 | /// Writes a log message at the Info level. 56 | /// 57 | /// The message to write. 58 | public void Info (string message) { 59 | WriteMessage(message, LogLevel.Info); 60 | } 61 | 62 | /// 63 | /// Writes a log message at the Debug level. 64 | /// 65 | /// The message to write. 66 | public void Debug (string message) { 67 | WriteMessage(message, LogLevel.Debug); 68 | } 69 | 70 | /// 71 | /// Writes a log message at the Trace level. 72 | /// 73 | /// The message to write. 74 | public void Trace (string message) { 75 | WriteMessage(message, LogLevel.Trace); 76 | } 77 | 78 | #endregion 79 | 80 | #region METHODS (PRIVATE) 81 | 82 | /// 83 | /// Writes the specified log message to the UnityEngine Debug log at the specified log level. 84 | /// 85 | /// The message to write. 86 | /// The log level at which the log should be written. 87 | private void WriteMessage (string message, LogLevel logLevel) { 88 | if (logLevel > MaxLogLevel) { 89 | return; 90 | } 91 | var msg = GetMessage (message, logLevel); 92 | switch (logLevel) { 93 | case LogLevel.Fatal: 94 | case LogLevel.Error: 95 | UnityEngine.Debug.LogError( msg ); 96 | break; 97 | case LogLevel.Warning: 98 | case LogLevel.Info: 99 | UnityEngine.Debug.LogWarning( msg ); 100 | break; 101 | case LogLevel.Debug: 102 | case LogLevel.Trace: 103 | UnityEngine.Debug.Log( msg ); 104 | break; 105 | } 106 | } 107 | 108 | /// 109 | /// Formats a log message with the mod name, owner name, log level, and specified message. 110 | /// 111 | /// The log message to be written. 112 | /// The log level at which the log should be written. 113 | /// The formatted message. 114 | private string GetMessage (string message, LogLevel logLevel) { 115 | return string.Format("[{0} [x] Science!]: <{1}> ({2}) - {3}", DateTime.Now, logLevel, _ownerName, message); 116 | } 117 | 118 | #endregion 119 | 120 | #region FIELDS 121 | 122 | private readonly string _ownerName; 123 | 124 | private const LogLevel MaxLogLevel = LogLevel.Trace; 125 | 126 | #endregion 127 | 128 | #region LogLevel 129 | 130 | private enum LogLevel 131 | { 132 | Fatal = 0, 133 | Error = 1, 134 | Warning = 2, 135 | Info = 3, 136 | Debug = 4, 137 | Trace = 5, 138 | } 139 | 140 | #endregion 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /X-Science/Lib/Logging.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Logging.cs 3 | * 4 | * Thunder Aerospace Corporation's library for the Kerbal Space Program, by Taranis Elsu 5 | * 6 | * (C) Copyright 2013, Taranis Elsu 7 | * 8 | * Kerbal Space Program is Copyright (C) 2013 Squad. See http://kerbalspaceprogram.com/. This 9 | * project is in no way associated with nor endorsed by Squad. 10 | * 11 | * This code is licensed under the Attribution-NonCommercial-ShareAlike 3.0 (CC BY-NC-SA 3.0) 12 | * creative commons license. See 13 | * for full details. 14 | * 15 | * Attribution — You are free to modify this code, so long as you mention that the resulting 16 | * work is based upon or adapted from this code. 17 | * 18 | * Non-commercial - You may not use this work for commercial purposes. 19 | * 20 | * Share Alike — If you alter, transform, or build upon this work, you may distribute the 21 | * resulting work only under the same or similar license to the CC BY-NC-SA 3.0 license. 22 | * 23 | * Note that Thunder Aerospace Corporation is a ficticious entity created for entertainment 24 | * purposes. It is in no way meant to represent a real entity. Any similarity to a real entity 25 | * is purely coincidental. 26 | */ 27 | 28 | using UnityEngine; 29 | 30 | 31 | 32 | namespace ScienceChecklist 33 | { 34 | public static class Logging 35 | { 36 | public static void Log(this UnityEngine.Object obj, string message) 37 | { 38 | Debug.Log("-INFO- " + obj.GetType().FullName + "[" + obj.GetInstanceID().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + message, obj); 39 | } 40 | 41 | public static void LogWarning(this UnityEngine.Object obj, string message) 42 | { 43 | Debug.LogWarning("-WARNING- " + obj.GetType().FullName + "[" + obj.GetInstanceID().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + message, obj); 44 | } 45 | 46 | public static void LogError(this UnityEngine.Object obj, string message) 47 | { 48 | Debug.LogError("-ERROR- " + obj.GetType().FullName + "[" + obj.GetInstanceID().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + message, obj); 49 | } 50 | 51 | public static void Log(this System.Object obj, string message) 52 | { 53 | Debug.Log("-INFO- " + obj.GetType().FullName + "[" + obj.GetHashCode().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + message); 54 | } 55 | 56 | public static void LogWarning(this System.Object obj, string message) 57 | { 58 | Debug.LogWarning("-WARNING- " + obj.GetType().FullName + "[" + obj.GetHashCode().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + message); 59 | } 60 | 61 | public static void LogError(this System.Object obj, string message) 62 | { 63 | Debug.LogError("-ERROR- " + obj.GetType().FullName + "[" + obj.GetHashCode().ToString("X") + "][" + Time.time.ToString("0.00") + "]: " + message); 64 | } 65 | 66 | public static void Log(string context, string message) 67 | { 68 | Debug.Log("-INFO- " + context + "[][" + Time.time.ToString("0.00") + "]: " + message); 69 | } 70 | 71 | public static void LogWarning(string context, string message) 72 | { 73 | Debug.LogWarning("-WARNING- " + context + "[][" + Time.time.ToString("0.00") + "]: " + message); 74 | } 75 | 76 | public static void LogError(string context, string message) 77 | { 78 | Debug.LogError("-ERROR- " + context + "[][" + Time.time.ToString("0.00") + "]: " + message); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /X-Science/Lib/StreamEx.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | 4 | 5 | 6 | namespace ScienceChecklist 7 | { 8 | /// 9 | /// Contains extension methods on the Stream class. 10 | /// 11 | internal static class StreamEx { 12 | /// 13 | /// Reads the Stream to the end and returns a byte array containing the contents of the Stream. 14 | /// 15 | /// The stream to be read. 16 | /// A byte array containing the contents of the Stream. 17 | public static byte[] ReadToEnd (this Stream stream) { 18 | long originalPosition = 0; 19 | 20 | if (stream.CanSeek) { 21 | originalPosition = stream.Position; 22 | stream.Position = 0; 23 | } 24 | 25 | try { 26 | var readBuffer = new byte[4096]; 27 | 28 | int totalBytesRead = 0; 29 | int bytesRead; 30 | 31 | while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0) { 32 | totalBytesRead += bytesRead; 33 | 34 | if (totalBytesRead == readBuffer.Length) { 35 | int nextByte = stream.ReadByte(); 36 | if (nextByte != -1) { 37 | var temp = new byte[readBuffer.Length * 2]; 38 | Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length); 39 | Buffer.SetByte(temp, totalBytesRead, (byte) nextByte); 40 | readBuffer = temp; 41 | totalBytesRead++; 42 | } 43 | } 44 | } 45 | 46 | var buffer = readBuffer; 47 | if (readBuffer.Length != totalBytesRead) { 48 | buffer = new byte[totalBytesRead]; 49 | Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead); 50 | } 51 | return buffer; 52 | } finally { 53 | if (stream.CanSeek) { 54 | stream.Position = originalPosition; 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /X-Science/Lib/TextureHelper.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Reflection; 3 | using UnityEngine; 4 | using KSP.IO; 5 | 6 | 7 | namespace ScienceChecklist 8 | { 9 | /// 10 | /// Contains static methods to assist in creating textures. 11 | /// 12 | internal static class TextureHelper { 13 | /// 14 | /// Creates a new Texture2D from an embedded resource. 15 | /// 16 | /// The location of the resource in the assembly. 17 | /// The width of the texture. 18 | /// The height of the texture. 19 | /// 20 | public static Texture2D FromResource( string resource, int width, int height ) 21 | { 22 | var tex = new Texture2D( width, height, TextureFormat.ARGB32, false ); 23 | var iconStream = Assembly.GetExecutingAssembly( ).GetManifestResourceStream( resource ).ReadToEnd( ); 24 | if( iconStream == null ) 25 | return null; 26 | tex.LoadImage( iconStream ); 27 | tex.Apply( ); 28 | return tex; 29 | } 30 | 31 | 32 | 33 | public static Texture2D LoadImage( string filename, int width, int height ) 34 | { 35 | if( File.Exists( filename ) ) 36 | { 37 | var bytes = File.ReadAllBytes( filename ); 38 | Texture2D texture = new Texture2D( width, height, TextureFormat.ARGB32, false ); 39 | texture.LoadImage( bytes ); 40 | return texture; 41 | } 42 | else 43 | return null; 44 | } 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /X-Science/Lib/Window.cs: -------------------------------------------------------------------------------- 1 | /** 2 | * Windows.cs 3 | * 4 | * Thunder Aerospace Corporation's library for the Kerbal Space Program, by Taranis Elsu 5 | * 6 | * (C) Copyright 2013, Taranis Elsu 7 | * 8 | * Kerbal Space Program is Copyright (C) 2013 Squad. See http://kerbalspaceprogram.com/. This 9 | * project is in no way associated with nor endorsed by Squad. 10 | * 11 | * This code is licensed under the Attribution-NonCommercial-ShareAlike 3.0 (CC BY-NC-SA 3.0) 12 | * creative commons license. See 13 | * for full details. 14 | * 15 | * Attribution — You are free to modify this code, so long as you mention that the resulting 16 | * work is based upon or adapted from this code. 17 | * 18 | * Non-commercial - You may not use this work for commercial purposes. 19 | * 20 | * Share Alike — If you alter, transform, or build upon this work, you may distribute the 21 | * resulting work only under the same or similar license to the CC BY-NC-SA 3.0 license. 22 | * 23 | * Note that Thunder Aerospace Corporation is a ficticious entity created for entertainment 24 | * purposes. It is in no way meant to represent a real entity. Any similarity to a real entity 25 | * is purely coincidental. 26 | */ 27 | using System; 28 | using UnityEngine; 29 | using KSP.IO; 30 | using KSP.UI.Dialogs; 31 | 32 | 33 | 34 | namespace ScienceChecklist 35 | { 36 | public abstract class Window 37 | { 38 | private string windowTitle; 39 | private int windowId; 40 | private readonly int _tooltipWindowId = UnityEngine.Random.Range( 0, int.MaxValue ); 41 | private string configNodeName; 42 | protected Rect windowPos; 43 | protected Vector2 defaultWindowSize; 44 | private bool mouseDown; 45 | private bool visible; 46 | private readonly Logger _logger; 47 | protected string _lastTooltip; 48 | 49 | protected GUISkin _skin; 50 | protected GUIStyle closeButtonStyle; 51 | protected GUIContent closeContent; 52 | private GUIStyle resizeStyle; 53 | private GUIContent resizeContent; 54 | private GUIStyle _tooltipStyle; 55 | private GUIStyle _tooltipBoxStyle; 56 | private GUIStyle windowStyle; 57 | 58 | public bool Resizable { get; set; } 59 | public bool HideCloseButton { get; set; } 60 | public bool HideWhenPaused { get; set; } 61 | public event EventHandler WindowClosed; 62 | public float UiScale { get; set; } 63 | 64 | 65 | 66 | protected Window(string windowTitle, float defaultWidth, float defaultHeight) 67 | { 68 | _logger = new Logger( this ); 69 | UiScale = 1f; 70 | Resizable = true; 71 | HideCloseButton = false; 72 | HideWhenPaused = true; 73 | defaultWindowSize = new Vector2(defaultWidth, defaultHeight); 74 | 75 | this.windowTitle = windowTitle; 76 | this.windowId = windowTitle.GetHashCode() + new System.Random().Next(65536); 77 | 78 | configNodeName = windowTitle.Replace(" ", ""); 79 | 80 | windowPos = new Rect((Screen.width - wScale(defaultWindowSize.x)) / 2, (Screen.height - wScale(defaultWindowSize.y)) / 2, wScale(defaultWindowSize.x), wScale(defaultWindowSize.y)); 81 | mouseDown = false; 82 | visible = false; 83 | 84 | var texture = TextureHelper.FromResource( "ScienceChecklist.icons.resize.png", 16, 16 ); 85 | resizeContent = (texture != null) ? new GUIContent(texture, "Drag to resize the window") : new GUIContent("R", "Drag to resize the window"); 86 | 87 | var closetexture = TextureHelper.FromResource( "ScienceChecklist.icons.close.png", 16, 16 ); 88 | closeContent = ( closetexture != null ) ? new GUIContent( closetexture, "Close window" ) : new GUIContent( "X", "Close window" ); 89 | } 90 | 91 | public bool IsVisible() 92 | { 93 | return visible; 94 | } 95 | 96 | public virtual void SetVisible(bool newValue) 97 | { 98 | this.visible = newValue; 99 | } 100 | 101 | public void ToggleVisible() 102 | { 103 | SetVisible(!visible); 104 | } 105 | 106 | public bool Contains(Vector2 point) 107 | { 108 | return windowPos.Contains(point); 109 | } 110 | 111 | public void SetSize(int width, int height) 112 | { 113 | windowPos.width = width; 114 | windowPos.height = height; 115 | } 116 | 117 | /* public virtual ConfigNode Load(ConfigNode config) 118 | { 119 | if (config.HasNode(configNodeName)) 120 | { 121 | ConfigNode windowConfig = config.GetNode(configNodeName); 122 | 123 | windowPos.x = Utilities.GetValue(windowConfig, "x", windowPos.x); 124 | windowPos.y = Utilities.GetValue(windowConfig, "y", windowPos.y); 125 | windowPos.width = Utilities.GetValue(windowConfig, "width", windowPos.width); 126 | windowPos.height = Utilities.GetValue(windowConfig, "height", windowPos.height); 127 | 128 | bool newValue = Utilities.GetValue(windowConfig, "visible", visible); 129 | SetVisible(newValue); 130 | 131 | return windowConfig; 132 | } 133 | else 134 | { 135 | return null; 136 | } 137 | } 138 | 139 | public virtual ConfigNode Save(ConfigNode config) 140 | { 141 | ConfigNode windowConfig; 142 | if (config.HasNode(configNodeName)) 143 | { 144 | windowConfig = config.GetNode(configNodeName); 145 | windowConfig.ClearData(); 146 | } 147 | else 148 | { 149 | windowConfig = config.AddNode(configNodeName); 150 | } 151 | 152 | windowConfig.AddValue("visible", visible); 153 | windowConfig.AddValue("x", windowPos.x); 154 | windowConfig.AddValue("y", windowPos.y); 155 | windowConfig.AddValue("width", windowPos.width); 156 | windowConfig.AddValue("height", windowPos.height); 157 | return windowConfig; 158 | }*/ 159 | 160 | public virtual void DrawWindow( ) 161 | { 162 | if (visible) 163 | { 164 | bool paused = false; 165 | if (HideWhenPaused && HighLogic.LoadedSceneIsFlight) 166 | { 167 | try 168 | { 169 | paused = PauseMenu.isOpen || FlightResultsDialog.isDisplaying; 170 | } 171 | catch (Exception) 172 | { 173 | // ignore the error and assume the pause menu is not open 174 | } 175 | } 176 | 177 | if (!paused) 178 | { 179 | ConfigureStyles( ); 180 | var oldSkin = GUI.skin; 181 | GUI.skin = _skin; 182 | 183 | windowPos = Utilities.EnsureVisible(windowPos); 184 | windowPos = GUILayout.Window( windowId, windowPos, PreDrawWindowContents, windowTitle, GUILayout.ExpandWidth(true), 185 | GUILayout.ExpandHeight(true), GUILayout.MinWidth(wScale(64)), GUILayout.MinHeight(wScale(64))); 186 | 187 | 188 | if( !string.IsNullOrEmpty( _lastTooltip ) ) 189 | { 190 | _tooltipStyle = _tooltipStyle ?? new GUIStyle( GUI.skin.window ) 191 | { 192 | // fontSize = wScale(11), 193 | normal = 194 | { 195 | background = GUI.skin.window.normal.background 196 | }, 197 | wordWrap = true 198 | }; 199 | 200 | _tooltipBoxStyle = _tooltipBoxStyle ?? new GUIStyle( GUI.skin.box ) 201 | { 202 | // int left, int right, int top, int bottom 203 | // fontSize = wScale(11), 204 | padding = wScale(new RectOffset(4, 4, 4, 4)), 205 | wordWrap = true 206 | }; 207 | 208 | float boxHeight = _tooltipBoxStyle.CalcHeight(new GUIContent(_lastTooltip), wScale(190)); 209 | GUI.Window(_tooltipWindowId, new Rect(Mouse.screenPos.x + wScale(15), Mouse.screenPos.y + wScale(15), wScale(200), boxHeight + wScale(10)), x => 210 | { 211 | GUI.Box(new Rect(wScale(5), wScale(5), wScale(190), boxHeight), _lastTooltip, _tooltipBoxStyle); 212 | }, string.Empty, _tooltipStyle ); 213 | } 214 | 215 | 216 | 217 | GUI.skin = oldSkin; 218 | } 219 | } 220 | } 221 | 222 | protected virtual void ConfigureStyles( ) 223 | { 224 | if( _skin == null ) 225 | { 226 | // Initialize our skin and styles. 227 | _skin = GameObject.Instantiate(HighLogic.Skin) as GUISkin; 228 | 229 | if (windowStyle == null) 230 | { 231 | windowStyle = new GUIStyle(_skin.window); 232 | windowStyle.fontSize = (int)(_skin.window.fontSize * UiScale); 233 | windowStyle.padding = wScale(_skin.window.padding); 234 | windowStyle.margin = wScale(_skin.window.margin); 235 | windowStyle.border = wScale(_skin.window.border); 236 | windowStyle.contentOffset = wScale(_skin.window.contentOffset); 237 | } 238 | _skin.window = windowStyle; 239 | 240 | if( closeButtonStyle == null ) 241 | { 242 | closeButtonStyle = new GUIStyle(_skin.button); 243 | closeButtonStyle.padding = wScale(new RectOffset(2, 2, 2, 2)); 244 | closeButtonStyle.margin = wScale(new RectOffset(1, 1, 1, 1)); 245 | closeButtonStyle.stretchWidth = false; 246 | closeButtonStyle.stretchHeight = false; 247 | closeButtonStyle.alignment = TextAnchor.MiddleCenter; 248 | } 249 | if( resizeStyle == null ) 250 | { 251 | resizeStyle = new GUIStyle(_skin.label); 252 | resizeStyle.alignment = TextAnchor.MiddleCenter; 253 | resizeStyle.padding = wScale(new RectOffset(1, 1, 1, 1)); 254 | } 255 | } 256 | } 257 | 258 | 259 | 260 | private void PreDrawWindowContents(int windowId) 261 | { 262 | DrawWindowContents(windowId); 263 | 264 | if (!HideCloseButton) 265 | { 266 | if (GUI.Button(wScale(new Rect(4, 4, 20, 20)), closeContent, closeButtonStyle)) 267 | { 268 | SetVisible(false); 269 | OnClose( EventArgs.Empty ); 270 | } 271 | } 272 | 273 | if (Resizable) 274 | { 275 | var resizeRect = new Rect(windowPos.width - wScale(16), windowPos.height - wScale(16), wScale(16), wScale(16)); 276 | GUI.Label(resizeRect, resizeContent, resizeStyle); 277 | 278 | HandleWindowEvents(resizeRect); 279 | } 280 | if( Event.current.type == EventType.Repaint && GUI.tooltip != _lastTooltip ) 281 | { 282 | _lastTooltip = GUI.tooltip; 283 | } 284 | 285 | // If this window gets focus, it pushes the tooltip behind the window, which looks weird. 286 | // Just hide the tooltip while mouse buttons are held down to avoid this. 287 | if( Input.GetMouseButton( 0 ) || Input.GetMouseButton( 1 ) || Input.GetMouseButton( 2 ) ) 288 | { 289 | _lastTooltip = string.Empty; 290 | } 291 | GUI.DragWindow( ); 292 | } 293 | 294 | protected abstract void DrawWindowContents( int windowId ); 295 | 296 | 297 | 298 | private void HandleWindowEvents(Rect resizeRect) 299 | { 300 | var theEvent = Event.current; 301 | if (theEvent != null) 302 | { 303 | if (!mouseDown) 304 | { 305 | if (theEvent.type == EventType.MouseDown && theEvent.button == 0 && resizeRect.Contains(theEvent.mousePosition)) 306 | { 307 | mouseDown = true; 308 | theEvent.Use(); 309 | } 310 | } 311 | else if (theEvent.type != EventType.Layout) 312 | { 313 | if (Input.GetMouseButton(0)) 314 | { 315 | // Flip the mouse Y so that 0 is at the top 316 | float mouseY = Screen.height - Input.mousePosition.y; 317 | 318 | windowPos.width = Mathf.Clamp(Input.mousePosition.x - windowPos.x + (resizeRect.width / 2), wScale(50), Screen.width - windowPos.x); 319 | windowPos.height = Mathf.Clamp(mouseY - windowPos.y + (resizeRect.height / 2), wScale(50), Screen.height - windowPos.y); 320 | } 321 | else 322 | { 323 | mouseDown = false; 324 | } 325 | } 326 | } 327 | } 328 | 329 | 330 | 331 | private void OnClose( EventArgs e ) 332 | { 333 | // _logger.Trace( "Window Closed" ); 334 | if( WindowClosed != null ) 335 | WindowClosed( this, e ); 336 | } 337 | 338 | 339 | 340 | protected virtual void OnUiScaleChange( ) 341 | { 342 | _skin = null; 343 | closeButtonStyle = null; 344 | resizeStyle = null; 345 | _tooltipStyle = null; 346 | _tooltipBoxStyle = null; 347 | windowStyle = null; 348 | 349 | ConfigureStyles( ); 350 | } 351 | 352 | protected int wScale(int v) { return Convert.ToInt32(Math.Round(v * UiScale)); } 353 | protected float wScale(float v) { return v * UiScale; } 354 | protected Rect wScale(Rect v) 355 | { 356 | return new Rect(wScale(v.x), wScale(v.y), wScale(v.width), wScale(v.height)); 357 | } 358 | protected RectOffset wScale(RectOffset v) 359 | { 360 | return new RectOffset(wScale(v.left), wScale(v.right), wScale(v.top), wScale(v.bottom)); 361 | } 362 | protected Vector2 wScale(Vector2 v) 363 | { 364 | return new Vector2(wScale(v.x), wScale(v.y)); 365 | } 366 | 367 | } 368 | 369 | } 370 | -------------------------------------------------------------------------------- /X-Science/Libraries/MiniAVC-1.0.3.0/CHANGES.txt: -------------------------------------------------------------------------------- 1 | 1.0.3.0 2 | Added: Remote version files take priority when local/remote add-on versions are the same. 3 | Added: 'Any' type versions are now fully supported. 4 | Added: Wildcards for version fields with '-1'. 5 | 6 | 1.0.2.4 7 | Updated for KSP v0.25.0 8 | Fixed: Typo in AddonInfo.ToString() 9 | Fixed: Bug with empty version files. 10 | 11 | 1.0.2.3 12 | Changed: Done a lot of under the hood refactoring. 13 | Fixed: Bug that would freeze the computer when checking many add-ons. 14 | 15 | 1.0.2.2 16 | Changed: Versions will always have the minimum formatting of 'x.x'. 17 | Fixed: Issue with non-RAW GitHub version file hosting, extending the url formatter. 18 | 19 | 1.0.2.1 20 | Added: Some extra exception handling and cleaned up some of the code. 21 | 22 | 1.0.2.0 23 | Added: GitHub latest release checking. 24 | Added: Version file reading is now case insensitive. 25 | Fixed: Bug in version equality checking. (Now using a custom VersionInfo object). 26 | 27 | 1.0.1.1 28 | Fixed: Bug where it did not do the allow check. 29 | 30 | 1.0.1.0 31 | Added: Tooltip when hovering over the download button showing the destination URL. 32 | Added: File not found handling. 33 | 34 | 1.0.0.0 35 | Initial release of MiniAVC based on the core KSP-AVC Plugin v1.1.1 system. -------------------------------------------------------------------------------- /X-Science/Libraries/MiniAVC-1.0.3.0/MiniAVC.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/Libraries/MiniAVC-1.0.3.0/MiniAVC.dll -------------------------------------------------------------------------------- /X-Science/Libraries/MiniAVC-1.0.3.0/README.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MiniAVC - README 6 | 7 | 112 | 113 | 114 |
115 |
MiniAVC Add-on Version Checker
116 | 117 |
118 |

Developer

119 |

CYBUTEK

120 |
121 | 122 |
123 |

KSP-AVC Ready

124 |

125 | KSP Add-on Version Checker is a standardised system for versioning mods. You can get more information on the 126 | forum thread. 127 |

128 |
129 | 130 |
131 |

Description

132 |

133 | This plugin checks inside its current directory and all contained directories for version files. It's use is for mods to make use of the KSP-AVC system without requiring the player to have the full KSP-AVC Plugin installed. The MiniAVC.dll plugin is safe to be bundled with mods and will negotiate between all other instances of MiniAVC to run the latest version. If an installation of KSP-AVC Plugin is found, the MiniAVC system will be disabled to let KSP-AVC take over. MiniAVC can check for both updates and game version compatibility, the same way as KSP-AVC Plugin does. The biggest difference is that because MiniAVC is a bundleable plugin, it will ask the player on the first run whether to allow update checking. If the user does not wish your add-on to check for updates, the remote checking functionality will be disabled. This will not completely turn off MiniAVC as it can still run in local mode to notify the player of any game version compatibility issues. 134 |

135 |
136 | 137 |
138 |

Installation

139 |
    140 |
  • Bundle the MiniAVC.dll file into your packaged add-on directory along with your version file.
  • 141 |
  • If your add-on contains multiple version files, place it at the lowest directory level which will cover all the version files, but do not place it in GameData.
  • 142 |
143 |
144 | 145 |
146 |

Community Add-on Rule 5.5

147 |

148 | The rule states that, "Add-ons that contact another network or computer system must tell users exactly what it's sending or receiving in a clear and obvious way in all locations it is offered for download." This means that if you bundle MiniAVC with your add-on, you must clearly notify players before downloading that it contains MiniAVC and how it works. 149 | 150 |

BB Code
151 | This mod includes version checking using [URL=http://forum.kerbalspaceprogram.com/threads/79745]MiniAVC[/URL]. If you opt-in, it will use the internet to check whether there is a new version available. Data is only read from the internet and no personal information is sent. For a more comprehensive version checking experience, please download the [URL=http://forum.kerbalspaceprogram.com/threads/79745]KSP-AVC Plugin[/URL]. 152 |
153 |
HTML
154 | This mod includes version checking using <a href="http://forum.kerbalspaceprogram.com/threads/79745">MiniAVC</a>. If you opt-in, it will use the internet to check whether there is a new version available. Data is only read from the internet and no personal information is sent. For a more comprehensive version checking experience, please download the <a href="http://forum.kerbalspaceprogram.com/threads/79745">KSP-AVC Plugin</a>. 155 |
156 |

157 |
158 | 159 |
160 |

Version File Breakdown

161 |

162 |

    163 |
  • NAME - Required
    164 | The display name for the add-on.
    165 |
  • 166 |
  • URL - Optional
    167 | Location of a remote version file for update checking. 168 |
  • 169 |
  • DOWNLOAD - Optional
    170 | Web address where the latest version can be downloaded.
    171 | This is only used from the remote version file. 172 |
  • 173 |
  • CHANGE_LOG - Optional
    174 | The complete or incremental change log for the add-on.
    175 | This is only used from the remote version file. 176 |
  • 177 |
  • CHANGE_LOG_URL - Optional
    178 | Populates the CHANGE_LOG field using the file at this url.
    179 | This is only used from the remote version file. 180 |
  • 181 |
  • GITHUB - Optional
    182 | Allows KSP-AVC to do release checks with GitHub including setting a download location if one is not specified.
    183 | If the latest release version is not equal to the version in the file, an update notification will not appear.
    184 | This is only used from the remote version file. 185 |
      186 |
    • USERNAME - Required
      187 | Your GitHub username. 188 |
    • 189 |
    • REPOSITORY - Required
      190 | The name of the source repository. 191 |
    • 192 |
    • ALLOW_PRE_RELEASE - Optional
      193 | Include pre-releases in the latest release search.
      194 | The default value is false. 195 |
    • 196 |
    197 |
  • 198 |
  • VERSION - Required
    199 | The version of the add-on. 200 |
  • 201 |
  • KSP_VERSION - Optional, Required for MIN/MAX
    202 | Version of KSP that the add-on was made to support. 203 |
  • 204 |
  • KSP_VERSION_MIN - Optional
    205 | Minimum version of KSP that the add-on supports.
    206 | Requires KSP_VERSION field to work. 207 |
  • 208 |
  • KSP_VERSION_MAX - Optional
    209 | Maximum version of KSP that the add-on supports.
    210 | Requires KSP_VERSION field to work. 211 |
  • 212 |
213 |
214 | For simple management of your version files you can use the KSP-AVC Online website at: ksp-avc.cybutek.net. 215 |

216 |
217 | 218 |
219 |

Version File Example

220 |

221 | {
222 |     "NAME":"KSP-AVC",
223 |     "URL":"http://ksp-avc.cybutek.net/version.php?id=2",
224 |     "DOWNLOAD":"http://kerbal.curseforge.com/ksp-mods/220462-ksp-avc-add-on-version-checker",
225 |     "GITHUB":
226 |     {
227 |         "USERNAME":"YourGitHubUserName",
228 |         "REPOSITORY":"YourGitHubRepository",
229 |         "ALLOW_PRE_RELEASE":false,
230 |     },
231 |     "VERSION":
232 |     {
233 |         "MAJOR":1,
234 |         "MINOR":1,
235 |         "PATCH":0,
236 |         "BUILD":0
237 |     },
238 |     "KSP_VERSION":
239 |     {
240 |         "MAJOR":0,
241 |         "MINOR":24,
242 |         "PATCH":2
243 |     },
244 |     "KSP_VERSION_MIN":
245 |     {
246 |         "MAJOR":0,
247 |         "MINOR":24,
248 |         "PATCH":0
249 |     },
250 |     "KSP_VERSION_MAX":
251 |     {
252 |         "MAJOR":0,
253 |         "MINOR":24,
254 |         "PATCH":2
255 |     }
256 | } 257 |

258 |
259 | 260 |
261 |

Change Log

262 | 263 |
264 | 265 |
266 |

Software License

267 |

268 | Licensed under the GNU General Public License v3. 269 |

270 |
271 | 272 | 273 |
274 | 275 |
276 | README design by CYBUTEK (GPLv3) 277 |
278 | 279 | -------------------------------------------------------------------------------- /X-Science/NewSelectionData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KSP; 3 | 4 | 5 | namespace ScienceChecklist 6 | { 7 | public class NewSelectionData : EventArgs 8 | { 9 | public MapObject _selectedObject; 10 | public NewSelectionData( MapObject SelectedObject ) 11 | { 12 | _selectedObject = SelectedObject; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /X-Science/NewSituationData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using KSP; 3 | 4 | 5 | namespace ScienceChecklist 6 | { 7 | public class NewSituationData : EventArgs 8 | { 9 | public Body _body; 10 | public ExperimentSituations _situation; 11 | public string _biome; 12 | public string _subBiome; 13 | 14 | 15 | 16 | public NewSituationData( Body Body, ExperimentSituations Situation, string biome, string subBiome ) 17 | { 18 | _body = Body; 19 | _situation = Situation; 20 | _biome = biome; 21 | _subBiome = subBiome; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /X-Science/Noise.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | 4 | 5 | namespace ScienceChecklist 6 | { 7 | sealed class Noise : MonoBehaviour 8 | { 9 | private static readonly Logger _logger = new Logger( "Noise" ); 10 | private static readonly string _file = "[x] Science!/bubbles"; 11 | 12 | private void Awake( ) 13 | { } 14 | 15 | private void OnDestroy( ) 16 | { } 17 | 18 | public void PlaySound( ) 19 | { 20 | if( gameObject == null ) 21 | { 22 | _logger.Debug( "gameObject is null!" ); 23 | return; 24 | } 25 | 26 | AudioSource audioSource = gameObject.GetComponent( ) ?? gameObject.AddComponent( ); 27 | if( audioSource != null ) 28 | { 29 | audioSource.spatialBlend = 0f; 30 | audioSource.panStereo = 0f; 31 | 32 | AudioClip Clip = null; 33 | Clip = GameDatabase.Instance.GetAudioClip( _file ); 34 | if( Clip == null ) 35 | { 36 | _logger.Debug( "No noise to play!" ); 37 | return; 38 | } 39 | 40 | audioSource.PlayOneShot( Clip, Mathf.Clamp( GameSettings.UI_VOLUME, 0f, 1f ) ); 41 | } 42 | else 43 | _logger.Debug( "No AudioSource" ); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /X-Science/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("[x] Science!")] 8 | [assembly: AssemblyDescription("")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("")] 11 | [assembly: AssemblyProduct("[x] Science!")] 12 | [assembly: AssemblyCopyright("Copyright © 2014")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("4705e880-6411-4426-a701-1d682fcc2c7d")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("5.17.*")] 35 | -------------------------------------------------------------------------------- /X-Science/ScienceInstance.cs: -------------------------------------------------------------------------------- 1 |  2 | namespace ScienceChecklist { 3 | /// 4 | /// An object that represents a ScienceExperiement in a given Situation. 5 | /// 6 | public sealed class ScienceInstance { 7 | #region FIELDS 8 | private readonly ScienceExperiment _experiment; 9 | private readonly Situation _situation; 10 | #endregion 11 | 12 | 13 | /// 14 | /// Creates a new instance of the Experiment class. 15 | /// 16 | /// The ScienceExperiment to be used. 17 | /// The Situation this experiment is valid in. 18 | /// A collection of all onboard ScienceData. 19 | public ScienceInstance( ScienceExperiment experiment, Situation situation, ScienceContext Sci ) 20 | { 21 | _experiment = experiment; 22 | _situation = situation; 23 | ScienceSubject = null; 24 | Update( Sci ); 25 | } 26 | 27 | #region PROPERTIES 28 | 29 | /// 30 | /// Gets the ScienceExperiment used by ResearchAndDevelopment. 31 | /// 32 | public ScienceExperiment ScienceExperiment { get { return _experiment; } } 33 | /// 34 | /// Gets the Situation in which this experiment is valid. 35 | /// 36 | public Situation Situation { get { return _situation; } } 37 | 38 | /// 39 | /// Gets the ResearchAndDevelopment ID for this experiment. 40 | /// 41 | public string Id { 42 | get { 43 | return string.Format("{0}@{1}{2}{3}", ScienceExperiment.id, Situation.Body.Name, Situation.ExperimentSituation, (Situation.SubBiome ?? Situation.Biome ?? string.Empty).Replace(" ", "")); 44 | } 45 | } 46 | 47 | /// 48 | /// Gets the amount of science completed for this experiment. 49 | /// 50 | public float CompletedScience { get; private set; } 51 | /// 52 | /// Gets a value indicating if this experiment has been unlocked in the tech tree. 53 | /// 54 | public bool IsUnlocked { get; private set; } 55 | /// 56 | /// Gets the total amount of science available for this experiment. 57 | /// 58 | public float TotalScience { get; private set; } 59 | /// 60 | /// Gets a value indicating whether all the science has been obtained for this experiment. 61 | /// This is science that has made it back to KSC 62 | /// 63 | public bool IsComplete { get; private set; } 64 | 65 | /// 66 | /// Completed Science + Onboard Science science 67 | /// 68 | public bool IsCollected { get; private set; } 69 | 70 | /// 71 | /// Gets the amount of science for this experiment that is currently stored on vessels. 72 | /// 73 | public float OnboardScience { get; private set; } 74 | /// 75 | /// Gets the ScienceSubject containing information on how much science has been retrieved from this experiment. 76 | /// 77 | public ScienceSubject ScienceSubject { get; private set; } 78 | 79 | /// 80 | /// Gets the human-readable description of this experiment. 81 | /// 82 | public string Description { 83 | get { 84 | return string.Format( 85 | "{0} while {1}", 86 | ScienceExperiment.experimentTitle, 87 | Situation.Description); 88 | } 89 | } 90 | 91 | public string ShortDescription { get { return ScienceExperiment.experimentTitle; } } 92 | 93 | #endregion 94 | 95 | #region METHODS (PUBLIC) 96 | 97 | /// 98 | /// Updates the IsUnlocked, CompletedScience, TotalScience, OnboardScience, and IsComplete fields. 99 | /// 100 | /// The total onboard ScienceData. 101 | public void Update( ScienceContext Sci ) 102 | { 103 | if( Sci.ScienceSubjects.ContainsKey( Id ) ) 104 | ScienceSubject = Sci.ScienceSubjects[ Id ]; 105 | else ScienceSubject = new ScienceSubject(ScienceExperiment, Situation.ExperimentSituation, Situation.Body.CelestialBody, Situation.SubBiome ?? Situation.Biome ?? string.Empty); 106 | 107 | 108 | IsUnlocked = Sci.UnlockedInstruments.IsUnlocked( ScienceExperiment.id ) && ( Situation.Body.Reached != null ); 109 | 110 | CompletedScience = ScienceSubject.science * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; 111 | TotalScience = ScienceSubject.scienceCap * HighLogic.CurrentGame.Parameters.Career.ScienceGainMultiplier; 112 | IsComplete = CompletedScience > TotalScience || TotalScience - CompletedScience < 0.1; 113 | 114 | var multiplier = ScienceExperiment.baseValue / ScienceExperiment.scienceCap; 115 | 116 | 117 | 118 | OnboardScience = 0; 119 | if( Sci.OnboardScienceList.ContainsKey( ScienceSubject.id ) ) 120 | { 121 | var data = Sci.OnboardScienceList[ ScienceSubject.id ]; 122 | // var _logger = new Logger( "Experiment" ); 123 | // _logger.Trace( ScienceSubject.id + " found " + data.Count( ) + " items" ); 124 | 125 | for( int x = 0; x < data.Count; x++ ) 126 | { 127 | var next = (TotalScience - (CompletedScience + OnboardScience)) * multiplier; 128 | OnboardScience += next; 129 | } 130 | } 131 | var AllCollectedScience = CompletedScience + OnboardScience; 132 | IsCollected = AllCollectedScience > TotalScience || TotalScience - AllCollectedScience < 0.1; 133 | } 134 | #endregion 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /X-Science/SettingsWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | 5 | 6 | namespace ScienceChecklist 7 | { 8 | class SettingsWindow : Window 9 | { 10 | private readonly string version; 11 | private GUIStyle labelStyle; 12 | private GUIStyle toggleStyle; 13 | private GUIStyle sliderStyle; 14 | private GUIStyle editStyle; 15 | private GUIStyle versionStyle; 16 | private GUIStyle selectionStyle; 17 | 18 | private readonly Logger _logger; 19 | private readonly ScienceChecklistAddon _parent; 20 | 21 | 22 | 23 | // Constructor 24 | public SettingsWindow( ScienceChecklistAddon Parent ) 25 | : base( "[x] Science! Settings", 240, 360 ) 26 | { 27 | _logger = new Logger( this ); 28 | _parent = Parent; 29 | UiScale = 1; // Don't let this change 30 | version = Utilities.GetDllVersion( this ); 31 | } 32 | 33 | 34 | // For our Window base class 35 | protected override void ConfigureStyles( ) 36 | { 37 | base.ConfigureStyles( ); 38 | 39 | if( labelStyle == null ) 40 | { 41 | labelStyle = new GUIStyle( _skin.label ); 42 | labelStyle.wordWrap = false; 43 | labelStyle.fontStyle = FontStyle.Normal; 44 | labelStyle.normal.textColor = Color.white; 45 | 46 | toggleStyle = new GUIStyle( _skin.toggle ); 47 | sliderStyle = new GUIStyle( _skin.horizontalSlider ); 48 | editStyle = new GUIStyle( _skin.textField ); 49 | versionStyle = Utilities.GetVersionStyle( ); 50 | selectionStyle = new GUIStyle( _skin.button ); 51 | selectionStyle.margin = new RectOffset( 30, 0, 0, 0 ); 52 | } 53 | } 54 | 55 | 56 | 57 | // For our Window base class 58 | protected override void DrawWindowContents( int windowID ) 59 | { 60 | GUILayout.BeginVertical( ); 61 | 62 | bool save = false; 63 | var toggle = GUILayout.Toggle( _parent.Config.HideCompleteExperiments, new GUIContent( "Hide complete experiments", "Experiments considered complete will not be shown." ), toggleStyle ); 64 | if( toggle != _parent.Config.HideCompleteExperiments ) 65 | { 66 | _parent.Config.HideCompleteExperiments = toggle; 67 | save = true; 68 | } 69 | 70 | toggle = GUILayout.Toggle( _parent.Config.CompleteWithoutRecovery, new GUIContent( "Complete without recovery", "Show experiments as completed even if they have not been recovered yet.\nYou still need to recover the science to get the points!\nJust easier to see what is left." ), toggleStyle ); 71 | if( toggle != _parent.Config.CompleteWithoutRecovery ) 72 | { 73 | _parent.Config.CompleteWithoutRecovery = toggle; 74 | save = true; 75 | } 76 | 77 | toggle = GUILayout.Toggle( _parent.Config.CheckDebris, new GUIContent( "Check debris", "Vessels marked as debris will be checked for recoverable science." ), toggleStyle ); 78 | if( toggle != _parent.Config.CheckDebris ) 79 | { 80 | _parent.Config.CheckDebris = toggle; 81 | save = true; 82 | } 83 | 84 | toggle = GUILayout.Toggle( _parent.Config.AllFilter, new GUIContent( "Allow all filter", "Adds a filter button showing all experiments, even on unexplored bodies using unavailable instruments.\nMight be considered cheating." ), toggleStyle ); 85 | if( toggle != _parent.Config.AllFilter ) 86 | { 87 | _parent.Config.AllFilter = toggle; 88 | save = true; 89 | } 90 | 91 | toggle = GUILayout.Toggle( _parent.Config.FilterDifficultScience, new GUIContent( "Filter difficult science", "Hide a few experiments such as flying at stars and gas giants that are almost impossible.\n Also most EVA reports before upgrading Astronaut Complex." ), toggleStyle ); 92 | if( toggle != _parent.Config.FilterDifficultScience ) 93 | { 94 | _parent.Config.FilterDifficultScience = toggle; 95 | save = true; 96 | } 97 | 98 | toggle = GUILayout.Toggle( _parent.Config.SelectedObjectWindow, new GUIContent( "Selected Object Window", "Show the Selected Object Window in the Tracking Station." ), toggleStyle ); 99 | if( toggle != _parent.Config.SelectedObjectWindow ) 100 | { 101 | _parent.Config.SelectedObjectWindow = toggle; 102 | save = true; 103 | } 104 | 105 | if( BlizzysToolbarButton.IsAvailable ) 106 | { 107 | toggle = GUILayout.Toggle( _parent.Config.UseBlizzysToolbar, new GUIContent( "Use blizzy78's toolbar", "Remove [x] Science button from stock toolbar and add to blizzy78 toolbar." ), toggleStyle ); 108 | if( toggle != _parent.Config.UseBlizzysToolbar ) 109 | { 110 | _parent.Config.UseBlizzysToolbar = toggle; 111 | save = true; 112 | } 113 | } 114 | 115 | GUILayout.Space(2); 116 | int selected = 0; 117 | if( !_parent.Config.RighClickMutesMusic ) 118 | selected = 1; 119 | int new_selected = selected; 120 | GUILayout.Label( "Right click [x] icon", labelStyle ); 121 | GUIContent[] Options = { 122 | new GUIContent( "Mute music", "Here & Now window gets its own icon" ), 123 | new GUIContent( "Opens Here & Now window", "Here & Now icon is hidden" ) 124 | }; 125 | new_selected = GUILayout.SelectionGrid( selected, Options, 1, selectionStyle ); 126 | if( new_selected != selected ) 127 | { 128 | if( new_selected == 0 ) 129 | _parent.Config.RighClickMutesMusic = true; 130 | else 131 | _parent.Config.RighClickMutesMusic = false; 132 | save = true; 133 | } 134 | 135 | if( _parent.Config.RighClickMutesMusic ) 136 | { 137 | toggle = GUILayout.Toggle( _parent.Config.MusicStartsMuted, new GUIContent( "Music starts muted", "Title music is silenced upon load. No need to right click" ), toggleStyle ); 138 | if( toggle != _parent.Config.MusicStartsMuted ) 139 | { 140 | _parent.Config.MusicStartsMuted = toggle; 141 | save = true; 142 | } 143 | } 144 | 145 | GUILayout.Space(2); 146 | GUILayout.Label(new GUIContent( "Adjust UI size", "Adjusts the the UI scaling." ), labelStyle ); 147 | var slider = GUILayout.HorizontalSlider( _parent.Config.UiScale, 1, 2 ); 148 | if( slider != _parent.Config.UiScale ) 149 | { 150 | _parent.Config.UiScale = slider; 151 | save = true; 152 | } 153 | 154 | if( save ) 155 | _parent.Config.Save( ); 156 | 157 | GUILayout.EndVertical( ); 158 | GUILayout.Space(10); 159 | GUI.Label( new Rect( 4, windowPos.height - 13, windowPos.width - 20, 12 ), "[x] Science! V" + version, versionStyle ); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /X-Science/ShipState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using System.Linq; 4 | using System.Collections.Generic; 5 | 6 | using System.Reflection; 7 | using KSP.UI.Screens; 8 | 9 | 10 | 11 | namespace ScienceChecklist 12 | { 13 | public enum Statuses { none, seat, pod } 14 | class ShipStateWindow : Window 15 | { 16 | private GUIStyle labelStyle; 17 | private GUIStyle sectionStyle; 18 | private Vector2 scrollPosition; 19 | private readonly ScienceChecklistAddon _parent; 20 | private readonly Logger _logger; 21 | private MapObject SelectedObject; 22 | public Statuses status = Statuses.none; 23 | 24 | 25 | public ShipStateWindow( ScienceChecklistAddon Parent ) 26 | : base( "[x] Science! Selected Object", 250, 30 ) 27 | { 28 | _parent = Parent; 29 | UiScale = _parent.Config.UiScale; 30 | scrollPosition = Vector2.zero; 31 | _parent.Config.UiScaleChanged += OnUiScaleChange; 32 | _logger = new Logger( this ); 33 | SelectedObject = null; 34 | 35 | _parent.ScienceEventHandler.MapObjectSelected += ( s, e ) => MapObjectSelected( s, e ); 36 | } 37 | 38 | 39 | 40 | protected override void ConfigureStyles( ) 41 | { 42 | base.ConfigureStyles(); 43 | 44 | if( labelStyle == null ) 45 | { 46 | labelStyle = new GUIStyle( _skin.label ); 47 | labelStyle.wordWrap = true; 48 | labelStyle.fontStyle = FontStyle.Normal; 49 | labelStyle.normal.textColor = Color.white; 50 | labelStyle.stretchWidth = true; 51 | labelStyle.stretchHeight = false; 52 | labelStyle.margin.bottom -= wScale( 2 ); 53 | labelStyle.padding.bottom -= wScale( 2 ); 54 | } 55 | 56 | if( sectionStyle == null ) 57 | { 58 | sectionStyle = new GUIStyle( labelStyle ); 59 | sectionStyle.fontStyle = FontStyle.Bold; 60 | } 61 | } 62 | 63 | 64 | 65 | private void OnUiScaleChange( object sender, EventArgs e ) 66 | { 67 | UiScale = _parent.Config.UiScale; 68 | labelStyle = null; 69 | sectionStyle = null; 70 | base.OnUiScaleChange( ); 71 | ConfigureStyles( ); 72 | } 73 | 74 | 75 | 76 | protected override void DrawWindowContents( int windowID ) 77 | { 78 | switch( SelectedObject.type ) 79 | { 80 | case MapObject.ObjectType.CelestialBody: 81 | DrawBody( ); 82 | break; 83 | case MapObject.ObjectType.Vessel: 84 | DrawVessel( ); 85 | break; 86 | } 87 | } 88 | 89 | protected void DrawBody( ) 90 | { 91 | string Title = ""; 92 | string Text = ""; 93 | if( SelectedObject.celestialBody ) 94 | { 95 | Body Body = _parent.Science.BodyList[ SelectedObject.celestialBody ]; 96 | Title += "Body: " + GameHelper.LocalizeBodyName( Body.CelestialBody.displayName ) + "\n"; 97 | Title += Body.Type; 98 | if( Body.IsHome ) 99 | Title += " - Home!"; 100 | 101 | 102 | 103 | Text += "Space high: " + (Body.CelestialBody.scienceValues.spaceAltitudeThreshold/1000) + "km"; 104 | if( Body.HasAtmosphere ) 105 | { 106 | Text += "\nAtmos depth: " + (Body.CelestialBody.atmosphereDepth/1000) + "km"; 107 | Text += "\nFlying high: " + (Body.CelestialBody.scienceValues.flyingAltitudeThreshold/1000) + "km"; 108 | if( Body.HasOxygen ) 109 | Text += "\nHas oxygen - jets work"; 110 | } 111 | else 112 | Text += "\nNo kind of atmosphere"; 113 | 114 | if( Body.HasSurface ) 115 | { 116 | if( Body.HasOcean ) 117 | Text += "\nHas oceans"; 118 | } 119 | else 120 | Text += "\nNo surface"; 121 | } 122 | 123 | scrollPosition = GUILayout.BeginScrollView( scrollPosition ); 124 | GUILayout.BeginVertical( GUILayout.ExpandWidth( true ) ); 125 | 126 | GUILayout.Label( Title, sectionStyle, GUILayout.ExpandWidth( true ) ); 127 | GUILayout.Space( wScale( 16 ) ); 128 | GUILayout.Label( Text, labelStyle, GUILayout.ExpandWidth( true ) ); 129 | 130 | GUILayout.EndVertical( ); 131 | GUILayout.EndScrollView( ); 132 | 133 | GUILayout.Space( wScale( 8 ) ); 134 | } 135 | 136 | 137 | 138 | protected void DrawVessel( ) 139 | { 140 | string Title = ""; 141 | string Text = ""; 142 | if( SelectedObject.vessel != null && SelectedObject.vessel.protoVessel != null ) 143 | { 144 | if( SelectedObject.vessel.DiscoveryInfo.Level != DiscoveryLevels.Owned ) 145 | Title = "Unowned object"; 146 | else 147 | { 148 | Title = SelectedObject.vessel.GetName( ); 149 | ProtoVessel proto = SelectedObject.vessel.protoVessel; 150 | double mass = 0; 151 | var res = new SortedDictionary(); 152 | foreach (ProtoPartSnapshot p in proto.protoPartSnapshots) 153 | { 154 | foreach (var r in p.resources) { 155 | xResourceData d; 156 | if (res.ContainsKey(r.resourceName)) 157 | d = res[r.resourceName]; 158 | else { 159 | d = new xResourceData(r.resourceName); 160 | } 161 | d.current += r.amount; 162 | d.max += r.maxAmount; 163 | res[r.resourceName] = d; 164 | } 165 | mass += p.mass; 166 | CheckCommand( p ); 167 | } 168 | 169 | 170 | 171 | var texts = res.Values.ToList().ConvertAll(d => d.ToString()); 172 | 173 | if (!SelectedObject.vessel.isEVA) 174 | { 175 | texts.Add(""); 176 | var crew = proto.GetVesselCrew().Count(); 177 | mass += res.Values.Sum(d => d.GetMass()); 178 | var parts = proto.protoPartSnapshots.Count(); 179 | texts.Add(string.Format( "Crew: {0}, Parts: {1}, Mass: {2:f2}t", crew, parts, mass ) ); 180 | 181 | 182 | 183 | switch( this.status ) 184 | { 185 | case Statuses.pod: 186 | break; 187 | case Statuses.none: 188 | texts.Add( "No command pod" ); 189 | break; 190 | case Statuses.seat: 191 | texts.Add( "Has command seat" ); 192 | break; 193 | } 194 | } 195 | 196 | Text = string.Join("\n", texts.ToArray()); 197 | 198 | } 199 | 200 | 201 | 202 | } 203 | 204 | 205 | 206 | 207 | 208 | scrollPosition = GUILayout.BeginScrollView( scrollPosition ); 209 | GUILayout.BeginVertical( GUILayout.ExpandWidth( true ) ); 210 | 211 | GUILayout.Label( Title, sectionStyle, GUILayout.ExpandWidth( true ) ); 212 | GUILayout.Space( wScale( 16 ) ); 213 | GUILayout.Label( Text, labelStyle, GUILayout.ExpandWidth( true ) ); 214 | 215 | GUILayout.EndVertical( ); 216 | GUILayout.EndScrollView( ); 217 | 218 | GUILayout.Space( wScale( 8 ) ); 219 | } 220 | 221 | 222 | public void CheckCommand( ProtoPartSnapshot part ) 223 | { 224 | if( status == Statuses.pod ) 225 | return; 226 | 227 | foreach( var m in part.modules ) 228 | { 229 | if (m.moduleName == "ModuleCommand") { 230 | status = Statuses.pod; 231 | return; 232 | } 233 | if (m.moduleName == "KerbalSeat") { 234 | status = Statuses.seat; 235 | } 236 | } 237 | } 238 | 239 | 240 | public void MapObjectSelected( object sender, NewSelectionData SelectionData ) 241 | { 242 | _logger.Trace( "MapObjectSelected" ); 243 | _logger.Trace( SelectionData._selectedObject.type.ToString( ) ); 244 | 245 | if( !_parent.Config.SelectedObjectWindow ) 246 | return; 247 | 248 | switch( SelectionData._selectedObject.type ) 249 | { 250 | case MapObject.ObjectType.CelestialBody: 251 | SetVisible( true ); 252 | SelectedObject = SelectionData._selectedObject; 253 | if( !_parent.Science.BodyList.ContainsKey( SelectedObject.celestialBody ) ) 254 | _parent.Science.Reset( ); 255 | break; 256 | case MapObject.ObjectType.Vessel: 257 | SetVisible( true ); 258 | SelectedObject = SelectionData._selectedObject; 259 | break; 260 | default: 261 | SetVisible( false ); 262 | break; 263 | } 264 | 265 | } 266 | 267 | 268 | 269 | public WindowSettings BuildSettings( ) 270 | { 271 | //_logger.Info( "BuildSettings" ); 272 | WindowSettings W = new WindowSettings( ScienceChecklistAddon.WINDOW_NAME_SHIP_STATE ); 273 | W.Set( "Top", (int)windowPos.yMin ); 274 | W.Set( "Left", (int)windowPos.xMin ); 275 | W.Set( "Width", (int)windowPos.width ); 276 | W.Set( "Height", (int)windowPos.height ); 277 | 278 | return W; 279 | } 280 | 281 | 282 | 283 | public void ApplySettings( WindowSettings W ) 284 | { 285 | windowPos.yMin = W.GetInt( "Top", 40 ); 286 | windowPos.xMin = W.GetInt( "Left", 40 ); 287 | windowPos.width = W.GetInt( "Width", 200 ); 288 | windowPos.height = W.GetInt( "Height", 200 ); 289 | 290 | if( windowPos.width < 100 ) 291 | windowPos.width = 100; 292 | 293 | if( windowPos.width < 50 ) 294 | windowPos.width = 50; 295 | 296 | } 297 | } 298 | 299 | 300 | 301 | class xResourceData { 302 | public double current, max; 303 | 304 | public readonly string name; 305 | readonly PartResourceDefinition def; 306 | 307 | public xResourceData(string name) { 308 | this.name = name; 309 | this.def = PartResourceLibrary.Instance.GetDefinition(name); 310 | } 311 | 312 | public double GetMass() { 313 | return def == null ? 0 : def.density * current; 314 | } 315 | 316 | public override string ToString() { 317 | return string.Format("{0}: {1} / {2}", name, s(current), s(max)); 318 | } 319 | 320 | private static string s(double d) { 321 | return d.ToString(d < 100 ? "f2" : "f0"); 322 | } 323 | } 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | } -------------------------------------------------------------------------------- /X-Science/Situation.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | 4 | 5 | 6 | namespace ScienceChecklist { 7 | /// 8 | /// A location in which experiments may be conducted. 9 | /// Many experiments may, perhaps, be conducted. Those create "ScienceInstance"s 10 | /// 11 | public sealed class Situation { 12 | /// 13 | /// Creates a new instance of the Situation class. 14 | /// 15 | /// The CelestialBody around which this situation is for. 16 | /// The ExperimentSituations flag which this situation is for. 17 | /// Optionally, the biome which this situation is for. 18 | /// Optionally, the KSC biome which this situation is for. 19 | public Situation( Body body, ExperimentSituations situation, string biome = null, string subBiome = null ) { 20 | _body = body; 21 | _situation = situation; 22 | _biome = biome; 23 | _subBiome = subBiome; 24 | _formattedBiome = BiomeToString(_biome); 25 | _formattedSubBiome = BiomeToString(_subBiome); 26 | _description = string.Format("{0} {1}{2}", 27 | ToString(_situation), 28 | GameHelper.LocalizeBodyName( Body.CelestialBody.displayName ), 29 | string.IsNullOrEmpty(_formattedBiome) 30 | ? string.Empty 31 | : string.IsNullOrEmpty(_formattedSubBiome) 32 | ? string.Format("'s {0}", _formattedBiome) 33 | : string.Format("'s {0} ({1})", _formattedSubBiome, _formattedBiome)); 34 | } 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | /// 51 | /// Gets the CelestialBody this situation is for. 52 | /// 53 | public Body Body { get { return _body; } } 54 | /// 55 | /// Gets the ExperimentSituations this situation is for. 56 | /// 57 | public ExperimentSituations ExperimentSituation { get { return _situation; } } 58 | /// 59 | /// Gets the biome this situation is for. 60 | /// 61 | public string Biome { get { return _biome; } } 62 | /// 63 | /// Gets the KSC biome this situation is for. 64 | /// 65 | public string SubBiome { get { return _subBiome; } } 66 | /// 67 | /// Gets the human-readable biome this situation is for. 68 | /// 69 | public string FormattedBiome { get { return _formattedBiome; } } 70 | /// 71 | /// Gets the human-readable KSC biome this situation is for. 72 | /// 73 | public string FormattedSubBiome { get { return _formattedSubBiome; } } 74 | /// 75 | /// Gets the human-readable description for this situation. 76 | /// 77 | public string Description { get { return _description; } } 78 | 79 | 80 | 81 | /// 82 | /// Converts an ExperimentSituations to a human-readable representation. 83 | /// 84 | /// The ExperimentSituations to be converted. 85 | /// The human-readable form of the ExperimentSituations. 86 | private string ToString ( ExperimentSituations situation ) 87 | { 88 | switch (situation) { 89 | case ExperimentSituations.FlyingHigh: 90 | return "flying high over"; 91 | case ExperimentSituations.FlyingLow: 92 | return "flying low over"; 93 | case ExperimentSituations.InSpaceHigh: 94 | return "in space high over"; 95 | case ExperimentSituations.InSpaceLow: 96 | return "in space near"; 97 | case ExperimentSituations.SrfLanded: 98 | return "landed at"; 99 | case ExperimentSituations.SrfSplashed: 100 | return "splashed down at"; 101 | default: 102 | return situation.ToString(); 103 | } 104 | } 105 | 106 | /// 107 | /// Converts a biome to a human-readable representation. 108 | /// 109 | /// The biome to be converted. 110 | /// The human-readable form of the biome. 111 | private string BiomeToString (string biome) { 112 | return Regex.Replace(biome ?? string.Empty, "((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", " $1").Replace(" ", " ").Trim(); 113 | } 114 | 115 | private readonly Body _body; 116 | private readonly ExperimentSituations _situation; 117 | private readonly string _biome; 118 | private readonly string _subBiome; 119 | private readonly string _formattedBiome; 120 | private readonly string _formattedSubBiome; 121 | private readonly string _description; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /X-Science/ToDo.txt: -------------------------------------------------------------------------------- 1 | TO DO LIST 2 | ---------- 3 | 4 | [DONE] Event handler and no coroutines 5 | [DONE] Window positions 6 | [DONE] Fix long text 7 | [DONE] Summary tooltip 8 | [DONE] Visibility doesn't stick 9 | [DONE] Button class 10 | [DONE] Compact mode use same icons 11 | [DONE] Drag bar 12 | [DONE] Seperate settings window 13 | [DONE] Help window 14 | [DONE] Backup skin then restore 15 | [DONE] Window class 16 | [DONE] Merge settings panel into window 17 | [DONE] Setting events 18 | [DONE] Help content 19 | [DONE] Science totals tool tip doesn't include partially collected science 20 | [DONE] Filter text + state 21 | [DONE] Finish icons 22 | [DONE] Is there any way to avoid the KSC baby biomes in science.cfg? I use AvoidSrfLanded but the KSC biomes still show up. 23 | [DONE] Remaining science tool tip - adding onboard science not removing it 24 | 25 | [DONE] Passing parent so add eventhandler to parent 26 | [DONE] Reorganise parent into more sensible sections. 27 | [DONE] Give Event handler hooks. 28 | [DONE] Event handler just re-throws events to who ever is listening. 29 | [DONE] Pass Event handler both windows. 30 | [DONE] Windows hook the events they need. 31 | 32 | [DONE] Move AllScienceInstances out of ExperimentFilter 33 | [DONE] Also the 2 refresh functions 34 | [DONE] Move config events to config object. 35 | [DONE] Regularly tell things the current situation 36 | 37 | [DONE] Event handler to recalculate science status as required. 38 | [DONE] Add one filter to each window 39 | [DONE] Move biome detection out of window 40 | [DONE] Clear blue water between science and GUI 41 | [DONE] Click to run experiment 42 | [DONE] Overide config settings in filter. 43 | [DONE] Hide when done/instrument is full/cant be run 44 | [DONE] Status window is always in Lablander mode 45 | [DONE] Stop time 46 | [DONE] Play noise 47 | [DONE] Grey buttons should be labels 48 | [DONE] Cache available experiments list in status window. 49 | 50 | [DONE] Don't rely on Kerbin+Shores 51 | [DONE] Ltech 52 | [DONE] Message on screen when changing biome. 53 | [DONE] Science in vehicle 54 | [DONE] Green bar 55 | [DONE] Ui Scaling from GitHub 56 | [DONE] FILTER in config file 57 | [DONE] Difficult science filter 58 | [DONE] Check weird bugs in status window 59 | 60 | [DONE] Situation bug on KSC window. 61 | [DONE] Orbital Science 62 | [DONE] Test with new science plugin by DMagic 63 | [DONE] Only fire stock science if we can't use the new ones 64 | [DONE] Add arguments for settings to avoid dependency. 65 | [DONE] Not storing button settings correctly 66 | [NOT SEEN] Open Here&Now before checklist - throws exception 67 | [NOT SEEN] H&N pops even if all science is done - May be when complete but not recovered 68 | [DONEish] New Baby Biome - probably a bug - new collider on wrong layer. 69 | (Added filter for KSC2. Being added to "shores" when probably should be grasslands, in RSS -> anybody's guess.) 70 | [DONE] Save settings more often - after filter change 71 | [NOT SEEN - DONE IT ANYWAY]Save settings more often - when leaving any scene and going to any scene 72 | [DONE] Config settings for Here&Now window 73 | [DONE] Here&Now Settings 74 | [DONE] New buttons 75 | [DONE] Dont show results window. 76 | [DONE] Right click to open h&N or MusicMute! 77 | ------------------------------------------------ 78 | [DONE] Resources in tracking station 79 | [DONE] Body info window 80 | [DONE] Vehicles 81 | [DONE] Rewrite settings 82 | [DONE] Vehicle category from rename window 83 | [DONE] Window settings for new window 84 | [DONE] Popping when science is available but experiments not runnable. Deal with CrewReport, EvaReport and SoilSample. 85 | 86 | 87 | --- NEXT ---------------------------------------- 88 | Add new options to help 89 | Settings window is getting ugly 90 | 91 | In selected object window - Is controlable + Has lab + Total amount of science stored 92 | 93 | Move decisions as to what is completed into a function 94 | Setting for when things are considered completed 95 | If something has 0 science collected then it cant be completed 96 | -------------------------------------------------- 97 | 98 | 99 | 100 | 101 | ---------------------------------------------------- 102 | Funding 103 | Biome list, has Lab, list of vessels 104 | Check map for water biomes. 105 | ---------------------------------------------------- 106 | 107 | 108 | Need red icons 109 | rename window 110 | img/sprite class - Load all in one place 111 | Visibility is weird. 112 | 113 | 114 | Pop icon when necessary. 115 | Put each icon into class 116 | Give icon to own window 117 | 118 | * Window class config 119 | * Window width 120 | * Store pre-calculated content where possible. 121 | 122 | 123 | 124 | /* 125 | * TO DO 126 | * 127 | * RECOVERY science 128 | * SCANSAT 129 | * RESOURCES 130 | * Weird Orbital Science experiments 131 | * 132 | */ 133 | 134 | 135 | 136 | 137 | /* Detect RMB 138 | if (Input.GetMouseButtonUp(1)) 139 | { 140 | onRightButtonStockClick(); 141 | } 142 | else 143 | { 144 | onLeftButtonClick(); 145 | }*/ 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Sprite.Create(texture, rect, pivot); 160 | 161 | 162 | 163 | The rectangle parameter is the source rectangle on the texture. If you want to use the whole texture as the sprite, use new Rect(0, 0, texture.width, texture.height); 164 | 165 | I believe the pivot is actually a percentage and not a pixel/unit value. So if you wanted to pivot at the center of the texture you would use new Vector2(0.5f, 0.5f) 166 | 167 | Sorry for the pseudo code, away from Unity at the moment. 168 | 169 | Hope this helps! 170 | 171 | 172 | 173 | 174 | 175 | ======================================= 176 | 177 | 178 | http://unity3d.com/support/documentation/ScriptReference/Texture2D.GetPixels.html 179 | 180 | 181 | function GetPixels (x : int, y : int, blockWidth : int, blockHeight : int, miplevel : int) : Color[] 182 | Description 183 | 184 | Get a block of pixel colors. 185 | 186 | This function is an extended version of GetPixels above; it does not return the whole mip level but only blockWidth by blockHeight region starting at x,y. The block must fit into the used mip level. The returned array is blockWidth*blockHeight size. 187 | 188 | to write them back: 189 | 190 | http://unity3d.com/support/documentation/ScriptReference/Texture2D.SetPixels.html 191 | 192 | function SetPixels (x : int, y : int, blockWidth : int, blockHeight : int, colors : Color[], miplevel : int) : void 193 | Description 194 | 195 | Set a block of pixel colors. 196 | 197 | This function is an extended version of SetPixels above; it does not modify the whole mip level but modifies only blockWidth by blockHeight region starting at x,y. The colors array must be blockWidth*blockHeight size, and the modified block must fit into the used mip level. 198 | 199 | 200 | 201 | ================== 202 | 203 | Check the GetPixels and SetPixels funcitons in Texture2D. It sounds like you should have a good idea of what to do from there. 204 | 205 | ========================= 206 | 207 | 208 | You can also use this if you want to copy the whole texture: 209 | 210 | // duplicate the original texture 211 | var texture : Texture2D = Instantiate(renderer.material.mainTexture); 212 | 213 | You can also reference the whole texture: 214 | 215 | // reference the original texture 216 | var texture : Texture2D = renderer.material.mainTexture; 217 | 218 | 219 | ------------------------------------------------ 220 | 221 | 222 | 223 | 224 | 225 | 226 | // Resource map 227 | //ResourceMap.Instance.IsPlanetScanned(body.flightGlobalsIndex); 228 | 229 | 230 | /* 231 | 232 | # Reverse-engineered caps for recovery missions. The values for SubOrbited 233 | # and Orbited are inverted on Kerbin, handled later. 234 | my %recoCap = ( 235 | Flew => 6, 236 | FlewBy => 7.2, 237 | SubOrbited => 12, 238 | Orbited => 9.6, 239 | Surfaced => 18 240 | ); 241 | recovery@KerbinFlew 242 | * recovery@KerbinSubOrbited 243 | * recovery@KerbinOrbited 244 | * recovery@MunFlewBy 245 | * recovery@MunOrbited 246 | * recovery@MinmusOrbited 247 | * recovery@MunSurfaced 248 | * recovery@MinmusSurfaced 249 | * recovery@MinmusFlewBy 250 | * recovery@SunOrbited 251 | */ 252 | 253 | 254 | ------------------------------------------------------------------------------- 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | --- Pass data to an event ------------------------------------------------- 263 | Make a new EventArgs class such as: 264 | 265 | public class ListEventArgs : EventArgs 266 | { 267 | public List Data { get; set; } 268 | public ListEventArgs(List data) 269 | { 270 | Data = data; 271 | } 272 | } 273 | 274 | And make your event as this: 275 | 276 | public event EventHandler NewFileAdded; 277 | 278 | Add a firing method: 279 | 280 | protected void OnNewFileAdded(List data) 281 | { 282 | var localCopy = NewFileAdded; 283 | if (localCopy != null) 284 | { 285 | localCopy(this, new ListEventArgs(data)); 286 | } 287 | } 288 | 289 | And when you want to handle this event: 290 | 291 | myObj.NewFileAdded += new EventHandler(myObj_NewFileAdded); 292 | 293 | The handler method would appear like this: 294 | 295 | public void myObj_NewFileAdded(object sender, ListEventArgs e) 296 | { 297 | // Do what you want with e.Data (It is a List of string) 298 | } 299 | -------------------------------------------------------------------------------- /X-Science/UnlockedInstrumentList.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | 4 | 5 | 6 | // Cache those experiments that are available so we don't keep 7 | // walking through expensive lists of rocket parts. 8 | namespace ScienceChecklist 9 | { 10 | public sealed class UnlockedInstrumentList 11 | { 12 | private Dictionary _unlockedInstruments; 13 | 14 | public UnlockedInstrumentList( ) 15 | { 16 | Clear( ); 17 | } 18 | 19 | 20 | 21 | public void Clear( ) 22 | { 23 | // var _logger = new Logger( "UnlockedInstrumentList" ); 24 | _unlockedInstruments = new Dictionary( ); 25 | float RnDLevel = ScenarioUpgradeableFacilities.GetFacilityLevel( SpaceCenterFacility.ResearchAndDevelopment ); 26 | // _logger.Trace( "RnDLevel " + RnDLevel ); 27 | 28 | 29 | 30 | /* According to the UI you need the AstronautComplex upgraded to do surface samples. Turns out that is rubbish. You just need to upgrade the science lab. 31 | * Upgrading the AstronautComplex does help with EVAs. But there are always cargo bays _grin_ 32 | float AstroLevel = ScenarioUpgradeableFacilities.GetFacilityLevel( SpaceCenterFacility.AstronautComplex );*/ 33 | 34 | 35 | 36 | _unlockedInstruments.Add( "crewReport", true ); 37 | _unlockedInstruments.Add( "evaReport", true ); 38 | if( RnDLevel >= 0.5 ) 39 | _unlockedInstruments.Add( "surfaceSample", true ); 40 | else 41 | _unlockedInstruments.Add( "surfaceSample", false ); 42 | } 43 | 44 | 45 | 46 | public bool IsUnlocked( string Id ) 47 | { 48 | if( PartLoader.Instance == null ) 49 | return false; 50 | if( _unlockedInstruments.ContainsKey( Id ) ) // Do we already have this 51 | return _unlockedInstruments[ Id ]; 52 | 53 | 54 | 55 | // Check RnD level 56 | float RnDLevel = ScenarioUpgradeableFacilities.GetFacilityLevel( SpaceCenterFacility.ResearchAndDevelopment ); 57 | var experiment = ResearchAndDevelopment.GetExperiment( Id ); 58 | if( experiment.requiredExperimentLevel > RnDLevel ) 59 | { 60 | _unlockedInstruments.Add( Id, false ); 61 | return false; 62 | } 63 | 64 | 65 | 66 | bool IsUnlocked = PartLoader.LoadedPartsList.Any 67 | ( 68 | x => ResearchAndDevelopment.PartModelPurchased( x ) && 69 | x.partPrefab.Modules != null && 70 | x.partPrefab.Modules.OfType( ).Any( y => y.experimentID == Id ) 71 | ); 72 | _unlockedInstruments.Add( Id, IsUnlocked ); 73 | 74 | 75 | 76 | return IsUnlocked; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /X-Science/WindowSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | 6 | // Holds settings for one window on one game scene. 7 | namespace ScienceChecklist 8 | { 9 | public sealed class WindowSettings 10 | { 11 | public string _windowName; 12 | public GameScenes _scene; 13 | public Dictionary _settings; 14 | 15 | 16 | 17 | public WindowSettings( ) 18 | { 19 | _windowName = ""; 20 | _settings = new Dictionary( ); 21 | } 22 | public WindowSettings( string WindowName ) : this( ) 23 | { 24 | _windowName = WindowName; 25 | } 26 | public WindowSettings( string WindowName, GameScenes Scene ) : this( ) 27 | { 28 | _windowName = WindowName; 29 | _scene = Scene; 30 | } 31 | 32 | 33 | 34 | public void Set( string Name, string Value ) 35 | { 36 | _settings[ Name ] = Value; 37 | } 38 | public void Set( string Name, int Value ) 39 | { 40 | _settings[ Name ] = Value.ToString( "D" ); 41 | } 42 | public void Set( string Name, bool Value ) 43 | { 44 | _settings[ Name ] = Value.ToString( ); 45 | } 46 | 47 | 48 | 49 | public string Get( string Name, string Default ) 50 | { 51 | if( _settings.ContainsKey( Name ) ) 52 | return _settings[ Name ]; 53 | return Default; 54 | } 55 | 56 | public string Get( string Name ) 57 | { 58 | if( _settings.ContainsKey( Name ) ) 59 | return _settings[ Name ]; 60 | return null; 61 | } 62 | 63 | public int GetInt( string Name, int Default ) 64 | { 65 | if( _settings.ContainsKey( Name ) ) 66 | { 67 | int Temp = 0; 68 | if( int.TryParse( _settings[ Name ], out Temp ) ) 69 | return Temp; 70 | } 71 | return Default; 72 | } 73 | public bool GetBool( string Name, bool Default ) 74 | { 75 | if( _settings.ContainsKey( Name ) ) 76 | { 77 | bool Temp = false; 78 | if( bool.TryParse( _settings[ Name ], out Temp ) ) 79 | return Temp; 80 | } 81 | return Default; 82 | } 83 | 84 | public bool Exists( string Name ) 85 | { 86 | if( _settings.ContainsKey( Name ) ) 87 | return true; 88 | return false; 89 | } 90 | 91 | public void TestPosition( ) 92 | { 93 | if( Exists( "Top" ) && Exists( "Left" ) ) 94 | { 95 | int Top = GetInt( "Top", 0 ); 96 | int Left = GetInt( "Left", 0 ); 97 | 98 | if( Top > ( Screen.height - 50 ) ) 99 | Set( "Top", Screen.height - 50 ); 100 | if( Left > ( Screen.width - 50 ) ) 101 | Set( "Left", Screen.width - 50 ); 102 | } 103 | 104 | if( Exists( "CompactTop" ) && Exists( "CompactLeft" ) ) 105 | { 106 | int CompactTop = GetInt( "CompactTop", 0 ); 107 | int CompactLeft = GetInt( "CompactLeft", 0 ); 108 | 109 | if( CompactTop > ( Screen.height - 50 ) ) 110 | Set( "CompactTop", Screen.height - 50 ); 111 | if( CompactLeft > ( Screen.width - 50 ) ) 112 | Set( "CompactLeft", Screen.width - 50 ); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /X-Science/[x] Science!.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DDFBE6F2-5DC6-4493-AB08-89F9A33A3219} 8 | Library 9 | Properties 10 | ScienceChecklist 11 | [x] Science! 12 | v3.5 13 | 512 14 | 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | none 29 | true 30 | bin\Release\ 31 | 32 | 33 | prompt 34 | 4 35 | false 36 | 37 | 38 | 39 | ..\..\..\..\Games\KSP\KSP_Real\KSP_x64_Data\Managed\Assembly-CSharp.dll 40 | 41 | 42 | 43 | 44 | ..\..\..\..\Games\KSP\KSP_Real\KSP_x64_Data\Managed\UnityEngine.dll 45 | 46 | 47 | ..\..\..\..\Games\KSP\KSP_Real\KSP_x64_Data\Managed\UnityEngine.UI.dll 48 | 49 | 50 | 51 | 52 | 53 | Code 54 | 55 | 56 | Code 57 | 58 | 59 | 60 | Code 61 | 62 | 63 | Code 64 | 65 | 66 | Code 67 | 68 | 69 | 70 | Code 71 | 72 | 73 | Code 74 | 75 | 76 | Code 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Code 86 | 87 | 88 | Code 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Code 99 | 100 | 101 | Code 102 | 103 | 104 | Code 105 | 106 | 107 | Code 108 | 109 | 110 | 111 | Code 112 | 113 | 114 | Code 115 | 116 | 117 | Code 118 | 119 | 120 | Code 121 | 122 | 123 | Code 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | SET PATHOUT=C:\Games\KSP\KSP_Test\GameData\[x] Science! 169 | IF NOT EXIST %25PATHOUT%25 ( 170 | MKDIR "%25PATHOUT%25" 171 | ) 172 | 173 | copy "$(TargetPath)" "%25PATHOUT%25" 174 | robocopy "$(ProjectDir)GameData\[x] Science!" "%25PATHOUT%25" /E 175 | exit 0 176 | 177 | 178 | 179 | 180 | 181 | 188 | -------------------------------------------------------------------------------- /X-Science/[x] Science!.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2013 for Windows Desktop 4 | VisualStudioVersion = 12.0.30723.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "[x] Science!", "[x] Science!.csproj", "{DDFBE6F2-5DC6-4493-AB08-89F9A33A3219}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {DDFBE6F2-5DC6-4493-AB08-89F9A33A3219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {DDFBE6F2-5DC6-4493-AB08-89F9A33A3219}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {DDFBE6F2-5DC6-4493-AB08-89F9A33A3219}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {DDFBE6F2-5DC6-4493-AB08-89F9A33A3219}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /X-Science/icons/OLD_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/OLD_settings.png -------------------------------------------------------------------------------- /X-Science/icons/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/all.png -------------------------------------------------------------------------------- /X-Science/icons/audio-alert-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/audio-alert-off.png -------------------------------------------------------------------------------- /X-Science/icons/audio-alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/audio-alert.png -------------------------------------------------------------------------------- /X-Science/icons/clearSearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/clearSearch.png -------------------------------------------------------------------------------- /X-Science/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/close.png -------------------------------------------------------------------------------- /X-Science/icons/currentSituation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/currentSituation.png -------------------------------------------------------------------------------- /X-Science/icons/currentVessel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/currentVessel.png -------------------------------------------------------------------------------- /X-Science/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/help.png -------------------------------------------------------------------------------- /X-Science/icons/icon-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/icon-small.png -------------------------------------------------------------------------------- /X-Science/icons/icon-status-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/icon-status-red.png -------------------------------------------------------------------------------- /X-Science/icons/icon-status-small-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/icon-status-small-red.png -------------------------------------------------------------------------------- /X-Science/icons/icon-status-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/icon-status-small.png -------------------------------------------------------------------------------- /X-Science/icons/icon-status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/icon-status.png -------------------------------------------------------------------------------- /X-Science/icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/icon.png -------------------------------------------------------------------------------- /X-Science/icons/maximize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/maximize.png -------------------------------------------------------------------------------- /X-Science/icons/minimize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/minimize.png -------------------------------------------------------------------------------- /X-Science/icons/report-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/report-x.png -------------------------------------------------------------------------------- /X-Science/icons/report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/report.png -------------------------------------------------------------------------------- /X-Science/icons/resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/resize.png -------------------------------------------------------------------------------- /X-Science/icons/runExperimentSmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/runExperimentSmall.png -------------------------------------------------------------------------------- /X-Science/icons/runExperimentsAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/runExperimentsAll.png -------------------------------------------------------------------------------- /X-Science/icons/runExperimentsOnce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/runExperimentsOnce.png -------------------------------------------------------------------------------- /X-Science/icons/runIncompleteExperimentsAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/runIncompleteExperimentsAll.png -------------------------------------------------------------------------------- /X-Science/icons/runIncompleteExperimentsOnce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/runIncompleteExperimentsOnce.png -------------------------------------------------------------------------------- /X-Science/icons/scienceComplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/scienceComplete.png -------------------------------------------------------------------------------- /X-Science/icons/scienceCompleteCompact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/scienceCompleteCompact.png -------------------------------------------------------------------------------- /X-Science/icons/scienceProgress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/scienceProgress.png -------------------------------------------------------------------------------- /X-Science/icons/scienceProgressCompact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/scienceProgressCompact.png -------------------------------------------------------------------------------- /X-Science/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/search.png -------------------------------------------------------------------------------- /X-Science/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/settings.png -------------------------------------------------------------------------------- /X-Science/icons/stored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/stored.png -------------------------------------------------------------------------------- /X-Science/icons/time-warp-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/time-warp-x.png -------------------------------------------------------------------------------- /X-Science/icons/time-warp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/time-warp.png -------------------------------------------------------------------------------- /X-Science/icons/unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/X-Science/icons/unlocked.png -------------------------------------------------------------------------------- /X-Science/xScienceEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | 4 | 5 | 6 | 7 | // This class is a junction box for events concerning science related stuff. 8 | // Events tend to happen in flurries. This deals with them and tries to prevent the system slowing down 9 | // because of event spamming. 10 | 11 | // There are 3 events. 12 | // * Filter update is the most basic, caused by changes to the current ship 13 | // * Experiment update is caused by experiments running, science being recovered or by science being lost in explosions. 14 | // * Full Updates are caused by researcing new rocket parts, upgrading KSC or visiting new bodies. 15 | 16 | 17 | 18 | namespace ScienceChecklist 19 | { 20 | public class xScienceEventHandler 21 | { 22 | // Use UpdateExperiments() to set this 23 | private DateTime? _nextExperimentUpdate; 24 | private bool _mustDoFullRefresh; 25 | 26 | 27 | 28 | // For smaller updates just set to true 29 | private DateTime? _nextFilterCheck; 30 | private bool _filterRefreshPending; // Set to true for a quick refresh of the science lists 31 | 32 | 33 | 34 | // Anyone can hook these to get notified 35 | public event EventHandler FilterUpdateEvent; 36 | public event EventHandler ExperimentUpdateEvent; 37 | public event EventHandler FullUpdateEvent; 38 | public event EventHandler SituationChanged; 39 | public event EventHandler MapObjectSelected; 40 | 41 | 42 | 43 | private ScienceChecklistAddon _parent; 44 | private Situation _currentSituation; 45 | //private Logger _logger; 46 | 47 | 48 | 49 | // Constructor 50 | public xScienceEventHandler( ScienceChecklistAddon Parent ) 51 | { 52 | //_logger = new Logger( this ); 53 | //_logger.Trace( "xScienceEventHandler" ); 54 | _parent = Parent; 55 | 56 | _nextExperimentUpdate = DateTime.Now; 57 | _nextFilterCheck = DateTime.Now; 58 | _mustDoFullRefresh = true; 59 | _filterRefreshPending = true; 60 | 61 | 62 | GameEvents.onVesselWasModified.Add( new EventData.OnEvent( this.VesselWasModified ) ); 63 | GameEvents.onVesselChange.Add( new EventData.OnEvent( this.VesselChange ) ); 64 | GameEvents.onEditorShipModified.Add( new EventData.OnEvent( this.EditorShipModified ) ); 65 | 66 | GameEvents.onGameStateSave.Add( new EventData.OnEvent( this.GameStateSave ) ); 67 | GameEvents.OnPartPurchased.Add( new EventData.OnEvent( this.PartPurchased ) ); 68 | GameEvents.OnTechnologyResearched.Add( new EventData>.OnEvent( this.TechnologyResearched ) ); 69 | GameEvents.OnScienceChanged.Add( new EventData.OnEvent( this.ScienceChanged ) ); 70 | GameEvents.OnScienceRecieved.Add( new EventData.OnEvent( this.ScienceRecieved ) ); 71 | GameEvents.onVesselRename.Add( new EventData>.OnEvent( this.VesselRename ) ); 72 | GameEvents.OnKSCFacilityUpgraded.Add( new EventData.OnEvent( this.FacilityUpgrade ) ); 73 | 74 | GameEvents.onDominantBodyChange.Add( new EventData>.OnEvent( this.DominantBodyChange ) ); 75 | GameEvents.onVesselSOIChanged.Add( new EventData>.OnEvent( this.VesselSOIChanged ) ); 76 | 77 | GameEvents.onPlanetariumTargetChanged.Add( new EventData.OnEvent( this.ActiveShipChanged ) ); 78 | 79 | _parent.Config.CheckDebrisChanged += ( s, e ) => CheckDebrisSettingChanged( ); 80 | _parent.Config.FilterDifficultScienceChanged += ( s, e ) => FilterDifficultScienceChanged( ); 81 | } 82 | 83 | 84 | 85 | // Called by the addon (_parent) on Update() - which happens every Unity frame. 86 | public void Update( ) 87 | { 88 | UpdateSituation( ); 89 | UpdateExperiments( ); 90 | RefreshFilter( ); 91 | } 92 | 93 | 94 | 95 | private int _lastDataCount; 96 | private DateTime _nextSituationUpdate = DateTime.Now; 97 | public void UpdateSituation( ) 98 | { 99 | if( _nextSituationUpdate < DateTime.Now ) 100 | { 101 | _nextSituationUpdate = DateTime.Now.AddSeconds( 0.5 ); 102 | RecalculateSituation( ); 103 | } 104 | } 105 | 106 | 107 | 108 | // Recalculates the current situation of the active vessel. 109 | private void RecalculateSituation( ) 110 | { 111 | //_logger.Trace( "RecalculateSituation Start" ); 112 | 113 | var vessel = FlightGlobals.ActiveVessel; 114 | if( vessel == null ) 115 | { 116 | if( _currentSituation != null ) 117 | { 118 | _currentSituation = null; 119 | if( SituationChanged != null ) 120 | SituationChanged( this, null ); 121 | } 122 | return; 123 | } 124 | 125 | var body = vessel.mainBody; 126 | var situation = ScienceUtil.GetExperimentSituation( vessel ); 127 | 128 | var biome = ScienceUtil.GetExperimentBiome( body, vessel.latitude, vessel.longitude ); 129 | var subBiome = string.IsNullOrEmpty( vessel.landedAt ) 130 | ? null 131 | : Vessel.GetLandedAtString( vessel.landedAt ).Replace( " ", "" ); 132 | 133 | var Parts = vessel.FindPartModulesImplementing( ); 134 | var dataCount = 0; 135 | for( var x = 0; x < Parts.Count; x++ ) 136 | dataCount +=Parts[ x].GetData( ).Length; 137 | 138 | if( _lastDataCount != dataCount ) 139 | { 140 | // _logger.Trace( "Collected new science!" ); 141 | _lastDataCount = dataCount; 142 | ScheduleExperimentUpdate( ); 143 | } 144 | 145 | if( 146 | _currentSituation != null && 147 | _currentSituation.Biome == biome && 148 | _currentSituation.ExperimentSituation == situation && 149 | _currentSituation.Body.CelestialBody == body && 150 | _currentSituation.SubBiome == subBiome 151 | ) 152 | { 153 | return; 154 | } 155 | var Body = new Body( body ); 156 | _currentSituation = new Situation( Body, situation, biome, subBiome ); 157 | 158 | if( SituationChanged != null ) 159 | SituationChanged( this, new NewSituationData( Body, situation, biome, subBiome ) ); 160 | //_logger.Trace( "RecalculateSituation Done" ); 161 | } 162 | 163 | 164 | 165 | private void UpdateExperiments( ) 166 | { 167 | if( _nextExperimentUpdate != null && _nextExperimentUpdate.Value < DateTime.Now ) 168 | { 169 | if( _mustDoFullRefresh ) 170 | { 171 | _parent.Science.Reset( ); 172 | if( FullUpdateEvent != null ) 173 | FullUpdateEvent( this, EventArgs.Empty ); 174 | } 175 | else 176 | { 177 | _parent.Science.UpdateAllScienceInstances( ); 178 | if( ExperimentUpdateEvent != null ) 179 | ExperimentUpdateEvent( this, EventArgs.Empty ); 180 | } 181 | _nextExperimentUpdate = null; 182 | _mustDoFullRefresh = false; 183 | _filterRefreshPending = true; // Must do a filter change if we updated some science 184 | } 185 | } 186 | 187 | 188 | 189 | private void RefreshFilter( ) 190 | { 191 | if( _filterRefreshPending && DateTime.Now > _nextFilterCheck ) 192 | { 193 | _nextFilterCheck = DateTime.Now.AddSeconds( 0.5 ); 194 | if( FilterUpdateEvent != null ) 195 | FilterUpdateEvent( this, EventArgs.Empty ); 196 | _filterRefreshPending = false; 197 | } 198 | } 199 | 200 | 201 | 202 | // Schedules a full experiment update in 1 second. 203 | // In addition to the events we hook, this is also called bu the parent when 204 | // the system has been sleeping and wakes up. Eg when the window is made visible. 205 | public void ScheduleExperimentUpdate( bool FullRefresh = false, int AddTime = 1 ) 206 | { 207 | _nextExperimentUpdate = DateTime.Now.AddSeconds( AddTime ); 208 | if( FullRefresh ) 209 | _mustDoFullRefresh = true; 210 | } 211 | 212 | 213 | 214 | // Clicked on something in the map view 215 | private void ActiveShipChanged( MapObject NewTarget ) 216 | { 217 | //_logger.Trace( "Callback: ActiveShipChanged" ); 218 | if( NewTarget == null ) 219 | return; 220 | if( MapObjectSelected != null ) 221 | MapObjectSelected( this, new NewSelectionData( NewTarget ) ); 222 | } 223 | 224 | 225 | // Something happened to the current vessel so we should do a check of the applied filters 226 | private void VesselWasModified( Vessel V ) 227 | { 228 | // _logger.Trace( "Callback: VesselWasModified" ); 229 | _filterRefreshPending = true; 230 | } 231 | 232 | private void VesselChange( Vessel V ) 233 | { 234 | // _logger.Trace( "Callback: VesselChange" ); 235 | _filterRefreshPending = true; 236 | } 237 | 238 | private void EditorShipModified( ShipConstruct S ) 239 | { 240 | // _logger.Trace( "Callback: EditorShipModified" ); 241 | _filterRefreshPending = true; 242 | } 243 | 244 | 245 | 246 | // Something happened to the ammount of science on vessels so we need to walk through the parts containg science 247 | // and count it all again 248 | private void GameStateSave( ConfigNode C ) 249 | { 250 | // _logger.Trace( "Callback: GameStateSave" ); 251 | ScheduleExperimentUpdate( ); 252 | } 253 | 254 | private void ScienceChanged( float V, TransactionReasons R ) 255 | { 256 | // _logger.Trace( "Callback: ScienceChanged" ); 257 | ScheduleExperimentUpdate( ); 258 | } 259 | 260 | private void ScienceRecieved( float V, ScienceSubject S, ProtoVessel P, bool F ) 261 | { 262 | // _logger.Trace( "Callback: ScienceRecieved" ); 263 | ScheduleExperimentUpdate( ); 264 | } 265 | 266 | private void VesselRename( GameEvents.HostedFromToAction Data ) 267 | { 268 | // _logger.Trace( "Callback: VesselRename" ); 269 | ScheduleExperimentUpdate( ); 270 | } 271 | 272 | 273 | 274 | 275 | // Something happened to the underling model of science. 276 | // We visited a new body or bought some ship parts or unlocked a new building. 277 | // We chuck everything away and start again 278 | // 279 | // Calling ScheduleExperimentUpdate with true 280 | private void PartPurchased( AvailablePart P ) 281 | { 282 | // _logger.Trace( "Callback: PartPurchased" ); 283 | ScheduleExperimentUpdate( true ); 284 | } 285 | 286 | private void TechnologyResearched( GameEvents.HostTargetAction Data ) 287 | { 288 | if( Data.target == RDTech.OperationResult.Successful ) 289 | { 290 | // _logger.Trace( "Callback: TechnologyResearched" ); 291 | ScheduleExperimentUpdate( true ); 292 | } 293 | // else 294 | // _logger.Trace( "Callback: Technology Research Failed" ); 295 | } 296 | 297 | private void FacilityUpgrade( Upgradeables.UpgradeableFacility Data, int V ) 298 | { 299 | // _logger.Trace( "Callback: KSP Facility Upgraded" ); 300 | ScheduleExperimentUpdate( true, 5 ); // 5 seconds. Trying to avoid an exception. The colliders list gets updated while we are looking at it. 301 | } 302 | 303 | private void DominantBodyChange( GameEvents.FromToAction Data ) 304 | { 305 | // _logger.Trace( "Callback: DominantBodyChange" ); 306 | ScheduleExperimentUpdate( true ); 307 | } 308 | 309 | private void VesselSOIChanged( GameEvents.HostedFromToAction Data ) 310 | { 311 | // _logger.Trace( "Callback: VesselSOIChanged" ); 312 | ScheduleExperimentUpdate( true ); 313 | } 314 | 315 | 316 | 317 | private void CheckDebrisSettingChanged( ) 318 | { 319 | // _logger.Trace( "Callback: CheckDebrisSettingChanged" ); 320 | ScheduleExperimentUpdate( false ); 321 | } 322 | 323 | 324 | 325 | private void FilterDifficultScienceChanged( ) 326 | { 327 | // _logger.Trace( "Callback: FilterDifficultScienceChanged" ); 328 | ScheduleExperimentUpdate( true ); 329 | } 330 | 331 | 332 | } // End of class 333 | } 334 | -------------------------------------------------------------------------------- /from-bitbucket.org/Bodrick-x-science-4d6001ced421.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thewebbooth/KSP-X-Science/ec68d85d348416bfa0729002499f2089a2c0d32d/from-bitbucket.org/Bodrick-x-science-4d6001ced421.zip -------------------------------------------------------------------------------- /from-bitbucket.org/readme.txt: -------------------------------------------------------------------------------- 1 | Downloaded from https://bitbucket.org/Bodrick/x-science --------------------------------------------------------------------------------