Skip to content

Commit 7107e94

Browse files
authored
Merge pull request #165 from GarwelGarwel/dev
v1.6.3
2 parents 8cca11c + 664cc17 commit 7107e94

19 files changed

Lines changed: 545 additions & 447 deletions

Core.cs

Lines changed: 116 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using KSP.UI.Screens;
1+
using KSP.Localization;
2+
using KSP.UI.Screens;
23
using System;
34
using System.Collections.Generic;
45
using System.Linq;
@@ -38,19 +39,10 @@ public static class Core
3839
/// </summary>
3940
public static Dictionary<string, HealthCondition> HealthConditions;
4041

41-
/// <summary>
42-
/// Mod-wide random number generator
43-
/// </summary>
44-
internal static System.Random Rand = new System.Random();
45-
4642
static readonly string[] prefixes = { "", "K", "M", "G", "T" };
4743

48-
static float radStormTypesTotalWeight = 0;
49-
5044
static Dictionary<string, Vessel> kerbalVesselsCache = new Dictionary<string, Vessel>();
5145

52-
static List<float> trainingCaps;
53-
5446
/// <summary>
5547
/// List of all tracked kerbals
5648
/// </summary>
@@ -63,59 +55,38 @@ public static class Core
6355
{
6456
new StressFactor(),
6557
new ConfinementFactor(),
66-
new LonelinessFactor(),
6758
new MicrogravityFactor(),
68-
new EVAFactor(),
69-
new ConditionsFactor(),
59+
new LonelinessFactor(),
7060
new IsolationFactor(),
61+
new EVAFactor(),
7162
new HomeFactor(),
72-
new KSCFactor()
63+
new KSCFactor(),
64+
new ConditionsFactor()
7365
};
7466

7567
/// <summary>
7668
/// Keeps data about all resources that provide Shielding. Key is resource id, value is amount of shielding provided by 1 unit
7769
/// </summary>
7870
public static Dictionary<int, double> ShieldingResources { get; set; } = new Dictionary<int, double>();
7971

72+
/// <summary>
73+
/// List of all possible quirks
74+
/// </summary>
8075
public static List<Quirk> Quirks { get; set; } = new List<Quirk>();
8176

8277
public static Dictionary<CelestialBody, PlanetHealthConfig> PlanetConfigs { get; set; }
8378

84-
public static List<RadStormType> RadStormTypes { get; set; }
85-
86-
public static double SolarCycleDuration { get; set; }
87-
88-
public static double SolarCycleStartingPhase { get; set; }
89-
90-
public static double RadStormMinMBTE { get; set; }
91-
92-
public static double RadStormMaxMBTE { get; set; }
93-
94-
public static double SolarCyclePhase => (SolarCycleStartingPhase + Planetarium.GetUniversalTime() / SolarCycleDuration) % 1;
95-
96-
public static double RadStormMTBE => RadStormMinMBTE + (RadStormMaxMBTE - RadStormMinMBTE) * (Math.Sin(2 * Math.PI * (SolarCyclePhase + 0.75)) + 1) / 2;
97-
9879
/// <summary>
9980
/// True if the current scene is Editor (VAB or SPH)
10081
/// </summary>
10182
public static bool IsInEditor => HighLogic.LoadedSceneIsEditor;
10283

103-
/// <summary>
104-
/// Max amount of stress reduced by training depending on Astronaut Complex's level
105-
/// </summary>
106-
public static double TrainingCap => trainingCaps[(int)Math.Round(ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) * 2)];
107-
108-
/// <summary>
109-
/// Current <see cref="LogLevel"/>: either Debug or Important
110-
/// </summary>
111-
public static LogLevel Level => KerbalHealthGeneralSettings.Instance.DebugMode ? LogLevel.Debug : LogLevel.Important;
112-
11384
/// <summary>
11485
/// Returns factor with a given id
11586
/// </summary>
11687
/// <param name="id">Factor id</param>
11788
/// <returns></returns>
118-
public static HealthFactor GetHealthFactor(string id) => Factors.FirstOrDefault(f => f.Name == id);
89+
public static HealthFactor GetHealthFactor(string id) => Factors.Find(f => f.Name == id);
11990

12091
public static HealthCondition GetHealthCondition(string s) => HealthConditions.TryGetValue(s, out HealthCondition value) ? value : null;
12192

@@ -135,6 +106,26 @@ public static PlanetHealthConfig GetPlanetConfig(string name)
135106
return cb != null && PlanetConfigs.TryGetValue(cb, out PlanetHealthConfig res) ? res : null;
136107
}
137108

