Compare commits

..

6 Commits

6 changed files with 108 additions and 31 deletions

View File

@@ -6,22 +6,22 @@ namespace RMROC451.TweaksAndThings.Extensions
{ {
internal static class AutoEngineer_Extensions internal static class AutoEngineer_Extensions
{ {
private static float CabooseHalvedFloat(this float input, bool hasCaboose) => private static float CabooseHalvedFloat(this float input, Model.Car? hasCaboose) =>
hasCaboose ? input / 2 : input; hasCaboose ? input / 2 : input;
private static float CabooseAutoOilerLimit(this bool hasCaboose) => private static float CabooseAutoOilerLimit(this Model.Car? caboose) =>
hasCaboose ? 0.99f : AutoOiler.OilIfBelow; caboose ? 0.99f : AutoOiler.OilIfBelow;
public static IEnumerator MrocAutoOilerLoop(this AutoOiler oiler, Serilog.ILogger _log, bool cabooseRequired) public static IEnumerator MrocAutoOilerLoop(this AutoOiler oiler, Serilog.ILogger _log, bool cabooseRequired)
{ {
int originIndex = oiler.FindOriginIndex(); int originIndex = oiler.FindOriginIndex();
bool hasCaboose = oiler._cars.CabooseInConsist(); Model.Car? foundCaboose = oiler._cars.CabooseInConsist();
if (originIndex < 0) if (originIndex < 0)
{ {
_log.Error("Couldn't find origin car {car}", oiler._originCar); _log.Error("Couldn't find origin car {car}", oiler._originCar);
oiler._coroutine = null; oiler._coroutine = null;
yield break; yield break;
} else if (CabooseRequirementChecker(string.Format("{0} {1}", oiler.GetType().Name, oiler.name), cabooseRequired, hasCaboose, _log)) } else if (CabooseRequirementChecker(string.Format("{0} {1}", oiler.GetType().Name, oiler.name), cabooseRequired, foundCaboose, _log))
{ {
yield break; yield break;
} }
@@ -31,30 +31,35 @@ namespace RMROC451.TweaksAndThings.Extensions
oiler.name, oiler.name,
oiler._reverse, oiler._reverse,
cabooseRequired, cabooseRequired,
hasCaboose, foundCaboose,
hasCaboose.CabooseAutoOilerLimit() foundCaboose.CabooseAutoOilerLimit()
); );
while (true) while (true)
{ {
yield return new WaitForSeconds(AutoOiler.StartDelay.CabooseHalvedFloat(hasCaboose)); yield return new WaitForSeconds(AutoOiler.StartDelay.CabooseHalvedFloat(foundCaboose));
int carIndex = originIndex; int carIndex = originIndex;
float adjustedTimeToWalk = AutoOiler.TimeToWalkCar.CabooseHalvedFloat(hasCaboose); float adjustedTimeToWalk = AutoOiler.TimeToWalkCar.CabooseHalvedFloat(foundCaboose);
do do
{ {
if (oiler.TryGetCar(carIndex, out var car)) if (oiler.TryGetCar(carIndex, out var car))
{ {
float num = 0f; float num = 0f;
float origOil = car.Oiled; float origOil = car.Oiled;
if (car.NeedsOiling && car.Oiled < hasCaboose.CabooseAutoOilerLimit()) if (car.NeedsOiling && car.Oiled < foundCaboose.CabooseAutoOilerLimit())
{ {
float num2 = 1f - car.Oiled; float num2 = 1f - car.Oiled;
car.OffsetOiled(num2); car.OffsetOiled(num2);
float num3 = num2 * AutoOiler.TimeToFullyOil.CabooseHalvedFloat(hasCaboose); float num3 = num2 * AutoOiler.TimeToFullyOil.CabooseHalvedFloat(foundCaboose);
num += num3; num += num3;
oiler._pendingRunDuration += num3; oiler._pendingRunDuration += num3;
oiler._oiledCount++; oiler._oiledCount++;
_log.Information("AutoOiler {name}: oiled {car} from {orig} => {new}", oiler.name, car, origOil, car.Oiled); _log.Information("AutoOiler {name}: oiled {car} from {orig} => {new}", oiler.name, car, origOil, car.Oiled);
} }
if (car.HasHotbox && car.Oiled == 1f && cabooseRequired && foundCaboose)
{
_log.Information("AutoOiler {name}: {foundCaboose} repaired hotbox {car}", oiler.name, foundCaboose, car);
car.AdjustHotboxValue(0f);
}
num += adjustedTimeToWalk; num += adjustedTimeToWalk;
oiler._pendingRunDuration += adjustedTimeToWalk; oiler._pendingRunDuration += adjustedTimeToWalk;
yield return new WaitForSeconds(num); yield return new WaitForSeconds(num);
@@ -71,14 +76,16 @@ namespace RMROC451.TweaksAndThings.Extensions
{ {
while (true) while (true)
{ {
bool hasCaboose = spotter._cars.CabooseInConsist(); Model.Car? foundCaboose = spotter._cars.CabooseInConsist();
if (!spotter.HasCars) if (!spotter.HasCars)
{ {
yield return new WaitForSeconds(1f); yield return new WaitForSeconds(1f);
continue; continue;
} }
_log.Information("AutoHotboxSpotter {name}: Hotbox Spotter Running, Has Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}", spotter.name, hasCaboose, spotter.HasCars, cabooseRequired); _log.Information("AutoHotboxSpotter {name}: Hotbox Spotter Running, Found Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}",
if (CabooseRequirementChecker(string.Format("{0} {1}", spotter.GetType().Name, spotter.name), cabooseRequired, hasCaboose, _log)) spotter.name, foundCaboose, spotter.HasCars, cabooseRequired);
foundCaboose = spotter._cars.CabooseInConsist();
if (CabooseRequirementChecker(string.Format("{0} {1}", spotter.GetType().Name, spotter.name), cabooseRequired, foundCaboose, _log))
{ {
yield break; yield break;
} }
@@ -86,11 +93,12 @@ namespace RMROC451.TweaksAndThings.Extensions
while (spotter.HasCars) while (spotter.HasCars)
{ {
int num = Random.Range(60, 300); int num = Random.Range(60, 300);
if (hasCaboose) foundCaboose = spotter._cars.CabooseInConsist();
if (foundCaboose)
{ {
var numOrig = num; var numOrig = num;
num = Random.Range(15, 30); num = Random.Range(15, 30);
_log.Information("AutoHotboxSpotter {name}: Next check went from num(60,300) => {numOrig}; to num(15,30) => {hasCaboose}; Requires Caboose {requiresCaboose}", spotter.name, numOrig, num, hasCaboose, cabooseRequired); _log.Information("AutoHotboxSpotter {name}: Next check went from num(60,300) => {numOrig}; to num(15,30) => {hasCaboose}; Requires Caboose {requiresCaboose}", spotter.name, numOrig, num, foundCaboose, cabooseRequired);
} }
yield return new WaitForSeconds(num); yield return new WaitForSeconds(num);
spotter.CheckForHotbox(); spotter.CheckForHotbox();
@@ -98,9 +106,9 @@ namespace RMROC451.TweaksAndThings.Extensions
} }
} }
private static bool CabooseRequirementChecker(string name, bool cabooseRequired, bool hasCaboose, Serilog.ILogger _log) private static bool CabooseRequirementChecker(string name, bool cabooseRequired, Model.Car? foundCaboose, Serilog.ILogger _log)
{ {
bool error = cabooseRequired && !hasCaboose; bool error = cabooseRequired && foundCaboose == null;
if (error) { if (error) {
_log.Debug("{name}: Couldn't find required caboose!", name); _log.Debug("{name}: Couldn't find required caboose!", name);
} }

View File

@@ -1,4 +1,6 @@
using Helpers; using Game.Messages;
using Game.State;
using Helpers;
using Model; using Model;
using Model.Definition.Data; using Model.Definition.Data;
using Model.OpsNew; using Model.OpsNew;
@@ -60,7 +62,9 @@ public static class Car_Extensions
public static bool IsCaboose(this Car car) => car.Archetype == Model.Definition.CarArchetype.Caboose; public static bool IsCaboose(this Car car) => car.Archetype == Model.Definition.CarArchetype.Caboose;
public static bool CabooseInConsist(this IEnumerable<Car> input) => input.FirstOrDefault(c => c.IsCaboose()); public static bool IsCabooseAndStoppedForLoadRefresh(this Car car) => car.IsCaboose() && car.IsStopped(30f);
public static Car? CabooseInConsist(this IEnumerable<Car> input) => input.FirstOrDefault(c => c.IsCaboose());
public static Car? CabooseWithSufficientCrewHours(this Car car, float timeNeeded, HashSet<string> carIdsCheckedAlready, bool decrement = false) public static Car? CabooseWithSufficientCrewHours(this Car car, float timeNeeded, HashSet<string> carIdsCheckedAlready, bool decrement = false)
{ {
@@ -122,4 +126,12 @@ public static class Car_Extensions
}).ToList(); }).ToList();
return source; return source;
} }
public static void AdjustHotboxValue(this Car car, float hotboxValue) =>
StateManager.ApplyLocal(
new PropertyChange(
car.id, PropertyChange.KeyForControl(PropertyChange.Control.Hotbox),
new FloatPropertyValue(hotboxValue)
)
);
} }

View File

@@ -43,7 +43,7 @@ internal class CarInspector_PopulateCarPanel_Patch
if (!tweaksAndThings.IsEnabled) return true; if (!tweaksAndThings.IsEnabled) return true;
bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment(); bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment();
var consist = __instance._car._set.Cars; var consist = __instance._car.EnumerateCoupled();
builder = AddCarConsistRebuildObservers(builder, consist); builder = AddCarConsistRebuildObservers(builder, consist);
builder.HStack(delegate (UIPanelBuilder hstack) builder.HStack(delegate (UIPanelBuilder hstack)
@@ -122,8 +122,8 @@ internal class CarInspector_PopulateCarPanel_Patch
{ {
try try
{ {
builder.Rebuild(); builder.RebuildOnInterval(.01f);
if (car.TagCallout != null) tagController.UpdateTags(CameraSelector.shared._currentCamera.GroundPosition, true); //tagController.UpdateTag(car, car.TagCallout, OpsController.Shared); if (car.TagCallout != null) tagController.UpdateTags(CameraSelector.shared._currentCamera.GroundPosition, true);
if (ContextMenu.IsShown && ContextMenu.Shared.centerLabel.text == car.DisplayName) CarPickable.HandleShowContextMenu(car); if (ContextMenu.IsShown && ContextMenu.Shared.centerLabel.text == car.DisplayName) CarPickable.HandleShowContextMenu(car);
} }
catch (Exception ex) catch (Exception ex)
@@ -151,7 +151,7 @@ internal class CarInspector_PopulateCarPanel_Patch
public static void MrocConsistHelper(Model.Car car, MrocHelperType mrocHelperType, bool buttonsHaveCost) public static void MrocConsistHelper(Model.Car car, MrocHelperType mrocHelperType, bool buttonsHaveCost)
{ {
TrainController tc = UnityEngine.Object.FindObjectOfType<TrainController>(); TrainController tc = UnityEngine.Object.FindObjectOfType<TrainController>();
IEnumerable<Model.Car> consist = car._set.Cars; IEnumerable<Model.Car> consist = car.EnumerateCoupled();
_log.ForContext("car", car).Verbose($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}"); _log.ForContext("car", car).Verbose($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
CalculateCostIfEnabled(car, mrocHelperType, buttonsHaveCost, consist); CalculateCostIfEnabled(car, mrocHelperType, buttonsHaveCost, consist);
@@ -232,7 +232,7 @@ internal class CarInspector_PopulateCarPanel_Patch
carIdsCheckedAlready.Add(car.id); carIdsCheckedAlready.Add(car.id);
//check consist, for cabeese //check consist, for cabeese
IEnumerable<Car> consist = car._set.Cars; IEnumerable<Car> consist = car.EnumerateCoupled();
output = consist.FirstOrDefault(c => c.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement)); output = consist.FirstOrDefault(c => c.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready, decrement));
if (output != null) return output; //short out if we are good if (output != null) return output; //short out if we are good
carIdsCheckedAlready.UnionWith(consist.Select(c => c.id)); carIdsCheckedAlready.UnionWith(consist.Select(c => c.id));

View File

@@ -0,0 +1,52 @@
using HarmonyLib;
using Railloader;
using RollingStock;
using UnityEngine;
namespace RMROC451.TweaksAndThings.Patches;
[HarmonyPatch(typeof(CarPickable))]
[HarmonyPatch(nameof(CarPickable.Activate), typeof(PickableActivateEvent))]
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
internal class CarPickable_Activate_Patch
{
static float clicked = 0;
static float clicktime = 0;
static float clickdelay = 0.5f;
private static bool Prefix(CarPickable __instance, PickableActivateEvent evt)
{
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
if (!tweaksAndThings.IsEnabled) return true;
if (OnPointerDown(evt))
{
CameraSelector.shared.FollowCar(__instance.car);
return false;
}
return true;
}
public static bool OnPointerDown(PickableActivateEvent evt)
{
bool output = false;
if (evt.Activation == PickableActivation.Primary)
{
clicked++;
if (clicked == 1) clicktime = Time.time;
if (clicked > 1 && Time.time - clicktime < clickdelay)
{
clicked = 0;
clicktime = 0;
output = true;
}
else if (clicked > 2 || Time.time - clicktime > 1) clicked = 0;
}
return output;
}
}

View File

@@ -22,12 +22,12 @@ internal class CarPickable_HandleShowContextMenu_Patch
bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment(); bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment();
ContextMenu shared = ContextMenu.Shared; ContextMenu shared = ContextMenu.Shared;
shared.AddButton(ContextMenuQuadrant.Unused2, $"{(car._set.Cars.Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate shared.AddButton(ContextMenuQuadrant.Unused2, $"{(car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
{ {
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost); CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
}); });
if (car._set.Cars.Any(c => c.EndAirSystemIssue())) if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
{ {
shared.AddButton(ContextMenuQuadrant.Unused2, $"Air Up Consist", SpriteName.Select, delegate shared.AddButton(ContextMenuQuadrant.Unused2, $"Air Up Consist", SpriteName.Select, delegate
{ {
@@ -35,7 +35,7 @@ internal class CarPickable_HandleShowContextMenu_Patch
}); });
} }
if (car._set.Cars.Any(c => c.SupportsBleed())) if (car.EnumerateCoupled().Any(c => c.SupportsBleed()))
{ {
shared.AddButton(ContextMenuQuadrant.Unused2, $"Bleed Consist", SpriteName.Bleed, delegate shared.AddButton(ContextMenuQuadrant.Unused2, $"Bleed Consist", SpriteName.Bleed, delegate
{ {

View File

@@ -90,10 +90,13 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
}); });
} }
private static string cabooseUse => "Caboose Use";
private static string autoAiRequirment => "AutoAI\nRequirement";
private void CabooseMods(UIPanelBuilder builder) private void CabooseMods(UIPanelBuilder builder)
{ {
builder.AddField( builder.AddField(
"Caboose Use", cabooseUse,
builder.AddToggle( builder.AddToggle(
() => settings?.EndGearHelpersRequirePayment ?? false, () => settings?.EndGearHelpersRequirePayment ?? false,
delegate (bool enabled) delegate (bool enabled)
@@ -109,12 +112,14 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
Caboose starts reloading `Crew Hours` at any Team or Repair track (no waybill), after being stationary for 30 seconds. Caboose starts reloading `Crew Hours` at any Team or Repair track (no waybill), after being stationary for 30 seconds.
AutoOiler Update: Increases limit that crew will oiling a car from 75% -> 99%, also halves the time it takes (simulating crew from lead end and caboose handling half the train) AutoOiler Update: Increases limit that crew will oiling a car from 75% -> 99%, also halves the time it takes (simulating crew from lead end and caboose handling half the train).
AutoOiler Update: if `{cabooseUse}` & `{autoAiRequirment.Replace("\n", " ")}` checked, then when a caboose is present, the AutoOiler will repair hotboxes afer oiling them to 100%.
AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 - 30 seconds (Safety Is Everyone's Job)"); AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 - 30 seconds (Safety Is Everyone's Job)");
builder.AddField( builder.AddField(
$"AutoAI\nRequirement", autoAiRequirment,
builder.AddToggle( builder.AddToggle(
() => settings?.RequireConsistCabooseForOilerAndHotboxSpotter ?? false, () => settings?.RequireConsistCabooseForOilerAndHotboxSpotter ?? false,
delegate (bool enabled) delegate (bool enabled)