Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions Source/RP0/Crew/BoostTrainingRate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Contracts;
using ContractConfigurator;

namespace ContractConfigurator.RP0
{
/// <summary>
/// On contract completion, permanently multiplies the astronaut training rate (both proficiency and
/// mission training) by <c>multiplier</c>. The bonus is stored on CrewHandler and persists with the save;
/// it stacks multiplicatively if more than one such contract is completed.
/// </summary>
public class BoostTrainingRate : ContractBehaviour
{
protected double multiplier = 1d;

public BoostTrainingRate() { }

public BoostTrainingRate(double multiplier)
{
this.multiplier = multiplier;
}

protected override void OnLoad(ConfigNode node)
{
base.OnLoad(node);
node.TryGetValue("multiplier", ref multiplier);
}

protected override void OnSave(ConfigNode node)
{
base.OnSave(node);
node.AddValue("multiplier", multiplier);
}

protected override void OnCompleted()
{
base.OnCompleted();
global::RP0.Crew.CrewHandler.Instance?.ApplyPermanentTrainingRateBonus(multiplier);
}
}
}
24 changes: 24 additions & 0 deletions Source/RP0/Crew/BoostTrainingRateFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Contracts;
using ContractConfigurator;

namespace ContractConfigurator.RP0
{
public class BoostTrainingRateFactory : BehaviourFactory
{
protected double multiplier;

public override bool Load(ConfigNode node)
{
bool valid = base.Load(node);

valid &= ConfigNodeUtil.ParseValue<double>(node, "multiplier", x => multiplier = x, this, 1.5, x => Validation.GT(x, 0.0));

return valid;
}

public override ContractBehaviour Generate(ConfiguredContract contract)
{
return new BoostTrainingRate(multiplier);
}
}
}
39 changes: 39 additions & 0 deletions Source/RP0/Crew/CrewHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@
public bool IsMissionTrainingEnabled;
public double ProfTrainRate;
public double MissionTrainRate;
// Permanent multiplier on training build rate, earned via contracts (see the BoostTrainingRate
// behaviour). 1.0 = no bonus. Persisted with the save, and contributed to the RateTraining currency
// query (OnCurrencyQuery) so it flows through CalculateBuildRate's existing rate line and composes
// with leader/strategy training modifiers.
public double TrainingRateBonus = 1d;

Check warning on line 66 in Source/RP0/Crew/CrewHandler.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Make this field 'private' and encapsulate it in a 'public' property.

See more on https://sonarcloud.io/project/issues?id=KSP-RO_RP-1&issues=AZ9O7XrBKu499Cc-v36D&open=AZ9O7XrBKu499Cc-v36D&pullRequest=2875

private EventData<RDTech> onKctTechQueuedEvent;
private HashSet<string> _toRemove = new HashSet<string>();
Expand Down Expand Up @@ -143,6 +148,7 @@
GameEvents.OnPartPurchased.Add(OnPartPurchased);
GameEvents.OnGameSettingsApplied.Add(LoadSettings);
GameEvents.onGameStateLoad.Add(LoadSettings);
GameEvents.Modifiers.OnCurrencyModifierQuery.Add(OnCurrencyQuery);

TrainingDatabase.EnsureInitialized();
}
Expand All @@ -164,12 +170,44 @@

LoadedSaveVersion = VERSION;

TrainingRateBonus = 1d;
node.TryGetValue(nameof(TrainingRateBonus), ref TrainingRateBonus);

KACWrapper.InitKACWrapper();
}

public override void OnSave(ConfigNode node)
{
base.OnSave(node);

node.AddValue(nameof(TrainingRateBonus), TrainingRateBonus);
}

/// <summary>
/// Permanently multiplies the astronaut training rate by <paramref name="multiplier"/> (stacks
/// multiplicatively). Applied to both proficiency and mission training via CalculateBuildRate.
/// </summary>
public void ApplyPermanentTrainingRateBonus(double multiplier)
{
if (multiplier <= 0d) return;
TrainingRateBonus *= multiplier;
RP0Debug.Log($"Applied permanent training rate bonus x{multiplier}; total is now x{TrainingRateBonus}");

foreach (var course in TrainingCourses)
course.RecalculateBuildRate();
}

// Contribute the earned training-rate bonus to any RateTraining currency query, the same way leader
// and strategy effects do (see Leaders/Effects/CurrencyModifier). CalculateBuildRate already folds in
// CurrencyUtils.Rate(RateTraining), so no direct multiply is needed there.
private void OnCurrencyQuery(CurrencyModifierQuery qry)
{
if (TrainingRateBonus == 1d) return;

Check warning on line 205 in Source/RP0/Crew/CrewHandler.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not check floating point equality with exact values, use a range instead.

See more on https://sonarcloud.io/project/issues?id=KSP-RO_RP-1&issues=AZ9O7XrBKu499Cc-v36E&open=AZ9O7XrBKu499Cc-v36E&pullRequest=2875
if (qry is CurrencyModifierQueryRP0 qryRP0 &&
(qryRP0.reasonRP0 & TransactionReasonsRP0.RateTraining) != 0)
{
qryRP0.Multiply(CurrencyRP0.Rate, TrainingRateBonus);
}
}

public void Process(double UTDiff)
Expand Down Expand Up @@ -210,6 +248,7 @@
GameEvents.OnPartPurchased.Remove(OnPartPurchased);
GameEvents.OnGameSettingsApplied.Remove(LoadSettings);
GameEvents.onGameStateLoad.Remove(LoadSettings);
GameEvents.Modifiers.OnCurrencyModifierQuery.Remove(OnCurrencyQuery);

if (onKctTechQueuedEvent != null) onKctTechQueuedEvent.Remove(AddCoursesForQueuedTechNode);
}
Expand Down
2 changes: 2 additions & 0 deletions Source/RP0/RP0.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@
<Compile Include="Settings\SpaceCenterSettings.cs" />
<Compile Include="Maintenance\MaintenanceHandler.cs" />
<Compile Include="Crew\CrewHandler.cs" />
<Compile Include="Crew\BoostTrainingRate.cs" />
<Compile Include="Crew\BoostTrainingRateFactory.cs" />
<Compile Include="Settings\GameParameters.cs" />
<Compile Include="PartModules\ModuleNonRecharge.cs" />
<Compile Include="PartModules\ModuleNonReentryRated.cs" />
Expand Down
Loading