109+
public static float GetInternalFacilityLevel(int displayFacilityLevel) => (float)(displayFacilityLevel - 1) / 2;
110+
111+
#region RAD STORMS
112+
113+
static float radStormTypesTotalWeight = 0;
114+
115+
public static List<RadStormType> RadStormTypes { get; set; }
116+
117+
public static float SolarCycleDuration { get; set; }
118+
119+
public static float SolarCycleStartingPhase { get; set; }
120+
121+
public static float RadStormMinMBTE { get; set; }
122+
123+
public static float RadStormMaxMBTE { get; set; }
124+
125+
public static float SolarCyclePhase => (int)(SolarCycleStartingPhase + Planetarium.GetUniversalTime() / SolarCycleDuration) % 1;
126+
127+
public static float RadStormMTBE => RadStormMinMBTE + (RadStormMaxMBTE - RadStormMinMBTE) * (float)(Math.Sin(2 * Math.PI * (SolarCyclePhase + 0.75)) + 1) / 2;
128+
138129
public static RadStormType GetRandomRadStormType()
139130
{
140131
double d = Rand.NextDouble() * radStormTypesTotalWeight;
@@ -147,6 +138,10 @@ public static RadStormType GetRandomRadStormType()
147138
return null;
148139
}
149140

141+
#endregion
142+
143+
#region CREW UTILITIES
144+
150145
public static IList<ProtoCrewMember> GetCrew(ProtoCrewMember pcm, bool entireVessel)
151146
{
152147
Vessel vessel = pcm.GetVessel();
@@ -181,17 +176,18 @@ public static int GetColleaguesCount(ProtoCrewMember pcm) =>
181176
public static Part GetCrewPart(this ProtoCrewMember pcm) =>
182177
IsInEditor ? KSPUtil.GetPartByCraftID(EditorLogic.SortedShipList, ShipConstruction.ShipManifest.GetPartForCrew(pcm).PartID) : pcm?.seat?.part;
183178

184-
public static string GetPartTitle(string partName) => PartLoader.getPartInfoByName(partName)?.title ?? partName;
179+
#endregion
180+
181+
public static string GetPartTitle(string partName) =>
182+
partName.StartsWith("kerbalEVA") ? Localizer.Format("#KH_SpacesuitPart", partName) : (PartLoader.getPartInfoByName(partName)?.title ?? partName);
185183

186184
/// <summary>
187185
/// Returns true if the kerbal is in a loaded vessel
188186
/// </summary>
189-
public static bool IsUnpacked(this ProtoCrewMember pcm) //=> pcm.GetVessel()?.loaded ?? false;
187+
public static bool IsUnpacked(this ProtoCrewMember pcm)
190188
{
191189
Vessel vessel = pcm.GetVessel();
192-
if (vessel == null)
193-
return false;
194-
return vessel.loaded && !vessel.packed;
190+
return vessel != null && vessel.loaded && !vessel.packed;
195191
}
196192

197193
/// <summary>
@@ -234,37 +230,66 @@ public static Vessel GetVessel(this ProtoCrewMember pcm)
234230
return vessel;
235231
}
236232

233+
public static bool IsPlanet(this CelestialBody body) => body?.orbit?.referenceBody == Sun.Instance.sun;
234+
235+
public static CelestialBody GetPlanet(this CelestialBody body) => body == null || body.IsPlanet() ? body : body.orbit?.referenceBody?.GetPlanet();
236+
237237
public static double GetDistanceToSun(this Vessel v) =>
238238
v.mainBody == Sun.Instance.sun
239239
? v.altitude + Sun.Instance.sun.Radius
240240
: (v.distanceToSun > 0 ? v.distanceToSun : v.mainBody.GetPlanet().orbit.altitude + Sun.Instance.sun.Radius);
241241

242+
public static float GetScienceMultiplier(this Vessel vessel, bool ignoreLandedOnHomebody = true)
243+
{
244+
CelestialBody body = vessel?.mainBody;
245+
if (body == null)
246+
{
247+
Log($"Could not get science multiplier for {vessel?.vesselName}.", LogLevel.Error);
248+
return 0;
249+
}
250+
if (ignoreLandedOnHomebody && body.isHomeWorld && vessel.LandedOrSplashed)
251+
return 0;
252+
if (vessel.Landed)
253+
return body.scienceValues.LandedDataValue;
254+
if (vessel.Splashed)
255+
return body.scienceValues.SplashedDataValue;
256+
if ((vessel.situation & Vessel.Situations.FLYING) != 0)
257+
return vessel.altitude < body.scienceValues.flyingAltitudeThreshold ? body.scienceValues.FlyingLowDataValue : body.scienceValues.FlyingHighDataValue;
258+
return vessel.altitude < body.scienceValues.InSpaceHighDataValue ? body.scienceValues.InSpaceLowDataValue : body.scienceValues.InSpaceHighDataValue;
259+
}
260+
261+
#region TRAINING
262+
263+
static List<float> trainingCaps;
264+
242265
/// <summary>
243-
/// Returns a list of part modules that are used in stress calculations
266+
/// Max amount of stress reduced by training depending on Astronaut Complex's level
244267
/// </summary>
245-
public static List<ModuleKerbalHealth> GetTrainableParts(IList<Part> allParts) =>
246-
allParts.SelectMany(part => part.FindModulesImplementing<ModuleKerbalHealth>()).Where(mkh => mkh.complexity != 0).ToList();
268+
public static float KSCTrainingCap => trainingCaps[(int)Math.Round(ScenarioUpgradeableFacilities.GetFacilityLevel(SpaceCenterFacility.AstronautComplex) * 2)];
269+
270+
public const float InFlightTrainingCap = 1;
247271

