mirror of
https://github.com/rmroc451/TweaksAndThings.git
synced 2025-12-16 01:09:38 -06:00
updates for TrainBrakeDisplay (allow color coding of brake display on engine control panel when in tag view mode, and be able to click them with my click modifier options to interact), AE waypoint engineer adding distinct "click to set" destinations in the gear menu, and allowing engine only consists to bypass safety first.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<MajorVersion>2</MajorVersion>
|
||||
<MinorVersion>0</MinorVersion>
|
||||
<PatchVersion>1</PatchVersion>
|
||||
<MinorVersion>1</MinorVersion>
|
||||
<PatchVersion>0</PatchVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -46,9 +46,9 @@ public class EchoCommand : IConsoleCommand
|
||||
EntityReference loco = new EntityReference(EntityType.Car, car.id);
|
||||
if (comps[2] == "+") message = new Hyperlink(entityReference.URI(), string.Format(message, OpsController.Shared.ClosestArea(car)?.name ?? "???"));
|
||||
|
||||
car.PostNotice(nameof(EchoCommand), $"{message} :{StateManager.Shared._playersManager.LocalPlayer}");
|
||||
if (StateManager.IsHost) car.PostNotice(nameof(EchoCommand), $"{message} :{StateManager.Shared._playersManager.LocalPlayer}");
|
||||
ExpandedConsole_Add_Patch.SendMs(null, $"{Hyperlink.To(car)} {message}");
|
||||
Multiplayer.Broadcast($"{StateManager.Shared._playersManager.LocalPlayer} {Hyperlink.To(car)}: \"{message}\"");
|
||||
if (!StateManager.IsHost) Multiplayer.Broadcast($"{StateManager.Shared._playersManager.LocalPlayer} {Hyperlink.To(car)}: \"{message}\"");
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"mixintos": {
|
||||
"container:ne-caboose01": "file(mroc-cabeese.json)",
|
||||
"container:ne-caboose02": "file(mroc-cabeese.json)",
|
||||
"container:ne-caboose03": "file(mroc-cabeese.json)"
|
||||
"container:ne-caboose03": "file(mroc-cabeese.json)",
|
||||
"game-graph": "file(tweakedLoadIDS.json)"
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace RMROC451.TweaksAndThings.Extensions
|
||||
yield break;
|
||||
}
|
||||
oiler._reverse = originIndex > oiler._cars.Count - originIndex;
|
||||
_log.Information(
|
||||
_log.Debug(
|
||||
"AutoOiler {name} starting, rev = {reverse}, caboose required = {req}, caboose halving adjustment = {hasCaboose}, oil limit = {limit}",
|
||||
oiler.name,
|
||||
oiler._reverse,
|
||||
@@ -58,11 +58,11 @@ namespace RMROC451.TweaksAndThings.Extensions
|
||||
num += num3;
|
||||
oiler._pendingRunDuration += num3;
|
||||
oiler._oiledCount++;
|
||||
_log.Information("AutoOiler {name}: oiled {car} from {orig} => {new}", oiler.name, car, origOil, car.Oiled);
|
||||
_log.Debug("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);
|
||||
_log.Debug("AutoOiler {name}: {foundCaboose} repaired hotbox {car}", oiler.name, foundCaboose, car);
|
||||
Multiplayer.Broadcast($"{Hyperlink.To(oiler._originCar)}: \"{Hyperlink.To(car)} hotbox repaired!\"");
|
||||
car.SendPropertyChange(PropertyChange.Control.Hotbox, false);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ namespace RMROC451.TweaksAndThings.Extensions
|
||||
continue;
|
||||
}
|
||||
var fc = foundCaboose();
|
||||
_log.Information("AutoHotboxSpotter {name}: Hotbox Spotter Running, Found Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}",
|
||||
_log.Debug("AutoHotboxSpotter {name}: Hotbox Spotter Running, Found Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}",
|
||||
spotter.name, fc, spotter.HasCars, cabooseRequired);
|
||||
if (CabooseRequirementChecker(string.Format("{0} {1}", spotter.GetType().Name, spotter.name), cabooseRequired, fc, _log))
|
||||
{
|
||||
@@ -104,7 +104,7 @@ namespace RMROC451.TweaksAndThings.Extensions
|
||||
{
|
||||
var numOrig = num;
|
||||
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, fc, cabooseRequired);
|
||||
_log.Debug("AutoHotboxSpotter {name}: Next check went from num(60,300) => {numOrig}; to num(15,30) => {hasCaboose}; Requires Caboose {requiresCaboose}", spotter.name, numOrig, num, fc, cabooseRequired);
|
||||
}
|
||||
yield return new WaitForSeconds(num);
|
||||
spotter.CheckForHotbox();
|
||||
|
||||
@@ -140,7 +140,7 @@ public static class Car_Extensions
|
||||
.Union(car.EnumerateCoupled())
|
||||
.Where(c => c.IsCaboose());
|
||||
|
||||
//if (cabeese?.Any() ?? false) Log.Information($"{nameof(CarsNearCurrentCar)}[{car.DisplayName}] => {cabeese.Count()}");
|
||||
if (cabeese?.Any() ?? false) Log.Debug($"{nameof(CarsNearCurrentCar)}[{car.DisplayName}] => {cabeese.Count()}");
|
||||
|
||||
List<(Car car, bool crewCar, float distance)> source =
|
||||
cabeese.Select(c => (car: c, crewCar: c.IsCrewCar(), distance: car.Distance(c))).ToList();
|
||||
|
||||
@@ -38,7 +38,7 @@ internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
|
||||
|
||||
if (orig != maxSpeedMph)
|
||||
{
|
||||
_log.Information($"{Enum.GetName(typeof(AutoEngineerMode), mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] {nameof(AutoEngineerOrdersExtensions.MaxSpeedMph)} limited to {limitedSpeed} from {orig}; No Caboose in Consist;");
|
||||
_log.Debug($"{Enum.GetName(typeof(AutoEngineerMode), mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] {nameof(AutoEngineerOrdersExtensions.MaxSpeedMph)} limited to {limitedSpeed} from {orig}; No Caboose in Consist;");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,9 @@ internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
|
||||
{
|
||||
var _persistence = new AutoEngineerPersistence(TrainController.Shared.SelectedLocomotive.KeyValueObject);
|
||||
var OrdersHelper = new AutoEngineerOrdersHelper(TrainController.Shared.SelectedLocomotive, _persistence);
|
||||
|
||||
|
||||
if (TrainController.Shared.SelectedLocomotive.EnumerateCoupled().All(c => c.IsCaboose() || c.MotivePower())) return false;
|
||||
|
||||
bool cabooseReq = SingletonPluginBase<TweaksAndThingsPlugin>.Shared.RequireConsistCabooseForOilerAndHotboxSpotter();
|
||||
string logMessage = $"\n{nameof(SafetyFirstGoverningApplies)}:{Enum.GetName(typeof(AutoEngineerMode), OrdersHelper.Mode)}[{TrainController.Shared.SelectedLocomotive.DisplayName}] ";
|
||||
Func<bool> firstClass = () =>
|
||||
@@ -85,7 +87,7 @@ internal class AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch
|
||||
|
||||
logMessage += $"\nGovern AE? {output}";
|
||||
|
||||
_log.Information(logMessage);
|
||||
_log.Debug(logMessage);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Game.Notices;
|
||||
using Game.State;
|
||||
using HarmonyLib;
|
||||
using Model;
|
||||
using Network;
|
||||
using Serilog;
|
||||
using UI.EngineControls;
|
||||
using UnityEngine;
|
||||
@@ -16,11 +18,14 @@ internal class AutoEngineerOrdersHelper_SetWaypoint_patch
|
||||
private static Serilog.ILogger _log => Log.ForContext<AutoEngineerOrdersHelper_SetWaypoint_patch>();
|
||||
static void Postfix(AutoEngineerOrdersHelper __instance, Track.Location location, string coupleToCarId)
|
||||
{
|
||||
_log.Information($"start setWP");
|
||||
Car selectedLoco = __instance._locomotive;
|
||||
_log.Information($"{selectedLoco?.DisplayName ?? ""} set WP");
|
||||
Vector3 gamePoint = location.GetPosition();
|
||||
EntityReference entityReference = new EntityReference(EntityType.Position, new Vector4(gamePoint.x, gamePoint.y, gamePoint.z, 0));
|
||||
selectedLoco.PostNotice("ai-wpt-rmroc451", new Hyperlink(entityReference.URI(), $"WP SET"));
|
||||
if (StateManager.IsHost)
|
||||
{
|
||||
_log.Debug($"start setWP");
|
||||
Car selectedLoco = __instance._locomotive;
|
||||
_log.Debug($"{selectedLoco?.DisplayName ?? ""} set WP");
|
||||
Vector3 gamePoint = location.GetPosition();
|
||||
EntityReference entityReference = new EntityReference(EntityType.Position, new Vector4(gamePoint.x, gamePoint.y, gamePoint.z, 0));
|
||||
selectedLoco.PostNotice("ai-wpt-rmroc451", new Hyperlink(entityReference.URI(), $"WP SET"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
using Game.State;
|
||||
using HarmonyLib;
|
||||
using KeyValue.Runtime;
|
||||
using Model;
|
||||
using Model.AI;
|
||||
using Model.Ops;
|
||||
using Network;
|
||||
using Network.Messages;
|
||||
using Railloader;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Track;
|
||||
using Track.Search;
|
||||
using UI;
|
||||
using UI.EngineControls;
|
||||
using UnityEngine;
|
||||
using static Track.Search.RouteSearch;
|
||||
using Location = Track.Location;
|
||||
|
||||
namespace RMROC451.TweaksAndThings.Patches;
|
||||
|
||||
[HarmonyPatch(typeof(AutoEngineerWaypointControls))]
|
||||
[HarmonyPatch(nameof(AutoEngineerWaypointControls.ConfigureOptionsDropdown))]
|
||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||
internal class AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch
|
||||
{
|
||||
private static Serilog.ILogger _log => Log.ForContext<AutoEngineerWaypointControls_ConfigureOptionsDropdown_Patch>();
|
||||
|
||||
private static readonly HashSet<IDisposable> _keyChangeObservers = new HashSet<IDisposable>();
|
||||
private static readonly HashSet<string> destinations = new HashSet<string>();
|
||||
private static readonly HashSet<Car> consist = new HashSet<Car>();
|
||||
private static string _lastLocoCarId = string.Empty;
|
||||
private static bool recalcing = false;
|
||||
|
||||
static void Postfix(AutoEngineerWaypointControls __instance, ref OptionsDropdownConfiguration __result)
|
||||
{
|
||||
|
||||
_log.Information($"HI BOB");
|
||||
foreach(var o in _keyChangeObservers) o.Dispose();
|
||||
_keyChangeObservers.Clear();
|
||||
destinations.Clear();
|
||||
recalcing = false;
|
||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
if (!tweaksAndThings.IsEnabled()) return;
|
||||
//_log.Information($"HI2");
|
||||
|
||||
|
||||
List<DropdownMenu.RowData> rowDatas = __result.Rows.ToList();
|
||||
var func = __result.OnRowSelected;
|
||||
int origCount = rowDatas.Count;
|
||||
int maxRowOrig = origCount - 1;
|
||||
|
||||
var selectedLoco = TrainController.Shared.SelectedLocomotive;
|
||||
if (selectedLoco.id != _lastLocoCarId || !(consist?.Any() ?? false))
|
||||
{
|
||||
_lastLocoCarId = selectedLoco.id;
|
||||
consist.Clear();
|
||||
consist.UnionWith(selectedLoco.EnumerateCoupled()?.ToList() ?? Enumerable.Empty<Car>());
|
||||
}
|
||||
var aeoh = new AutoEngineerOrdersHelper(persistence: new AutoEngineerPersistence(selectedLoco.KeyValueObject), locomotive: selectedLoco);
|
||||
List<(string destinationId, string destination, float? distance, Location? location)> jumpTos = new();
|
||||
|
||||
foreach(var c in consist)
|
||||
{
|
||||
AddObserversToCar(__instance, c);
|
||||
OpsCarPosition? destination = c.Waybill.HasValue && !c.Waybill.Value.Completed ? c.Waybill.Value.Destination : null;
|
||||
bool completed = c.Waybill?.Completed ?? false;
|
||||
if (!destination.HasValue && c.TryGetOverrideDestination(OverrideDestination.Repair, OpsController.Shared, out (OpsCarPosition, string)? result)) destination = result.Value.Item1;
|
||||
_log.Information($"{c.DisplayName} -> {destination.HasValue}");
|
||||
|
||||
string destId = destination?.Identifier ?? string.Empty;
|
||||
|
||||
if (destinations.Contains(destId)) continue;
|
||||
|
||||
if (destination.HasValue && !completed)
|
||||
{
|
||||
string destName = destination.Value.DisplayName;
|
||||
float? distance = null;
|
||||
|
||||
if (Graph.Shared.TryGetLocationFromPoint(destination.Value.Spans?.FirstOrDefault().GetSegments().FirstOrDefault(), destination.Value.Spans?.FirstOrDefault()?.GetCenterPoint() ?? default, 200f, out Location destLoc))
|
||||
{
|
||||
|
||||
float trainMomentum = 0f;
|
||||
Location start = StateManager.IsHost ? selectedLoco.AutoEngineerPlanner.RouteStartLocation(out trainMomentum) : RouteStartLocation(__instance, selectedLoco);
|
||||
HeuristicCosts autoEngineer = HeuristicCosts.AutoEngineer;
|
||||
List<RouteSearch.Step> list = new List<RouteSearch.Step>();
|
||||
var totLen = StateManager.IsHost ? selectedLoco.AutoEngineerPlanner.CalculateTotalLength() : CalculateTotalLength(selectedLoco);
|
||||
distance = Graph.Shared.FindRoute(start, destLoc, autoEngineer, list, out var metrics, checkForCars: false, totLen, trainMomentum)
|
||||
? metrics.Distance
|
||||
: null;
|
||||
};
|
||||
_log.Information($"{c.DisplayName} -> {destName} {destId} {distance?.ToString()}");
|
||||
if (distance.HasValue)
|
||||
{
|
||||
destinations.Add(destId);
|
||||
jumpTos.Add((
|
||||
destinationId: destId,
|
||||
destination: $"WP> {destName}"
|
||||
, distance: distance
|
||||
, location: (Location?)destLoc
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jumpTos = jumpTos?.OrderBy(c => c.distance)?.ToList() ?? [];
|
||||
var safetyFirst = AutoEngineerOrdersHelper_SendAutoEngineerCommand_Patch.SafetyFirstGoverningApplies() && jumpTos.Any();
|
||||
|
||||
rowDatas.AddRange(jumpTos.Select(j =>
|
||||
new DropdownMenu.RowData(
|
||||
$"{j.destination} <b>({(j.distance.HasValue ? Units.DistanceText(j.distance.Value) : "N/A")})</b>",
|
||||
!safetyFirst ? null : "<i>Disabled; Safety First!</i>"
|
||||
)
|
||||
));
|
||||
|
||||
__result = new OptionsDropdownConfiguration(
|
||||
rowDatas
|
||||
, delegate (int row)
|
||||
{
|
||||
_log.Information($"{TrainController.Shared.SelectedLocomotive.DisplayName} row {row}/{jumpTos.Count}/{rowDatas.Count}");
|
||||
if (row <= maxRowOrig)
|
||||
{
|
||||
func(row);
|
||||
}
|
||||
if (row > maxRowOrig && jumpTos[row - origCount].location.HasValue)
|
||||
{
|
||||
if (safetyFirst)
|
||||
{
|
||||
Multiplayer.SendError(StateManager.Shared.PlayersManager.LocalPlayer, "Safety First, find yourself a caboose!", AlertLevel.Error);
|
||||
return;
|
||||
}
|
||||
float trainMomentum = 0f;
|
||||
Location end = jumpTos[row - origCount].location.Value;
|
||||
Location start = RouteStartLocation(__instance, selectedLoco);
|
||||
HeuristicCosts autoEngineer = HeuristicCosts.AutoEngineer;
|
||||
List<RouteSearch.Step> list = new List<RouteSearch.Step>();
|
||||
|
||||
var totLen = StateManager.IsHost ? selectedLoco.AutoEngineerPlanner.CalculateTotalLength() : CalculateTotalLength(selectedLoco);
|
||||
if (!Graph.Shared.FindRoute(start, end, autoEngineer, list, out var metrics, checkForCars: false, totLen, trainMomentum))
|
||||
{
|
||||
RouteSearch.Metrics metrics2;
|
||||
bool flag = Graph.Shared.FindRoute(start, end, autoEngineer, null, out metrics2);
|
||||
Multiplayer.SendError(StateManager.Shared.PlayersManager.LocalPlayer, flag ? (selectedLoco.DisplayName + " Train too long to navigate to waypoint.") : (selectedLoco.DisplayName + " Unable to find a path to waypoint."), AlertLevel.Error);
|
||||
} else
|
||||
{
|
||||
var mw = (location: end, carId: string.Empty);
|
||||
aeoh.SetWaypoint(mw.location, mw.carId);
|
||||
aeoh.SetOrdersValue(maybeWaypoint: mw);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private static Location RouteStartLocation(AutoEngineerWaypointControls __instance, BaseLocomotive _locomotive) {
|
||||
bool num = _locomotive.IsStopped();
|
||||
bool? flag = (num ? null : new bool?(_locomotive.velocity >= 0f));
|
||||
|
||||
bool flag2 = flag ?? __instance.OrdersHelper.Orders.Forward;
|
||||
if (_locomotive.EndToLogical((!flag2) ? Car.End.R : Car.End.F) == Car.LogicalEnd.A)
|
||||
{
|
||||
return _locomotive.EnumerateCoupled().First().WheelBoundsA;
|
||||
}
|
||||
|
||||
return _locomotive.EnumerateCoupled(Car.LogicalEnd.B).First().WheelBoundsB.Flipped();
|
||||
}
|
||||
|
||||
private static float CalculateTotalLength(BaseLocomotive selectedLoco)
|
||||
{
|
||||
List<Car> coupledCarsCached = selectedLoco.EnumerateCoupled().ToList();
|
||||
float num = 0f;
|
||||
foreach (Car item in coupledCarsCached)
|
||||
{
|
||||
num += item.carLength;
|
||||
}
|
||||
|
||||
return num + 1.04f * (float)(coupledCarsCached.Count - 1);
|
||||
}
|
||||
|
||||
private static void AddObserversToCar(AutoEngineerWaypointControls __instance, Car c)
|
||||
{
|
||||
AddObserver(__instance, c, Car.KeyOpsWaybill);
|
||||
AddObserver(__instance, c, Car.KeyOpsRepairDestination);
|
||||
foreach (Car.LogicalEnd logicalEnd in CarInspector_PopulateCarPanel_Patch.ends)
|
||||
{
|
||||
AddObserver(__instance, c, Car.KeyValueKeyFor(Car.EndGearStateKey.IsCoupled, c.LogicalToEnd(logicalEnd)), true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddObserver(AutoEngineerWaypointControls __instance, Model.Car car, string key, bool clearCarCache = false)
|
||||
{
|
||||
_keyChangeObservers.Add(
|
||||
car.KeyValueObject.Observe(
|
||||
key,
|
||||
delegate (Value value)
|
||||
{
|
||||
_log.Information($"{car.DisplayName} OBSV {key}: {value}; recalcing {recalcing}");
|
||||
if (recalcing) return;
|
||||
try
|
||||
{
|
||||
foreach(var o in _keyChangeObservers)
|
||||
{
|
||||
o.Dispose();
|
||||
}
|
||||
var loco = TrainController.Shared.SelectedLocomotive;
|
||||
TrainController.Shared.SelectedCar = null;
|
||||
_keyChangeObservers.Clear();
|
||||
recalcing = true;
|
||||
new WaitForSeconds(0.25f);
|
||||
TrainController.Shared.SelectedCar = loco;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.ForContext("car", car).Warning(ex, $"{nameof(AddObserver)} {car} Exception logged for {key}");
|
||||
}
|
||||
},
|
||||
false
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -43,3 +43,89 @@ internal class BaseLocomotive_FindSourceLocomotive_Patch
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//[HarmonyPatch(typeof(LocomotiveAirSystem))]
|
||||
//[HarmonyPatch(nameof(LocomotiveAirSystem._ShouldDeferToLocomotiveAir))]
|
||||
//[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||
//internal class LocomotiveAirSystem__ShouldDeferToLocomotiveAir_Patch
|
||||
//{
|
||||
// private static void Postfix(LocomotiveAirSystem __instance, ref LocomotiveAirSystem locomotiveAirSystem, ref bool __result)
|
||||
// {
|
||||
// TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
// if (!tweaksAndThings.IsEnabled()) return;
|
||||
|
||||
// __result = _ShouldDeferToLocomotiveAir(__instance, out locomotiveAirSystem);
|
||||
// }
|
||||
// public static bool _ShouldDeferToLocomotiveAir(LocomotiveAirSystem __instance, out LocomotiveAirSystem locomotiveAirSystem)
|
||||
// {
|
||||
// locomotiveAirSystem = null;
|
||||
// if (__instance.car.set == null)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (!(__instance.car.air is LocomotiveAirSystem locomotiveAirSystem2) || !(__instance.car is BaseLocomotive baseLocomotive))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (!locomotiveAirSystem2.IsCutOut || locomotiveAirSystem2.IsMuEnabled)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// BaseLocomotive baseLocomotive2 = baseLocomotive.FindMuSourceLocomotive();
|
||||
// if (baseLocomotive2 == null)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (!(baseLocomotive2.air is LocomotiveAirSystem locomotiveAirSystem3))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// locomotiveAirSystem = locomotiveAirSystem3;
|
||||
// return true;
|
||||
// }
|
||||
//}
|
||||
|
||||
//[HarmonyPatch(typeof(CarAirSystem))]
|
||||
//[HarmonyPatch(nameof(CarAirSystem.ShouldDeferToLocomotiveAir))]
|
||||
//[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||
//internal class CarAirSystem_ShouldDeferToLocomotiveAir_Patch
|
||||
//{
|
||||
// private static void Postfix(CarAirSystem __instance, ref LocomotiveAirSystem locomotiveAirSystem, ref bool __result)
|
||||
// {
|
||||
// TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
// if (!tweaksAndThings.IsEnabled()) return;
|
||||
|
||||
// __result = ShouldDeferToLocomotiveAir(__instance, out locomotiveAirSystem);
|
||||
// }
|
||||
|
||||
// public static bool ShouldDeferToLocomotiveAir(CarAirSystem __instance, out LocomotiveAirSystem locomotiveAirSystem)
|
||||
// {
|
||||
// locomotiveAirSystem = null;
|
||||
// if (__instance.car.set == null)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (__instance.car.Archetype != CarArchetype.Tender)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (!__instance.car.TryGetAdjacentCar(__instance.car.EndToLogical(Car.End.F), out var adjacent) || !adjacent.IsLocomotive)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// if (!(adjacent.air is LocomotiveAirSystem locomotiveAirSystem2))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
// locomotiveAirSystem = locomotiveAirSystem2;
|
||||
// if (locomotiveAirSystem.IsMuEnabled)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// if (!locomotiveAirSystem.IsCutOut)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// return locomotiveAirSystem.ShouldDeferToLocomotiveAir(out locomotiveAirSystem);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace RMROC451.TweaksAndThings.Patches;
|
||||
internal class CarInspector_PopulateCarPanel_Patch
|
||||
{
|
||||
private static ILogger _log => Log.ForContext<CarInspector_PopulateCarPanel_Patch>();
|
||||
private static IEnumerable<LogicalEnd> ends = Enum.GetValues(typeof(LogicalEnd)).Cast<LogicalEnd>();
|
||||
internal static IEnumerable<LogicalEnd> ends = Enum.GetValues(typeof(LogicalEnd)).Cast<LogicalEnd>();
|
||||
|
||||
/// <summary>
|
||||
/// If a caboose inspector is opened, it will auto set Anglecocks, gladhands and hand brakes
|
||||
@@ -181,7 +181,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
||||
|
||||
case MrocHelperType.BleedAirSystem:
|
||||
consist = consist.Where(c => !c.MotivePower());
|
||||
_log.ForContext("car", car).Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
|
||||
_log.ForContext("car", car).Debug($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
|
||||
foreach (Model.Car bleed in consist)
|
||||
{
|
||||
StateManager.ApplyLocal(new PropertyChange(bleed.id, PropertyChange.Control.Bleed, 1));
|
||||
@@ -190,7 +190,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
||||
|
||||
case MrocHelperType.Oil:
|
||||
consist = consist.Where(c => c.NeedsOiling || c.HasHotbox);
|
||||
_log.ForContext("car", car).Information($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
|
||||
_log.ForContext("car", car).Debug($"{car} => {mrocHelperType} => {string.Join("/", consist.Select(c => c.ToString()))}");
|
||||
foreach (Model.Car oil in consist)
|
||||
{
|
||||
StateManager.ApplyLocal(new PropertyChange(oil.id, nameof(Car.Oiled).ToLower(), new FloatPropertyValue(1)));
|
||||
@@ -232,7 +232,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
||||
if (cabooseWithAvailCrew == null) timeCost *= 1.5f;
|
||||
var cabooseFoundDisplay = cabooseWithAvailCrew?.DisplayName ?? "No caboose";
|
||||
|
||||
_log.ForContext("car", car).Information($"{nameof(MrocConsistHelper)} {mrocHelperType} : [VACINITY CABEESE FOUND:{cabooseWithAvailCrew?.ToString() ?? "NONE"}] => Consist Length {consist.Count()} => costs {timeCost / 60} minutes of AI Engineer time, $5 per hour = ~${Math.Ceiling((decimal)(timeCost / 3600) * 5)} (*2 if no caboose nearby)");
|
||||
_log.ForContext("car", car).Debug($"{nameof(MrocConsistHelper)} {mrocHelperType} : [VACINITY CABEESE FOUND:{cabooseWithAvailCrew?.ToString() ?? "NONE"}] => Consist Length {consist.Count()} => costs {timeCost / 60} minutes of AI Engineer time, $5 per hour = ~${Math.Ceiling((decimal)(timeCost / 3600) * 5)} (*2 if no caboose nearby)");
|
||||
|
||||
|
||||
Multiplayer.SendError(StateManager.Shared._playersManager.LocalPlayer, $"{(cabooseWithAvailCrew != null ? $"{cabooseWithAvailCrew.DisplayName} Hours Adjusted: ({tsString})\n" : string.Empty)}Wages: ~(${Math.Ceiling((decimal)(timeCost / 3600) * 5)})");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using HarmonyLib;
|
||||
using Model;
|
||||
using Model.Ops;
|
||||
using Model.Physics;
|
||||
using Network;
|
||||
using Railloader;
|
||||
using RMROC451.TweaksAndThings.Enums;
|
||||
@@ -9,6 +10,7 @@ using RMROC451.TweaksAndThings.Extensions;
|
||||
using RollingStock;
|
||||
using Serilog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UI;
|
||||
using UI.Tags;
|
||||
@@ -40,92 +42,179 @@ internal class CarPickable_Activate_Patch
|
||||
{
|
||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
if (!tweaksAndThings.IsEnabled()) return true;
|
||||
bool bCtrlAltHeld = GameInput.IsControlDown && GameInput.IsAltDown;
|
||||
|
||||
_log.ForContext("car", __instance.car).Information($"{GameInput.IsShiftDown} {GameInput.IsControlDown} {GameInput.IsAltDown} {bCtrlAltHeld} ");
|
||||
_log.ForContext("car", __instance.car).Debug($"{GameInput.IsShiftDown} {GameInput.IsControlDown} {GameInput.IsAltDown}");
|
||||
|
||||
if (OnPointerDown(evt, PickableActivation.Primary))
|
||||
{
|
||||
CameraSelector.shared.FollowCar(__instance.car);
|
||||
_log.ForContext("car", __instance.car).Information("just click!");
|
||||
_log.ForContext("car", __instance.car).Debug("just click!");
|
||||
return false;
|
||||
|
||||
}
|
||||
//single click with keys pressed:
|
||||
else if (evt.Activation == PickableActivation.Primary)
|
||||
{
|
||||
bool output = true;
|
||||
var consist = __instance.car.EnumerateCoupled();
|
||||
bool handbrakesApplied = consist.Any(c => c.HandbrakeApplied());
|
||||
bool airSystemIssues = consist.Any(c => c.EndAirSystemIssue());
|
||||
Func<bool> cabooseNear = () => (bool)__instance.car.FindMyCaboose(0.0f, false);
|
||||
bool needsOiling = GameInput.IsShiftDown && consist.All(c => c.IsStopped()) && consist.Any(c => c.NeedsOiling || c.HasHotbox) && (!tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter() || cabooseNear());
|
||||
var chargeIt = handbrakesApplied || airSystemIssues || needsOiling;
|
||||
//CTRL + ALT + SHIFT : BrakesAngleCocksAndOiling
|
||||
//CTRL + ALT : Release Consist Brakes and Check AngleCocks
|
||||
//ALT + SHIFT : toggle consist brakes
|
||||
//CTRL + SHIFT : Check Consist Angle Cocks
|
||||
//ALT : Toggle car brakes and & air up cars
|
||||
//CTRL : NOTHING; BASE CAR INSPECTOR
|
||||
}
|
||||
return HandleCarOrTrainBrakeDisplayClick(__instance.car, tweaksAndThings, evt.Activation);
|
||||
}
|
||||
|
||||
internal static bool HandleCarOrTrainBrakeDisplayClick(Car car, TweaksAndThingsPlugin tweaksAndThings, PickableActivation activation)
|
||||
{
|
||||
bool bCtrlAltHeld = GameInput.IsControlDown && GameInput.IsAltDown;
|
||||
bool output = true;
|
||||
var consist = car.EnumerateCoupled();
|
||||
bool handbrakesApplied = consist.Any(c => c.HandbrakeApplied());
|
||||
bool airSystemIssues = consist.Any(c => c.EndAirSystemIssue());
|
||||
Func<bool> cabooseNear = () => (bool)car.FindMyCaboose(0.0f, false);
|
||||
bool needsOiling = GameInput.IsShiftDown && consist.All(c => c.IsStopped()) && consist.Any(c => c.NeedsOiling || c.HasHotbox) && (!tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter() || cabooseNear());
|
||||
var chargeIt = handbrakesApplied || airSystemIssues || needsOiling;
|
||||
//CTRL + ALT + SHIFT : BrakesAngleCocksAndOiling
|
||||
//CTRL + ALT : Release Consist Brakes and Check AngleCocks
|
||||
//ALT + SHIFT : toggle consist brakes
|
||||
//CTRL + SHIFT : Check Consist Angle Cocks
|
||||
//ALT : Toggle car brakes and & air up cars
|
||||
//CTRL : NOTHING; BASE CAR INSPECTOR
|
||||
//SHIFT : FOLLOW
|
||||
|
||||
if (activation == PickableActivation.Primary)
|
||||
{
|
||||
if (bCtrlAltHeld)
|
||||
{
|
||||
BrakesAngleCocksAndOiling(__instance, tweaksAndThings, GameInput.IsShiftDown, consist, handbrakesApplied, airSystemIssues, needsOiling, chargeIt);
|
||||
_log.ForContext("car", __instance.car).Information($"ctrlAlt{(GameInput.IsShiftDown ? "shift" : string.Empty)}Held!");
|
||||
BrakesAngleCocksAndOiling(car, tweaksAndThings, GameInput.IsShiftDown, consist, handbrakesApplied, airSystemIssues, needsOiling, chargeIt);
|
||||
_log.ForContext("car", car).Debug($"ctrlAlt{(GameInput.IsShiftDown ? "shift" : string.Empty)}Held!");
|
||||
output = false;
|
||||
}
|
||||
else if (GameInput.IsAltDown && GameInput.IsShiftDown)
|
||||
{
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment());
|
||||
_log.ForContext("car", __instance.car).Information("ctrlShiftHeld!");
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment());
|
||||
_log.ForContext("car", car).Debug("ctrlShiftHeld!");
|
||||
output = false;
|
||||
}
|
||||
else if (GameInput.IsControlDown && GameInput.IsShiftDown)
|
||||
{
|
||||
if (airSystemIssues)
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.GladhandAndAnglecock, tweaksAndThings.EndGearHelpersRequirePayment());
|
||||
_log.ForContext("car", __instance.car).Information("altShiftHeld!");
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, tweaksAndThings.EndGearHelpersRequirePayment());
|
||||
_log.ForContext("car", car).Debug("altShiftHeld!");
|
||||
output = false;
|
||||
}
|
||||
else if (GameInput.IsAltDown)
|
||||
{
|
||||
__instance.car.SetHandbrake(!__instance.car.HandbrakeApplied());
|
||||
CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(__instance.car);
|
||||
if (__instance.car.TryGetAdjacentCar(Car.LogicalEnd.A, out Model.Car cA)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cA);
|
||||
if (__instance.car.TryGetAdjacentCar(Car.LogicalEnd.B, out Model.Car cB)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cB);
|
||||
_log.ForContext("car", __instance.car).Information("ctrlHeld!");
|
||||
TagController.Shared.UpdateTag(__instance.car, __instance.car.TagCallout, OpsController.Shared);
|
||||
__instance.car.TagCallout.Update();
|
||||
car.SetHandbrake(!car.HandbrakeApplied());
|
||||
CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(car);
|
||||
if (car.TryGetAdjacentCar(Car.LogicalEnd.A, out Model.Car cA)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cA);
|
||||
if (car.TryGetAdjacentCar(Car.LogicalEnd.B, out Model.Car cB)) CarInspector_PopulateCarPanel_Patch.CarEndAirUpdate(cB);
|
||||
_log.ForContext("car", car).Debug("ctrlHeld!");
|
||||
TagController.Shared.UpdateTag(car, car.TagCallout, OpsController.Shared);
|
||||
car.TagCallout.Update();
|
||||
output = false;
|
||||
}
|
||||
return output;
|
||||
|
||||
|
||||
//else if (ctrlHeld && shiftHeld)
|
||||
//{
|
||||
// var selected = UI.CarInspector.CarInspector._instance._selectedTabState.Value;
|
||||
// UI.CarInspector.CarInspector.Show(__instance.car);
|
||||
// UI.CarInspector.CarInspector._instance._selectedTabState.Value = selected;
|
||||
|
||||
//}
|
||||
else if (GameInput.IsShiftDown)
|
||||
{
|
||||
CameraSelector.shared.FollowCar(car);
|
||||
output = false;
|
||||
}
|
||||
}
|
||||
else if ((GameInput.IsControlDown || GameInput.IsAltDown) && activation == PickableActivation.Secondary)
|
||||
{
|
||||
AltClickageMyBrosif(car, activation);
|
||||
output = false;
|
||||
}
|
||||
else if (activation == PickableActivation.Secondary)
|
||||
{
|
||||
//AltClickageMyBrosif(car, activation);
|
||||
CarPickable.HandleShowContextMenu(car);
|
||||
output = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return output;
|
||||
}
|
||||
|
||||
private static void BrakesAngleCocksAndOiling(CarPickable __instance, TweaksAndThingsPlugin tweaksAndThings, bool shiftHeld, System.Collections.Generic.IEnumerable<Car> consist, bool handbrakesApplied, bool airSystemIssues, bool needsOiling, bool chargeIt)
|
||||
private static void AltClickageMyBrosif(Car car, PickableActivation activation)
|
||||
{
|
||||
//if (GameInput.IsControlDown)
|
||||
//{
|
||||
|
||||
//}
|
||||
//else if (GameInput.IsAltDown)
|
||||
//{
|
||||
// logSet(car);
|
||||
// //car.TryGetAdjacentCar(Car.LogicalEnd.A, out var OutCarA);
|
||||
// //car.TryGetAdjacentCar(Car.LogicalEnd.B, out var OutCarB);
|
||||
// output = false;
|
||||
//}
|
||||
List<Car> cars = TrainController.Shared.SelectedLocomotive.EnumerateCoupled().ToList();
|
||||
logSet(car);
|
||||
//car.TryGetAdjacentCar(Car.LogicalEnd.A, out var OutCarA);
|
||||
//car.TryGetAdjacentCar(Car.LogicalEnd.B, out var OutCarB);
|
||||
//bool b4 = false;
|
||||
//if ((Object)(object)OutCarA != (Object)null && OutCarA.id == cars[i - 1].id)
|
||||
//{
|
||||
// cars[i - 1].ApplyEndGearChange(Car.LogicalEnd.B, Car.EndGearStateKey.Anglecock, 0f);
|
||||
// ccar.ApplyEndGearChange(Car.LogicalEnd.A, Car.EndGearStateKey.Anglecock, 0f);
|
||||
// ccar.HandleCouplerClick(ccar.EndGearA.Coupler);
|
||||
// logger.Information("{indName}: Decoupled {ccarName} from {cars1Name} at NOA{FR}", new object[4]
|
||||
// {
|
||||
// ((Object)base.Industry).name,
|
||||
// ccar.DisplayName,
|
||||
// cars[i - 1].DisplayName,
|
||||
// (ccar.LogicalToEnd(Car.LogicalEnd.A) == Car.End.F) ? "F" : "R"
|
||||
// });
|
||||
// Storage.LastCarEnd = ccar.LogicalToEnd(Car.LogicalEnd.A);
|
||||
// b4 = true;
|
||||
//}
|
||||
//if ((Object)(object)OutCarB != (Object)null && !b4 && OutCarB.id == cars[i - 1].id)
|
||||
//{
|
||||
// cars[i - 1].ApplyEndGearChange(Car.LogicalEnd.A, Car.EndGearStateKey.Anglecock, 0f);
|
||||
// ccar.ApplyEndGearChange(Car.LogicalEnd.B, Car.EndGearStateKey.Anglecock, 0f);
|
||||
// ccar.HandleCouplerClick(ccar.EndGearB.Coupler);
|
||||
// logger.Information("{indName}: Decoupled {ccarName} from {carsm1Name} at NOB{FR}", new object[4]
|
||||
// {
|
||||
// ((Object)base.Industry).name,
|
||||
// ccar.DisplayName,
|
||||
// cars[i - 1].DisplayName,
|
||||
// (ccar.LogicalToEnd(Car.LogicalEnd.A) == Car.End.F) ? "F" : "R"
|
||||
// });
|
||||
// Storage.LastCarEnd = ccar.LogicalToEnd(Car.LogicalEnd.B);
|
||||
// b4 = true;
|
||||
//}
|
||||
//if (!b4)
|
||||
//{
|
||||
// logger.Information("{IndName}: ERROR: NLC {ccarName} can't find LCC {carsm1Name} ({OutCarAName},{OutCarBName})", new object[5]
|
||||
// {
|
||||
// ((Object)base.Industry).name,
|
||||
// ccar.DisplayName,
|
||||
// cars[i - 1].DisplayName,
|
||||
// ((Object)(object)OutCarA != (Object)null) ? OutCarA.DisplayName : "no Car",
|
||||
// ((Object)(object)OutCarB != (Object)null) ? OutCarB.DisplayName : "no Car"
|
||||
// });
|
||||
// return;
|
||||
//}
|
||||
}
|
||||
|
||||
private static void logSet(Car refCar)
|
||||
{
|
||||
IntegrationSet set = refCar.set;
|
||||
foreach (Car car in set.Cars)
|
||||
{
|
||||
Car acar;
|
||||
string endA = (car.TryGetAdjacentCar(Car.LogicalEnd.A, out acar) ? acar.DisplayName : "none");
|
||||
Car bcar;
|
||||
string endB = (car.TryGetAdjacentCar(Car.LogicalEnd.B, out bcar) ? bcar.DisplayName : "none");
|
||||
_log.Information("[Car: {id}:(EndA:{carA}),(EndB:{carB}),(FisA:{fisA})]", new object[4] { car.DisplayName, endA, endB, car.FrontIsA });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void BrakesAngleCocksAndOiling(Car car, TweaksAndThingsPlugin tweaksAndThings, bool shiftHeld, System.Collections.Generic.IEnumerable<Car> consist, bool handbrakesApplied, bool airSystemIssues, bool needsOiling, bool chargeIt)
|
||||
{
|
||||
int hbFix = 0;
|
||||
if (handbrakesApplied)
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.Handbrake, false);
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, false);
|
||||
if (airSystemIssues)
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.GladhandAndAnglecock, false);
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, false);
|
||||
if (needsOiling)
|
||||
hbFix = CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(__instance.car, MrocHelperType.Oil, false);
|
||||
hbFix = CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Oil, false);
|
||||
if (hbFix > 0)
|
||||
Multiplayer.Broadcast($"Near {Hyperlink.To(__instance.car)}: \"{hbFix.Pluralize("hotbox") + " repaired!"}\"");
|
||||
Multiplayer.Broadcast($"Near {Hyperlink.To(car)}: \"{hbFix.Pluralize("hotbox") + " repaired!"}\"");
|
||||
if (chargeIt)
|
||||
CarInspector_PopulateCarPanel_Patch.CalculateCostIfEnabled(__instance.car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment(), consist);
|
||||
CarInspector_PopulateCarPanel_Patch.CalculateCostIfEnabled(car, MrocHelperType.Handbrake, tweaksAndThings.EndGearHelpersRequirePayment(), consist);
|
||||
}
|
||||
|
||||
public static bool OnPointerDown(
|
||||
|
||||
@@ -44,23 +44,24 @@ internal class CarPickable_HandleShowContextMenu_Patch
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.BleedAirSystem, buttonsHaveCost);
|
||||
});
|
||||
}
|
||||
|
||||
shared.AddButton(ContextMenuQuadrant.Brakes, $"{(car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
|
||||
{
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
|
||||
});
|
||||
|
||||
if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
|
||||
{
|
||||
shared.AddButton(ContextMenuQuadrant.Brakes, $"{(car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
|
||||
{
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.Handbrake, buttonsHaveCost);
|
||||
});
|
||||
|
||||
if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
|
||||
{
|
||||
shared.AddButton(ContextMenuQuadrant.Unused2, $"Air Up Consist", SpriteName.Select, delegate
|
||||
{
|
||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (car.SupportsBleed())
|
||||
else
|
||||
{
|
||||
if (car.SupportsBleed())
|
||||
{
|
||||
shared.AddButton(ContextMenuQuadrant.Brakes, "Bleed", SpriteName.Bleed, car.SetBleed);
|
||||
}
|
||||
shared.AddButton(ContextMenuQuadrant.Brakes, car.air.handbrakeApplied ? "Release Handbrake" : "Apply Handbrake", SpriteName.Handbrake, delegate
|
||||
|
||||
@@ -39,7 +39,7 @@ internal class MapWindow_OnClick_Patch
|
||||
texture2D.wrapMode = TextureWrapMode.Clamp;
|
||||
if (!ImageConversion.LoadImage(texture2D, File.ReadAllBytes(path)))
|
||||
{
|
||||
_log.Information($"Unable to load {name} icon!");
|
||||
_log.Debug($"Unable to load {name} icon!");
|
||||
return null;
|
||||
}
|
||||
Sprite sprite = Sprite.Create(texture2D, new Rect(0f, 0f, texture2D.width, texture2D.height), new Vector2(0.5f, 0.5f));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Game.Notices;
|
||||
using Game.State;
|
||||
using HarmonyLib;
|
||||
using Model;
|
||||
using Serilog;
|
||||
@@ -14,10 +15,11 @@ internal class NoticeExtensions_PostNotice_Patch
|
||||
private static ILogger _log => Log.ForContext<NoticeExtensions_PostNotice_Patch>();
|
||||
static void Postfix(Car car, string key, string content)
|
||||
{
|
||||
if (!StateManager.IsHost) return;
|
||||
try
|
||||
{
|
||||
|
||||
//Log.Information($"{car.DisplayName} patch PostNotice");
|
||||
//Log.Debug($"{car.DisplayName} patch PostNotice");
|
||||
if (!string.IsNullOrEmpty(content) &&
|
||||
key.Equals("ai-wpt") &&
|
||||
content.ToLower().Contains("Arrived at Waypoint".ToLower())
|
||||
|
||||
@@ -113,18 +113,18 @@ internal class OpsController_AnnounceCoalescedPayments_Patch
|
||||
|
||||
var passengerStops = OpsController.Shared.AllIndustries
|
||||
.SelectMany(i => i.TrackDisplayables.Where(t => refillLocations.Contains(t.GetType())));
|
||||
//Log.Information($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops => {string.Join(",", passengerStops)}");
|
||||
//Log.Debug($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops => {string.Join(",", passengerStops)}");
|
||||
|
||||
var cabeese = passengerStops
|
||||
.SelectMany(t => t.TrackSpans?.Select(s => (tc.CarsOnSpan(s) ?? Enumerable.Empty<Car>()).Where(c => c.IsCaboose()))?.SelectMany(c => c?.Select(c2 => (t, c2))));
|
||||
//Log.Information($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops Cabeese => {string.Join(",", cabeese?.Select(c => $"{c.t} : {c.c2}") ?? [])}");
|
||||
//Log.Debug($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper => PassengerStops Cabeese => {string.Join(",", cabeese?.Select(c => $"{c.t} : {c.c2}") ?? [])}");
|
||||
|
||||
CrewCarDict = CrewCarDict.Where(kvp => cabeese.Select(c => c.c2.id).Contains(kvp.Key)).ToDictionary(k => k.Key, v => v.Value);
|
||||
|
||||
var deltaTime = (float)(TimeWeather.Now.TotalSeconds - dateTime.TotalSeconds);
|
||||
foreach (var caboose in cabeese)
|
||||
{
|
||||
//Log.Information($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper ({deltaTime}) => {caboose.t} : {caboose.c2}");
|
||||
//Log.Debug($"{nameof(OpsController_AnnounceCoalescedPayments_Patch)} => Caboose Helper ({deltaTime}) => {caboose.t} : {caboose.c2}");
|
||||
CarLoadCrewHelper(caboose.c2, deltaTime);
|
||||
}
|
||||
dateTime = TimeWeather.Now;
|
||||
|
||||
@@ -28,7 +28,7 @@ internal class TagController_UpdateTag_Patch
|
||||
return;
|
||||
}
|
||||
|
||||
ProceedWithPostFix(car, tagCallout, tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter() || !tweaksAndThings.CabooseRequiredForLocoOilIndicator());
|
||||
ProceedWithPostFix(car, tagCallout, tweaksAndThings.CabooseRequiredForLocoOilIndicator());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using HarmonyLib;
|
||||
using Model;
|
||||
using Railloader;
|
||||
using UI;
|
||||
using UI.Tags;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RMROC451.TweaksAndThings.Patches;
|
||||
|
||||
[HarmonyPatch(typeof(TrainBrakeDisplay))]
|
||||
[HarmonyPatch(nameof(TrainBrakeDisplay.Update))]
|
||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||
internal class TrainBrakeDisplay_Update_Patch()
|
||||
{
|
||||
private static bool Prefix(TrainBrakeDisplay __instance)
|
||||
{
|
||||
|
||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
if (!tweaksAndThings.IsEnabled()) return true;
|
||||
|
||||
TweakedOriginalMethods.TrainBrakeDisplay.Update(__instance);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(TrainBrakeDisplay))]
|
||||
[HarmonyPatch(nameof(TrainBrakeDisplay.ColorForCar))]
|
||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||
internal class TrainBrakeDisplay_ColorForCar_Patch
|
||||
{
|
||||
private static bool Prefix(TrainBrakeDisplay __instance, Car car, ref Color __result)
|
||||
{
|
||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
if (!tweaksAndThings.IsEnabled() || !tweaksAndThings.TrainBrakeDisplayShowsColorsInCalloutMode() || !TagController.Shared.TagsVisible) return true;
|
||||
|
||||
TweakedOriginalMethods.TrainBrakeDisplay.ColorForCar(__instance, car, ref __result);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup><!-- Optionally, set a few things to your liking -->
|
||||
<PropertyGroup>
|
||||
<!-- Optionally, set a few things to your liking -->
|
||||
<!-- <MajorVersion>1</MajorVersion> -->
|
||||
<!-- <MinorVersion>0</MinorVersion> -->
|
||||
|
||||
<SignAssembly>False</SignAssembly>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<Optimize>False</Optimize>
|
||||
|
||||
@@ -29,7 +29,8 @@ public class Settings
|
||||
bool servicingFundPenalty,
|
||||
bool safetyFirst,
|
||||
CrewHourLoadMethod loadCrewHoursMethod,
|
||||
float cabeeseSearchRadiusFtInMeters
|
||||
float cabeeseSearchRadiusFtInMeters,
|
||||
bool trainBrakeDisplayShowsColorsInCalloutMode
|
||||
)
|
||||
{
|
||||
WebhookSettingsList = webhookSettingsList;
|
||||
@@ -43,6 +44,7 @@ public class Settings
|
||||
SafetyFirst = safetyFirst;
|
||||
LoadCrewHoursMethod = loadCrewHoursMethod;
|
||||
CabeeseSearchRadiusFtInMeters = cabeeseSearchRadiusFtInMeters;
|
||||
TrainBrakeDisplayShowsColorsInCalloutMode = trainBrakeDisplayShowsColorsInCalloutMode;
|
||||
}
|
||||
|
||||
public readonly UIState<string> _selectedTabState = new UIState<string>(null);
|
||||
@@ -57,6 +59,7 @@ public class Settings
|
||||
public bool SafetyFirst;
|
||||
public CrewHourLoadMethod LoadCrewHoursMethod;
|
||||
public float CabeeseSearchRadiusFtInMeters;
|
||||
public bool TrainBrakeDisplayShowsColorsInCalloutMode;
|
||||
|
||||
internal void AddAnotherRow()
|
||||
{
|
||||
@@ -64,7 +67,7 @@ public class Settings
|
||||
if (!string.IsNullOrEmpty(WebhookSettingsList.OrderByDescending(wsl => wsl.WebhookUrl).Last().WebhookUrl))
|
||||
{
|
||||
WebhookSettingsList.Add(new());
|
||||
Log.Information($"Adding another {nameof(WebhookSettings)} list entry, last one was filled in");
|
||||
Log.Debug($"Adding another {nameof(WebhookSettings)} list entry, last one was filled in");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +138,7 @@ public static class SettingsExtensions
|
||||
input?.settings?.SafetyFirst ?? false;
|
||||
public static bool DayLoadCrewHours(this TweaksAndThingsPlugin input) =>
|
||||
(input?.settings?.LoadCrewHoursMethod ?? CrewHourLoadMethod.Tracks) == CrewHourLoadMethod.Daily;
|
||||
public static float CabeeseSearchRadiusInMeters(this TweaksAndThingsPlugin input) =>
|
||||
input?.settings?.CabeeseSearchRadiusFtInMeters ?? 21f;
|
||||
public static bool TrainBrakeDisplayShowsColorsInCalloutMode(this TweaksAndThingsPlugin input) =>
|
||||
input?.settings?.TrainBrakeDisplayShowsColorsInCalloutMode ?? false;
|
||||
|
||||
}
|
||||
177
TweaksAndThings/TweakedOriginalMethods/TrainBrakeDisplay.cs
Normal file
177
TweaksAndThings/TweakedOriginalMethods/TrainBrakeDisplay.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
using Model;
|
||||
using Model.Ops;
|
||||
using Model.Physics;
|
||||
using Railloader;
|
||||
using RMROC451.TweaksAndThings.Patches;
|
||||
using UI;
|
||||
using UI.CarInspector;
|
||||
using UI.Common;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using static UnityEngine.UI.Image;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace RMROC451.TweaksAndThings.TweakedOriginalMethods
|
||||
{
|
||||
internal static class TrainBrakeDisplay
|
||||
{
|
||||
internal static void ColorForCar(UI.TrainBrakeDisplay __instance, Car car, ref Color __result)
|
||||
{
|
||||
__result = Color.gray;
|
||||
|
||||
if (car.IsDerailed)
|
||||
{
|
||||
__result = __instance.derailedColor;
|
||||
return;
|
||||
}
|
||||
CarAirSystem air = car.air;
|
||||
OpsController opsController = OpsController.Shared;
|
||||
if (air.handbrakeApplied)
|
||||
{
|
||||
__result = __instance.handbrakeAppliedColor;
|
||||
return;
|
||||
}
|
||||
else if (
|
||||
(Object)(object)opsController != (Object)null &&
|
||||
opsController.TryGetDestinationInfo(car, out var destinationName, out var isAtDestination, out var destinationPosition, out var destination)
|
||||
)
|
||||
{
|
||||
Area area = opsController.AreaForCarPosition(destination);
|
||||
if ((Object)(object)area != (Object)null)
|
||||
{
|
||||
__result = area.tagColor;
|
||||
}
|
||||
if (!isAtDestination)
|
||||
{
|
||||
float num = 1f / __result.maxColorComponent;
|
||||
__result *= num;
|
||||
}
|
||||
}
|
||||
|
||||
if (Mathf.InverseLerp(0f, 72f, air.BrakeCylinder.Pressure) >= 10f) __result = (__result + __instance.ColorForPsi(air.BrakeCylinder.Pressure)) / 2f;
|
||||
}
|
||||
|
||||
internal static Image GetCarImage(UI.TrainBrakeDisplay __instance, int index, float xCyl, float yCyl, Car car)
|
||||
{
|
||||
Image output = null;
|
||||
if (__instance._carImages.Count - 1 < index)
|
||||
{
|
||||
var tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||
GameObject val = new GameObject();
|
||||
val.transform.SetParent(((Component)__instance).transform, false);
|
||||
((Object)val).name = $"Car {index}";
|
||||
float height = 12f;
|
||||
val.AddComponent<RectTransform>().SetFrame(xCyl, yCyl, __instance._imageWidth, height);
|
||||
EventTrigger trigger = val.AddComponent<EventTrigger>();
|
||||
EventTrigger.Entry entry = new EventTrigger.Entry();
|
||||
entry.eventID = EventTriggerType.PointerClick;
|
||||
entry.callback.AddListener((eventData) => {
|
||||
PointerEventData ped = (PointerEventData)eventData;
|
||||
PickableActivation pa = PickableActivation.Primary;
|
||||
if (ped.button == PointerEventData.InputButton.Right) pa = PickableActivation.Secondary;
|
||||
|
||||
bool checkFurther = ped.button == PointerEventData.InputButton.Middle ? true : CarPickable_Activate_Patch.HandleCarOrTrainBrakeDisplayClick(car, tweaksAndThings, pa);
|
||||
if (checkFurther & GameInput.IsControlDown) CarInspector.Show(car);
|
||||
});
|
||||
trigger.triggers.Add(entry);
|
||||
output = val.AddComponent<Image>();
|
||||
|
||||
output.type = (Type)1;
|
||||
__instance._carImages.Add(output);
|
||||
}
|
||||
else
|
||||
{
|
||||
output = __instance._carImages[index];
|
||||
((Component)output).gameObject.SetActive(true);
|
||||
}
|
||||
output.sprite = (car.IsLocomotive ? __instance.locomotiveTile : __instance.carTile);
|
||||
return output;
|
||||
}
|
||||
|
||||
internal static void Update(UI.TrainBrakeDisplay __instance)
|
||||
{
|
||||
Car selectedCar = __instance._trainController.SelectedCar;
|
||||
if (selectedCar == null || selectedCar.set == null) return;
|
||||
|
||||
int numberOfCars = selectedCar.set.NumberOfCars;
|
||||
if (numberOfCars != __instance._lastNumCars)
|
||||
{
|
||||
__instance.RemoveAllImages();
|
||||
int num = Mathf.Clamp(numberOfCars, 0, 100);
|
||||
float num2 = (float)num * 8f + (float)(num - 1) * 1f;
|
||||
if (num2 > __instance._rectTransform.rect.width)
|
||||
{
|
||||
float num3 = __instance._rectTransform.rect.width / num2;
|
||||
__instance._imageWidth = 8f * num3;
|
||||
__instance._spacing = 1f * num3;
|
||||
}
|
||||
else
|
||||
{
|
||||
__instance._imageWidth = 8f;
|
||||
__instance._spacing = 1f;
|
||||
}
|
||||
|
||||
__instance._lastNumCars = numberOfCars;
|
||||
}
|
||||
|
||||
int num4 = 0;
|
||||
float num5 = __instance._imageWidth / 2f;
|
||||
float num6 = 0f;
|
||||
float y = 12f - 2f * __instance._spacing;
|
||||
Car.LogicalEnd logicalEnd = ((selectedCar.set.IndexOfCar(selectedCar).GetValueOrDefault(0) >= numberOfCars / 2) ? Car.LogicalEnd.B : Car.LogicalEnd.A);
|
||||
Car.LogicalEnd end = ((logicalEnd == Car.LogicalEnd.A) ? Car.LogicalEnd.B : Car.LogicalEnd.A);
|
||||
bool stop = false;
|
||||
int carIndex = selectedCar.set.StartIndexForConnected(selectedCar, logicalEnd, IntegrationSet.EnumerationCondition.Coupled);
|
||||
Car car;
|
||||
while (!stop && (car = selectedCar.set.NextCarConnected(ref carIndex, logicalEnd, IntegrationSet.EnumerationCondition.Coupled, out stop)) != null && !(num5 > __instance._rectTransform.rect.width))
|
||||
{
|
||||
Image carImage = TweakedOriginalMethods.TrainBrakeDisplay.GetCarImage(__instance, num4, num5, 0f, car);
|
||||
num5 += __instance._imageWidth + __instance._spacing;
|
||||
carImage.color = __instance.ColorForCar(car);
|
||||
Image airImage = __instance.GetAirImage(num4, num6, y);
|
||||
num6 += __instance._imageWidth + __instance._spacing;
|
||||
Color color;
|
||||
if (!car[logicalEnd].IsCoupled)
|
||||
{
|
||||
color = ColorForOuterAnglecock(car[logicalEnd].AnglecockSetting);
|
||||
}
|
||||
else
|
||||
{
|
||||
Car car2 = car.CoupledTo(logicalEnd);
|
||||
bool num7 = car2 != null && car2[end].AnglecockSetting > 0.9f;
|
||||
bool flag = car[logicalEnd].AnglecockSetting > 0.9f;
|
||||
color = ((num7 && flag && car[logicalEnd].IsAirConnected) ? Color.clear : Color.white);
|
||||
}
|
||||
|
||||
airImage.color = color;
|
||||
if (!car[end].IsCoupled)
|
||||
{
|
||||
__instance.GetAirImage(num4 + 1, num6, y).color = ColorForOuterAnglecock(car[end].AnglecockSetting);
|
||||
}
|
||||
|
||||
num4++;
|
||||
}
|
||||
|
||||
for (int i = num4; i < __instance._carImages.Count; i++)
|
||||
{
|
||||
__instance._carImages[i].gameObject.SetActive(value: false);
|
||||
}
|
||||
|
||||
for (int j = num4 + 1; j < __instance._airImages.Count; j++)
|
||||
{
|
||||
__instance._airImages[j].gameObject.SetActive(value: false);
|
||||
}
|
||||
|
||||
static Color ColorForOuterAnglecock(float value)
|
||||
{
|
||||
if (!((double)value < 0.01))
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
return Color.clear;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
||||
|
||||
static TweaksAndThingsPlugin()
|
||||
{
|
||||
Log.Information("Hello! Static Constructor was called!");
|
||||
Log.Debug("Hello! Static Constructor was called!");
|
||||
}
|
||||
|
||||
public TweaksAndThingsPlugin(IModdingContext moddingContext, IModDefinition self)
|
||||
@@ -49,7 +49,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
||||
|
||||
this.moddingContext = moddingContext;
|
||||
|
||||
logger.Information("Hello! Constructor was called for {modId}/{modVersion}!", self.Id, self.Version);
|
||||
logger.Debug("Hello! Constructor was called for {modId}/{modVersion}!", self.Id, self.Version);
|
||||
|
||||
moddingContext.RegisterConsoleCommand(new EchoCommand());
|
||||
|
||||
@@ -58,7 +58,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
logger.Information("OnEnable() was called!");
|
||||
logger.Debug("OnEnable() was called!");
|
||||
var harmony = new Harmony(modDefinition.Id);
|
||||
harmony.PatchCategory(modDefinition.Id.Replace(".", string.Empty));
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
||||
|
||||
public void ModTabDidOpen(UIPanelBuilder builder)
|
||||
{
|
||||
logger.Information("Daytime!");
|
||||
logger.Debug("Daytime!");
|
||||
|
||||
if (settings == null) settings = new();
|
||||
if (!settings?.WebhookSettingsList?.Any() ?? true) settings.WebhookSettingsList = new[] { new WebhookSettings() }.ToList();
|
||||
@@ -88,7 +88,9 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
||||
settings?.WebhookSettingsList.SanitizeEmptySettings();
|
||||
|
||||
builder.AddSection("Adjustments To Base Game", (UIPanelBuilder builder) => {
|
||||
builder.AddLabel("Repair tracks now require cars to be waybilled, or they will not be serviced/overhauled.\nThey will report on the company window's location section as 'No Work Order Assigned'.");
|
||||
builder.AddLabel("1) Repair tracks now require cars to be waybilled, or they will not be serviced/overhauled.\nThey will report on the company window's location section as 'No Work Order Assigned'.");
|
||||
builder.Spacer(spacing * spacing);
|
||||
builder.AddLabel("2) You now have the same click options on the little car icons in the lower left engine controls ui, as you do with cars in the game. Ctrl click -> open car inspector, etc.");
|
||||
});
|
||||
builder.Spacer(spacing * spacing);
|
||||
builder.AddTabbedPanels(settings._selectedTabState, delegate (UITabbedPanelBuilder tabBuilder)
|
||||
@@ -236,6 +238,18 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
|
||||
}
|
||||
).Tooltip("Allow Insufficient Funds", $@"Will allow interchange service and repair shops to still function when you are insolvent, at a 20% overdraft fee.");
|
||||
|
||||
builder.Spacer(spacing);
|
||||
builder.AddFieldToggle(
|
||||
"Train Brake Color Mode",
|
||||
() => this.TrainBrakeDisplayShowsColorsInCalloutMode(),
|
||||
delegate (bool enabled)
|
||||
{
|
||||
if (settings == null) settings = new();
|
||||
settings.TrainBrakeDisplayShowsColorsInCalloutMode = enabled;
|
||||
builder.Rebuild();
|
||||
}
|
||||
).Tooltip("Train Brake Color Mode", $@"When enabled/checked and car tag callout mode is enabled (showing car tags hovering over them), the train brake display of the selected locomotive will change the cars/engines to their destination area's color to help you visualize sets of cars at a glance.");
|
||||
|
||||
builder.Spacer(spacing);
|
||||
EngineRosterShowsFuelStatusUISection(builder);
|
||||
}
|
||||
@@ -256,7 +270,7 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
|
||||
builder.Rebuild();
|
||||
}
|
||||
)
|
||||
).Tooltip("Enable Fuel Display in Engine Roster", $"Will add reaming fuel indication to Engine Roster (with details in roster row tool tip), Examples : {string.Join(" ", Enumerable.Range(0, 4).Select(i => TextSprites.PiePercent(i, 4)))}");
|
||||
).Tooltip("Enable Fuel Display in Engine Roster", $"Will add reamaing fuel indication to Engine Roster (with details in roster row tool tip), Examples : {string.Join(" ", Enumerable.Range(0, 4).Select(i => TextSprites.PiePercent(i, 4)))}");
|
||||
|
||||
builder.Spacer(spacing);
|
||||
builder.AddFieldToggle(
|
||||
@@ -333,7 +347,7 @@ AutoHotboxSpotter Update: decrease the random wait from 30 - 300 seconds to 15 -
|
||||
|
||||
public void ModTabDidClose()
|
||||
{
|
||||
logger.Information("Nighttime...");
|
||||
logger.Debug("Nighttime...");
|
||||
this.moddingContext.SaveSettingsData(this.modDefinition.Id, settings ?? new());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user