248272
/// <summary>
249-
/// Returns a list of *distinct* part modules that are used in training
273+
/// Returns a list of unique part modules that are used in training & stress calculations
250274
/// </summary>
251-
public static List<ModuleKerbalHealth> GetTrainablePartTypes(IList<Part> allParts)
275+
public static List<ModuleKerbalHealth> GetTrainableModules(this IEnumerable<Part> allParts)
252276
{
253277
List<ModuleKerbalHealth> res = new List<ModuleKerbalHealth>();
254-
foreach (ModuleKerbalHealth mkh in GetTrainableParts(allParts))
255-
if (!res.Any(mkh2 => mkh.PartName == mkh2.PartName))
256-
res.Add(mkh);
278+
foreach (Part part in allParts)
279+
foreach (ModuleKerbalHealth mkh in part.FindModulesImplementing<ModuleKerbalHealth>().Where(mkh => mkh.complexity != 0))
280+
{
281+
if (!res.Any(mkh2 => mkh2.PartName == mkh.PartName))
282+
res.Add(mkh);
283+
break;
284+
}
257285
return res;
258286
}
259287

260-
public static bool HasTrainableParts(IEnumerable<Part> allParts) => allParts.Any(part => part.FindModulesImplementing<ModuleKerbalHealth>().Any(mkh => mkh.complexity != 0));
288+
public static bool AnyTrainableParts(IEnumerable<Part> allParts) => allParts.Any(part => part.FindModulesImplementing<ModuleKerbalHealth>().Any(mkh => mkh.complexity != 0));
261289

262-
public static float GetInternalFacilityLevel(int displayFacilityLevel) => (float)(displayFacilityLevel - 1) / 2;
290+
#endregion
263291

264-
public static bool IsPlanet(this CelestialBody body) => body?.orbit?.referenceBody == Sun.Instance.sun;
265-
266-
public static CelestialBody GetPlanet(this CelestialBody body) =>
267-
body == null || body.IsPlanet() ? body : body.orbit?.referenceBody?.GetPlanet();
292+
#region CONFIG NODE UTILITIES
268293

269294
public static string GetString(this ConfigNode n, string key, string defaultValue = null)
270295
{
@@ -288,6 +313,15 @@ public static uint GetUInt(this ConfigNode n, string key, uint defaultValue = 0)
288313
public static bool GetBool(this ConfigNode n, string key, bool defaultValue = false) =>
289314
bool.TryParse(n.GetValue(key), out bool res) ? res : defaultValue;
290315

316+
#endregion
317+
318+
#region MATH & RNG UTILITIES
319+
320+
/// <summary>
321+
/// Mod-wide random number generator
322+
/// </summary>
323+
internal static System.Random Rand = new System.Random();
324+
291325
/// <summary>
292326
/// Returns x*x
293327
/// </summary>
@@ -301,22 +335,24 @@ public static double GetGaussian(double stdDev = 1, double mean = 0) =>
301335

302336
public static double EventChance(double mtbe, double interval) => 1 - Math.Exp(-interval / mtbe);
303337

304-
public static bool EventHappens(double mtbe, double interval) => mtbe >= 0 && Rand.NextDouble() < EventChance(mtbe, interval);
338+
public static bool EventHappens(double mtbe, double interval) => (mtbe > 0 && Rand.NextDouble() < EventChance(mtbe, interval)) || mtbe == 0;
339+
340+
#endregion
341+
342+
#region NUMBERS AND STRINGS
305343

306344
/// <summary>
307345
/// Returns a string of a value with a mandatory sign (+ or -, unless v = 0)
308346
/// </summary>
309347
/// <param name="value">Value to present as a string</param>
310348
/// <param name="format">String format according to Double.ToString</param>
311-
/// <returns></returns>
312349
public static string SignValue(double value, string format) => (value > 0 ? "+" : "") + value.ToString(format);
313350

314351
/// <summary>
315352
/// Converts a number into a string with a multiplicative character (K, M, G or T), if applicable
316353
/// </summary>
317354
/// <param name="value">The value to convert</param>
318355
/// <param name="digits">Number of digits to allow before the prefix (must be 3 or more)</param>
319-
/// <returns></returns>
320356
public static string PrefixFormat(double value, int digits = 3, bool mandatorySign = false)
321357
{
322358
double v = Math.Abs(value);
@@ -386,6 +422,8 @@ public static string ParseUT(double time, bool showSeconds = true, int daysTimeL
386422
return res.Trim();
387423
}
388424

425+
#endregion
426+
389427
public static void ShowMessage(string msg, bool unwarpTime)
390428
{
391429
MessageSystem.Instance.AddMessage(new MessageSystem.Message(
@@ -431,20 +469,12 @@ public static void LoadConfig()
431469

432470
int i = 0;
433471
foreach (ConfigNode n in config.GetNodes("PLANET_HEALTH_CONFIG"))
434-
{
435-
PlanetHealthConfig bc = GetPlanetConfig(n.GetString("name"));
436-
if (bc != null)
437-
{
438-
bc.Load(n);
439-
i++;
440-
}
441-
}
442-
Log($"{i} planet configs out of {PlanetConfigs.Count} bodies loaded.", LogLevel.Important);
472+
GetPlanetConfig(n.GetString("name"))?.Load(n);
443473

444-
SolarCycleDuration = config.GetDouble("solarCycleDuration", 11) * KSPUtil.dateTimeFormatter.Year;
445-
SolarCycleStartingPhase = config.GetDouble("solarCycleStartingPhase");
446-
RadStormMinMBTE = config.GetDouble("radStormMinMBTE", 426);
447-
RadStormMaxMBTE = config.GetDouble("radStormMaxMBTE", 6390);
474+
SolarCycleDuration = config.GetFloat("solarCycleDuration", 11) * KSPUtil.dateTimeFormatter.Year;
475+
SolarCycleStartingPhase = config.GetFloat("solarCycleStartingPhase");
476+
RadStormMinMBTE = config.GetFloat("radStormMinMBTE", 426);
477+
RadStormMaxMBTE = config.GetFloat("radStormMaxMBTE", 6390);
448478

449479
RadStormTypes = new List<RadStormType>();
450480
i = 0;
@@ -457,9 +487,9 @@ public static void LoadConfig()
457487

458488
trainingCaps = new List<float>(3)
459489
{
460-
0.40f,
461-
0.60f,
462-
0.75f
490+
0.30f,
491+
0.50f,
492+
0.60f
463493
};
464494
foreach (ConfigNode n in config.GetNodes("TRAINING_CAPS"))
465495
{
@@ -472,6 +502,13 @@ public static void LoadConfig()
472502
ConfigLoaded = true;
473503
}
474504

505+
#region LOG
506+
507+
/// <summary>
508+
/// Current <see cref="LogLevel"/>: either Debug or Important
509+
/// </summary>
510+
public static LogLevel Level => KerbalHealthGeneralSettings.Instance.DebugMode ? LogLevel.Debug : LogLevel.Important;
511+
475512
/// <summary>
476513
/// Returns true if current logging allows logging of messages at messageLevel
477514
/// </summary>
@@ -493,5 +530,7 @@ internal static void Log(string message, LogLevel messageLevel = LogLevel.Debug)
493530
Debug.Log($"[KerbalHealth] {message}");
494531
}
495532
}
533+
534+
#endregion
496535
}
497536
}

Factors/EVAFactor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace KerbalHealth
44
{
55
class EVAFactor : HealthFactor
66
{
7-
public const float BaseChangePerDay_Default = -10;
7+
public const float BaseChangePerDay_Default = -8;
88

99
public override string Name => "EVA";
1010

GameData/KerbalHealth/KerbalHealth.cfg

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@
55
TRAINING_CAPS
66
{
77
level = 1
8-
cap = 0.40
8+
cap = 0.30
99
}
1010

1111
TRAINING_CAPS
1212
{
1313
level = 2
14-
cap = 0.60
14+
cap = 0.50
1515
}
1616

1717
TRAINING_CAPS
1818
{
1919
level = 3
20-
cap = 0.75
20+
cap = 0.60
2121
}
2222

2323
//// HEALTH CONDITIONS ////
@@ -288,12 +288,12 @@
288288
description = #KH_PanicAttack_desc//The kerbal is panicking and refuses to cooperate. Kerbopsychologists say it should pass within a day or two.
289289
incompatibleCondition = Exhausted
290290
kerbalStatus = Assigned
291-
mtbe = 200
291+
mtbe = 50
292292
incapacitated = true
293293
MTBE_MODIFIER
294294
{
295-
modification = Multiply
296-
value = 5
295+
modification = Add
296+
value = 700
297297
useAttribute = Courage
298298
}
299299
OUTCOME
512 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)