mirror of
https://github.com/rmroc451/TweaksAndThings.git
synced 2025-12-17 01:39:38 -06:00
Compare commits
23 Commits
v0.1.8
...
experiment
| Author | SHA1 | Date | |
|---|---|---|---|
| bce1d8bd58 | |||
| c25271ee2d | |||
| 80f0847587 | |||
| 7552422b6e | |||
| 58dc7efac0 | |||
| 7ebd14db2a | |||
| ca0e78b971 | |||
| 9f210b0b8a | |||
| 840f35cf62 | |||
| 786db49b68 | |||
| 108900b026 | |||
| 9e8c38e6f4 | |||
| 89f2490f14 | |||
| fbd08b007c | |||
| 27d3432cbf | |||
| cf1d5e32e5 | |||
| 92317b29b2 | |||
| 1f48bf04aa | |||
| 5774c7f04c | |||
| 5eed492b47 | |||
| d4d18d8c92 | |||
| d7e35828b8 | |||
| 0b444d6364 |
7
Assembly.version
Normal file
7
Assembly.version
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MajorVersion>1</MajorVersion>
|
||||||
|
<MinorVersion>2</MinorVersion>
|
||||||
|
<PatchVersion>6</PatchVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<Import Project="Paths.user" Condition="Exists('Paths.user')" />
|
<Import Project="Paths.user" Condition="Exists('Paths.user')" />
|
||||||
|
<Import Project="Assembly.version" Condition="Exists('Assembly.version')" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net48</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
|
|||||||
@@ -2,17 +2,18 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- Try to find the directory on our own -->
|
<!-- Try to find the directory on our own -->
|
||||||
<GameManagedDir Condition="'$(GameManagedDir)' == ''">$([System.IO.Directory]::GetDirectories(`$(GameDir)`, `*_Data`)[0])\Managed</GameManagedDir>
|
<GameManagedDir Condition="'$(GameManagedDir)' == ''">$([System.IO.Directory]::GetDirectories(`$(GameDir)`, `*_Data`)[0])\Managed</GameManagedDir>
|
||||||
|
|
||||||
<!-- Copy the mod to the game directory -->
|
<!-- Copy the mod to the game directory -->
|
||||||
<GameModDir Condition="'$(GameModDir)' == ''">$(GameDir)/Mods/$(AssemblyName)</GameModDir>
|
<GameModDir Condition="'$(GameModDir)' == ''">$(GameDir)/Mods/$(AssemblyName)</GameModDir>
|
||||||
<OutDir Condition="'$(Configuration)' == 'Debug'">$(GameModDir)/</OutDir>
|
<OutDir Condition="'$(Configuration)' == 'Debug'">$(GameModDir)/</OutDir>
|
||||||
|
<VersionTimestamp>$([System.DateTime]::UtcNow.ToString(`o`))</VersionTimestamp>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Replace the default version if something was set for it -->
|
<!-- Replace the default version if something was set for it -->
|
||||||
<PropertyGroup Condition="'$(AssemblyVersion)' == '' OR '$(MajorVersion)' != '' OR '$(MinorVersion)' != ''">
|
<PropertyGroup Condition="'$(AssemblyVersion)' == '' OR '$(MajorVersion)' != '' OR '$(MinorVersion)' != ''">
|
||||||
<MajorVersion Condition="'$(MajorVersion)' == ''">0</MajorVersion>
|
<MajorVersion Condition="'$(MajorVersion)' == ''">1</MajorVersion>
|
||||||
<MinorVersion Condition="'$(MinorVersion)' == ''">1</MinorVersion>
|
<MinorVersion Condition="'$(MinorVersion)' == ''">1</MinorVersion>
|
||||||
<PatchVersion Condition="'$(PatchVersion)' == ''">8</PatchVersion>
|
<PatchVersion Condition="'$(PatchVersion)' == ''">1</PatchVersion>
|
||||||
<AssemblyVersion>$(MajorVersion).$(MinorVersion).$(PatchVersion)</AssemblyVersion>
|
<AssemblyVersion>$(MajorVersion).$(MinorVersion).$(PatchVersion)</AssemblyVersion>
|
||||||
<FileVersion>$(AssemblyVersion)</FileVersion>
|
<FileVersion>$(AssemblyVersion)</FileVersion>
|
||||||
<ProductVersion>$(AssemblyVersion)</ProductVersion>
|
<ProductVersion>$(AssemblyVersion)</ProductVersion>
|
||||||
@@ -30,7 +31,7 @@
|
|||||||
<!-- Publish the mod as a neat zip file -->
|
<!-- Publish the mod as a neat zip file -->
|
||||||
<Target Name="PrepareForPublishing" AfterTargets="AfterBuild" Condition="'$(Configuration)' == 'Release'">
|
<Target Name="PrepareForPublishing" AfterTargets="AfterBuild" Condition="'$(Configuration)' == 'Release'">
|
||||||
<!-- Replace $(AssemblyVersion) with the actual version -->
|
<!-- Replace $(AssemblyVersion) with the actual version -->
|
||||||
<Exec Command="powershell -Command "(Get-Content '$(OutputPath)Definition.json') -replace '\$\(AssemblyVersion\)', '$(AssemblyVersion)' | Set-Content '$(OutputPath)Definition.json'"" />
|
<Exec Command="powershell -Command "(Get-Content '$(OutputPath)Definition.json') -replace '\$\(AssemblyVersion\)', '$(AssemblyVersion)_$(VersionTimestamp)' | Set-Content '$(OutputPath)Definition.json'"" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ModsDirectory>$(OutputPath)/Mods</ModsDirectory>
|
<ModsDirectory>$(OutputPath)/Mods</ModsDirectory>
|
||||||
@@ -38,20 +39,20 @@
|
|||||||
|
|
||||||
<!-- Folder we'll put the published zips into -->
|
<!-- Folder we'll put the published zips into -->
|
||||||
<PublishPath>../bin</PublishPath>
|
<PublishPath>../bin</PublishPath>
|
||||||
<ZipName>$(PublishPath)/$(AssemblyName)_$(AssemblyVersion).zip</ZipName>
|
<ZipName>$(PublishPath)/$(AssemblyName)_$(AssemblyVersion)_Experimental.zip</ZipName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Assure the output path exists -->
|
<!-- Assure the output path exists -->
|
||||||
<MakeDir Directories="$(PublishPath)" />
|
<MakeDir Directories="$(PublishPath)" />
|
||||||
|
|
||||||
<!-- Remove the old Mods directory, and Zips file if any is lying around -->
|
<!-- Remove the old Mods directory, and Zips file if any is lying around -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<OldZips Include="$(PublishPath)/$(AssemblyName)_*.zip" />
|
<OldZips Include="$(PublishPath)/$(AssemblyName)_*.zip" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<RemoveDir Directories="$(ModsDirectory)" ContinueOnError="true" />
|
<RemoveDir Directories="$(ModsDirectory)" ContinueOnError="true" />
|
||||||
<Delete Files="@(OldZips)" />
|
<Delete Files="@(OldZips)" />
|
||||||
|
|
||||||
<!-- Create the Mods directory again -->
|
<!-- Create the Mods directory again -->
|
||||||
<MakeDir Directories="$(ModDirectory)" />
|
<MakeDir Directories="$(ModDirectory)" />
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@
|
|||||||
|
|
||||||
<!-- Zip it up -->
|
<!-- Zip it up -->
|
||||||
<Exec Command="powershell -Command "Compress-Archive -Path '$(ModsDirectory)' -Destination '$(ZipName)'"" />
|
<Exec Command="powershell -Command "Compress-Archive -Path '$(ModsDirectory)' -Destination '$(ZipName)'"" />
|
||||||
|
|
||||||
<!-- Move them to the game directory -->
|
<!-- Move them to the game directory -->
|
||||||
<Copy SourceFiles="@(OutputFiles)" DestinationFolder="$(GameModDir)" />
|
<Copy SourceFiles="@(OutputFiles)" DestinationFolder="$(GameModDir)" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|||||||
6
Paths.user.example
Normal file
6
Paths.user.example
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Directory that the game (Railroader.exe) is in -->
|
||||||
|
<GameDir></GameDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
|||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{452A23A6-81C8-49C6-A7EE-95FD9377F896}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{452A23A6-81C8-49C6-A7EE-95FD9377F896}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
.gitignore = .gitignore
|
.gitignore = .gitignore
|
||||||
|
Assembly.version = Assembly.version
|
||||||
Directory.Build.props = Directory.Build.props
|
Directory.Build.props = Directory.Build.props
|
||||||
Directory.Build.targets = Directory.Build.targets
|
Directory.Build.targets = Directory.Build.targets
|
||||||
Paths.user = Paths.user
|
Paths.user = Paths.user
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using Game.State;
|
using Game.State;
|
||||||
using Helpers;
|
using Helpers;
|
||||||
using Model.OpsNew;
|
using Model.Ops;
|
||||||
using Network;
|
using Network;
|
||||||
using RMROC451.TweaksAndThings.Extensions;
|
using RMROC451.TweaksAndThings.Extensions;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -5,10 +5,17 @@
|
|||||||
"version": "$(AssemblyVersion)",
|
"version": "$(AssemblyVersion)",
|
||||||
"requires": [
|
"requires": [
|
||||||
{
|
{
|
||||||
"id": "railloader",
|
"id": "railroader",
|
||||||
"notBefore": "1.8.1"
|
"notBefore": "2024.6"
|
||||||
},
|
},
|
||||||
"Zamu.StrangeCustoms"
|
{
|
||||||
|
"id": "railloader",
|
||||||
|
"notBefore": "1.9.6.14"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "Zamu.StrangeCustoms",
|
||||||
|
"notBefore": "1.10.25017.313"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"assemblies": [ "RMROC451.TweaksAndThings" ],
|
"assemblies": [ "RMROC451.TweaksAndThings" ],
|
||||||
"mixintos": {
|
"mixintos": {
|
||||||
|
|||||||
@@ -6,51 +6,60 @@ 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)
|
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, foundCaboose, _log))
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
}
|
}
|
||||||
oiler._reverse = originIndex > oiler._cars.Count - originIndex;
|
oiler._reverse = originIndex > oiler._cars.Count - originIndex;
|
||||||
_log.Information(
|
_log.Information(
|
||||||
"AutoOiler {name} starting, rev = {reverse}, caboose halving adjustment = {hasCaboose}, oil limit = {limit}",
|
"AutoOiler {name} starting, rev = {reverse}, caboose required = {req}, caboose halving adjustment = {hasCaboose}, oil limit = {limit}",
|
||||||
oiler.name,
|
oiler.name,
|
||||||
oiler._reverse,
|
oiler._reverse,
|
||||||
hasCaboose,
|
cabooseRequired,
|
||||||
hasCaboose.CabooseAutoOilerLimit()
|
foundCaboose,
|
||||||
|
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);
|
||||||
@@ -63,31 +72,47 @@ namespace RMROC451.TweaksAndThings.Extensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerator MrocAutoHotboxSpotterLoop(this AutoHotboxSpotter spotter, Serilog.ILogger _log)
|
public static IEnumerator MrocAutoHotboxSpotterLoop(this AutoHotboxSpotter spotter, Serilog.ILogger _log, bool cabooseRequired)
|
||||||
{
|
{
|
||||||
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}", spotter.name, hasCaboose, spotter.HasCars);
|
_log.Information("AutoHotboxSpotter {name}: Hotbox Spotter Running, Found Caboose => {hasCaboose}; Has Cars {hasCars}; Requires Caboose {requiresCaboose}",
|
||||||
|
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;
|
||||||
|
}
|
||||||
spotter.CheckForHotbox();
|
spotter.CheckForHotbox();
|
||||||
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}", spotter.name, numOrig, num);
|
_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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool CabooseRequirementChecker(string name, bool cabooseRequired, Model.Car? foundCaboose, Serilog.ILogger _log)
|
||||||
|
{
|
||||||
|
bool error = cabooseRequired && foundCaboose == null;
|
||||||
|
if (error) {
|
||||||
|
_log.Debug("{name}: Couldn't find required caboose!", name);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
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.Ops;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -12,10 +14,14 @@ namespace RMROC451.TweaksAndThings.Extensions;
|
|||||||
|
|
||||||
public static class Car_Extensions
|
public static class Car_Extensions
|
||||||
{
|
{
|
||||||
|
private static bool EndGearIssue(this Car car, Car.LogicalEnd end) =>
|
||||||
|
(!car[end].IsCoupled && car[end].IsAnglecockOpen) ||
|
||||||
|
(car[end].IsCoupled && !car[end].IsAirConnectedAndOpen);
|
||||||
|
|
||||||
public static bool EndAirSystemIssue(this Car car)
|
public static bool EndAirSystemIssue(this Car car)
|
||||||
{
|
{
|
||||||
bool AEndAirSystemIssue = car[Car.LogicalEnd.A].IsCoupled && !car[Car.LogicalEnd.A].IsAirConnectedAndOpen;
|
bool AEndAirSystemIssue = car.EndGearIssue(Car.LogicalEnd.A);
|
||||||
bool BEndAirSystemIssue = car[Car.LogicalEnd.B].IsCoupled && !car[Car.LogicalEnd.B].IsAirConnectedAndOpen;
|
bool BEndAirSystemIssue = car.EndGearIssue(Car.LogicalEnd.B);
|
||||||
bool EndAirSystemIssue = AEndAirSystemIssue || BEndAirSystemIssue;
|
bool EndAirSystemIssue = AEndAirSystemIssue || BEndAirSystemIssue;
|
||||||
return EndAirSystemIssue;
|
return EndAirSystemIssue;
|
||||||
}
|
}
|
||||||
@@ -56,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)
|
||||||
{
|
{
|
||||||
@@ -101,21 +109,28 @@ public static class Car_Extensions
|
|||||||
{
|
{
|
||||||
Vector3 position = car.GetMotionSnapshot().Position;
|
Vector3 position = car.GetMotionSnapshot().Position;
|
||||||
Vector3 center = WorldTransformer.WorldToGame(position);
|
Vector3 center = WorldTransformer.WorldToGame(position);
|
||||||
Rect rect = new Rect(new Vector2(center.x - 30f, center.z - 30f), Vector2.one * 30f * 2f);
|
var cars = tc.CarIdsInRadius(center, 60f);
|
||||||
var cars = tc.CarIdsInRect(rect);
|
|
||||||
Log.Information($"{nameof(HuntingForCabeeseNearCar)} => {cars.Count()}");
|
Log.Information($"{nameof(HuntingForCabeeseNearCar)} => {cars.Count()}");
|
||||||
List<(string carId, float distance)> source =
|
List<(string carId, float distance)> source =
|
||||||
cars
|
cars
|
||||||
.Select(carId =>
|
.Select(carId =>
|
||||||
|
{
|
||||||
|
Car car = tc.CarForId(carId);
|
||||||
|
if (car == null || !car.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready))
|
||||||
{
|
{
|
||||||
Car car = tc.CarForId(carId);
|
return (carId: carId, distance: 1000f);
|
||||||
if (car == null || !car.CabooseWithSufficientCrewHours(timeNeeded, carIdsCheckedAlready))
|
}
|
||||||
{
|
Vector3 a = WorldTransformer.WorldToGame(car.GetMotionSnapshot().Position);
|
||||||
return (carId: carId, distance: 1000f);
|
return (carId: carId, distance: Vector3.Distance(a, center));
|
||||||
}
|
}).ToList();
|
||||||
Vector3 a = WorldTransformer.WorldToGame(car.GetMotionSnapshot().Position);
|
|
||||||
return (carId: carId, distance: Vector3.Distance(a, center));
|
|
||||||
}).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)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ internal class AutoHotboxSpotter_SpotterLoop_Patch
|
|||||||
{
|
{
|
||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
if (!tweaksAndThings.IsEnabled) return true;
|
if (!tweaksAndThings.IsEnabled) return true;
|
||||||
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
|
bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment();
|
||||||
|
bool cabooseRequired = tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter();
|
||||||
|
|
||||||
if (buttonsHaveCost) __result = __instance.MrocAutoHotboxSpotterLoop(_log);
|
if (buttonsHaveCost) __result = __instance.MrocAutoHotboxSpotterLoop(_log, cabooseRequired);
|
||||||
return !buttonsHaveCost; //only hit this if !buttonsHaveCost, since Loop is a coroutine
|
return !buttonsHaveCost; //only hit this if !buttonsHaveCost, since Loop is a coroutine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ internal class AutoOiler_Loop_Patch
|
|||||||
{
|
{
|
||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
if (!tweaksAndThings.IsEnabled) return true;
|
if (!tweaksAndThings.IsEnabled) return true;
|
||||||
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
|
bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment();
|
||||||
|
bool cabooseRequired = tweaksAndThings.RequireConsistCabooseForOilerAndHotboxSpotter();
|
||||||
|
|
||||||
if (buttonsHaveCost)__result = __instance.MrocAutoOilerLoop(_log);
|
if (buttonsHaveCost) __result = __instance.MrocAutoOilerLoop(_log, cabooseRequired);
|
||||||
return !buttonsHaveCost; //only hit this if !buttonsHaveCost, since Loop is a coroutine
|
return !buttonsHaveCost; //only hit this if !buttonsHaveCost, since Loop is a coroutine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using Game.Messages;
|
using Core;
|
||||||
|
using Game.Messages;
|
||||||
using Game.State;
|
using Game.State;
|
||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using KeyValue.Runtime;
|
using KeyValue.Runtime;
|
||||||
using Model;
|
using Model;
|
||||||
using Model.OpsNew;
|
|
||||||
using Network;
|
using Network;
|
||||||
using Railloader;
|
using Railloader;
|
||||||
using RMROC451.TweaksAndThings.Enums;
|
using RMROC451.TweaksAndThings.Enums;
|
||||||
@@ -13,6 +13,7 @@ using Serilog;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using UI;
|
||||||
using UI.Builder;
|
using UI.Builder;
|
||||||
using UI.CarInspector;
|
using UI.CarInspector;
|
||||||
using UI.ContextMenu;
|
using UI.ContextMenu;
|
||||||
@@ -40,36 +41,61 @@ internal class CarInspector_PopulateCarPanel_Patch
|
|||||||
|
|
||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
if (!tweaksAndThings.IsEnabled) return true;
|
if (!tweaksAndThings.IsEnabled) return true;
|
||||||
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
|
bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment();
|
||||||
|
|
||||||
var consist = __instance._car.EnumerateCoupled(LogicalEnd.A);
|
var consist = __instance._car.EnumerateCoupled();
|
||||||
builder = AddCarConsistRebuildObservers(builder, consist);
|
|
||||||
|
|
||||||
builder.HStack(delegate (UIPanelBuilder hstack)
|
builder.HStack(delegate (UIPanelBuilder hstack)
|
||||||
{
|
{
|
||||||
|
hstack = AddCarConsistRebuildObservers(hstack, consist);
|
||||||
var buttonName = $"{(consist.Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} {TextSprites.HandbrakeWheel}";
|
var buttonName = $"{(consist.Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} {TextSprites.HandbrakeWheel}";
|
||||||
hstack.AddButtonCompact(buttonName, delegate {
|
hstack.AddButtonCompact(buttonName, delegate
|
||||||
|
{
|
||||||
MrocConsistHelper(__instance._car, MrocHelperType.Handbrake, buttonsHaveCost);
|
MrocConsistHelper(__instance._car, MrocHelperType.Handbrake, buttonsHaveCost);
|
||||||
hstack.Rebuild();
|
hstack.Rebuild();
|
||||||
}).Tooltip(buttonName, $"Iterates over cars in this consist and {(consist.Any(c => c.HandbrakeApplied()) ? "releases" : "sets")} {TextSprites.HandbrakeWheel}.");
|
}).Tooltip(buttonName, $"Iterates over cars in this consist and {(consist.Any(c => c.HandbrakeApplied()) ? "releases" : "sets")} {TextSprites.HandbrakeWheel}.");
|
||||||
|
|
||||||
if (consist.Any(c => c.EndAirSystemIssue()))
|
if (consist.Any(c => c.EndAirSystemIssue()))
|
||||||
{
|
{
|
||||||
hstack.AddButtonCompact("Connect Air", delegate {
|
hstack.AddButtonCompact("Connect Air", delegate
|
||||||
|
{
|
||||||
MrocConsistHelper(__instance._car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
MrocConsistHelper(__instance._car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
||||||
hstack.Rebuild();
|
hstack.Rebuild();
|
||||||
}).Tooltip("Connect Consist Air", "Iterates over each car in this consist and connects gladhands and opens anglecocks.");
|
}).Tooltip("Connect Consist Air", "Iterates over each car in this consist and connects gladhands and opens anglecocks.");
|
||||||
}
|
}
|
||||||
|
|
||||||
hstack.AddButtonCompact("Bleed Consist", delegate {
|
hstack.AddButtonCompact("Bleed Consist", delegate
|
||||||
|
{
|
||||||
MrocConsistHelper(__instance._car, MrocHelperType.BleedAirSystem, buttonsHaveCost);
|
MrocConsistHelper(__instance._car, MrocHelperType.BleedAirSystem, buttonsHaveCost);
|
||||||
hstack.Rebuild();
|
hstack.Rebuild();
|
||||||
}).Tooltip("Bleed Air Lines", "Iterates over each car in this consist and bleeds the air out of the lines.");
|
}).Tooltip("Bleed Air Lines", "Iterates over each car in this consist and bleeds the air out of the lines.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CabooseUiEnhancer(__instance, builder, consist, tweaksAndThings);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void CabooseUiEnhancer(CarInspector __instance, UIPanelBuilder builder, IEnumerable<Car> consist, TweaksAndThingsPlugin plugin)
|
||||||
|
{
|
||||||
|
if (plugin.CabooseNonMotiveAllowedSetting(__instance._car))
|
||||||
|
{
|
||||||
|
builder.HStack(delegate (UIPanelBuilder hstack)
|
||||||
|
{
|
||||||
|
hstack.AddField("Consist Info", hstack.HStack(delegate (UIPanelBuilder field)
|
||||||
|
{
|
||||||
|
int consistLength = consist.Count();
|
||||||
|
int tonnage = LocomotiveControlsHoverArea.CalculateTonnage(consist);
|
||||||
|
int lengthInMeters = UnityEngine.Mathf.CeilToInt(LocomotiveControlsHoverArea.CalculateLengthInMeters(consist.ToList()) * 3.28084f);
|
||||||
|
var newSubTitle = () => string.Format("{0}, {1:N0}T, {2:N0}ft, {3:0.0} mph", consistLength.Pluralize("car"), tonnage, lengthInMeters, __instance._car.VelocityMphAbs);
|
||||||
|
|
||||||
|
field.AddLabel(() => newSubTitle(), UIPanelBuilder.Frequency.Fast)
|
||||||
|
.Tooltip("Consist Info", "Reflects info about consist.").FlexibleWidth();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static UIPanelBuilder AddCarConsistRebuildObservers(UIPanelBuilder builder, IEnumerable<Model.Car> consist)
|
private static UIPanelBuilder AddCarConsistRebuildObservers(UIPanelBuilder builder, IEnumerable<Model.Car> consist)
|
||||||
{
|
{
|
||||||
TagController tagController = UnityEngine.Object.FindFirstObjectByType<TagController>();
|
TagController tagController = UnityEngine.Object.FindFirstObjectByType<TagController>();
|
||||||
@@ -97,10 +123,10 @@ internal class CarInspector_PopulateCarPanel_Patch
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
builder.Rebuild();
|
builder.Rebuild();
|
||||||
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)
|
||||||
{
|
{
|
||||||
_log.ForContext("car", car).Warning(ex, $"{nameof(AddObserver)} {car} Exception logged for {key}");
|
_log.ForContext("car", car).Warning(ex, $"{nameof(AddObserver)} {car} Exception logged for {key}");
|
||||||
}
|
}
|
||||||
@@ -114,7 +140,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
|||||||
|
|
||||||
//var dh = new DownloadHandlerAudioClip($"file://{cacheFileName}", AudioType.MPEG);
|
//var dh = new DownloadHandlerAudioClip($"file://{cacheFileName}", AudioType.MPEG);
|
||||||
//dh.compressed = true; // This
|
//dh.compressed = true; // This
|
||||||
|
|
||||||
//using (UnityWebRequest wr = new UnityWebRequest($"file://{cacheFileName}", "GET", dh, null)) {
|
//using (UnityWebRequest wr = new UnityWebRequest($"file://{cacheFileName}", "GET", dh, null)) {
|
||||||
// yield return wr.SendWebRequest();
|
// yield return wr.SendWebRequest();
|
||||||
// if (wr.responseCode == 200) {
|
// if (wr.responseCode == 200) {
|
||||||
@@ -125,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.EnumerateCoupled(LogicalEnd.A);
|
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);
|
||||||
@@ -182,7 +208,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
|||||||
float originalTimeCost = consist.CalculateCostForAutoEngineerEndGearSetting();
|
float originalTimeCost = consist.CalculateCostForAutoEngineerEndGearSetting();
|
||||||
float timeCost = originalTimeCost;
|
float timeCost = originalTimeCost;
|
||||||
float crewCost = timeCost / 3600; //hours of time deducted from caboose.
|
float crewCost = timeCost / 3600; //hours of time deducted from caboose.
|
||||||
var tsString = crewCost.FormatCrewHours(IndustryComponent_Service_Patch.CrewHoursLoad().description);
|
var tsString = crewCost.FormatCrewHours(OpsController_AnnounceCoalescedPayments_Patch.CrewHoursLoad().description);
|
||||||
Car? cabooseWithAvailCrew = NearbyCabooseWithAvailableCrew(car, crewCost, buttonsHaveCost);
|
Car? cabooseWithAvailCrew = NearbyCabooseWithAvailableCrew(car, crewCost, buttonsHaveCost);
|
||||||
if (cabooseWithAvailCrew == null) timeCost *= 1.5f;
|
if (cabooseWithAvailCrew == null) timeCost *= 1.5f;
|
||||||
var cabooseFoundDisplay = cabooseWithAvailCrew?.DisplayName ?? "No caboose";
|
var cabooseFoundDisplay = cabooseWithAvailCrew?.DisplayName ?? "No caboose";
|
||||||
@@ -194,7 +220,7 @@ internal class CarInspector_PopulateCarPanel_Patch
|
|||||||
|
|
||||||
StateManager_OnDayDidChange_Patch.UnbilledAutoBrakeCrewRunDuration += timeCost;
|
StateManager_OnDayDidChange_Patch.UnbilledAutoBrakeCrewRunDuration += timeCost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Car? NearbyCabooseWithAvailableCrew(Car car, float timeNeeded, bool decrement = false)
|
public static Car? NearbyCabooseWithAvailableCrew(Car car, float timeNeeded, bool decrement = false)
|
||||||
{
|
{
|
||||||
@@ -206,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.EnumerateCoupled(LogicalEnd.A);
|
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));
|
||||||
|
|||||||
52
TweaksAndThings/Patches/CarPickable_Activate_Patch.cs
Normal file
52
TweaksAndThings/Patches/CarPickable_Activate_Patch.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ using RollingStock;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UI;
|
using UI;
|
||||||
using UI.ContextMenu;
|
using UI.ContextMenu;
|
||||||
using static Model.Car;
|
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
@@ -21,23 +20,22 @@ internal class CarPickable_HandleShowContextMenu_Patch
|
|||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
if (!tweaksAndThings.IsEnabled) return;
|
if (!tweaksAndThings.IsEnabled) return;
|
||||||
|
|
||||||
bool buttonsHaveCost = tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false;
|
bool buttonsHaveCost = tweaksAndThings.EndGearHelpersRequirePayment();
|
||||||
ContextMenu shared = ContextMenu.Shared;
|
ContextMenu shared = ContextMenu.Shared;
|
||||||
var consist = car.EnumerateCoupled(LogicalEnd.A);
|
shared.AddButton(ContextMenuQuadrant.Unused1, $"{(car.EnumerateCoupled().Any(c => c.HandbrakeApplied()) ? "Release " : "Set ")} Consist", SpriteName.Handbrake, delegate
|
||||||
shared.AddButton(ContextMenuQuadrant.Unused2, $"{(consist.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 (consist.Any(c => c.EndAirSystemIssue()))
|
if (car.EnumerateCoupled().Any(c => c.EndAirSystemIssue()))
|
||||||
{
|
{
|
||||||
shared.AddButton(ContextMenuQuadrant.Unused2, $"Air Up Consist", SpriteName.Select, delegate
|
shared.AddButton(ContextMenuQuadrant.Unused1, $"Air Up Consist", SpriteName.Select, delegate
|
||||||
{
|
{
|
||||||
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
CarInspector_PopulateCarPanel_Patch.MrocConsistHelper(car, MrocHelperType.GladhandAndAnglecock, buttonsHaveCost);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (consist.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
|
||||||
{
|
{
|
||||||
@@ -45,6 +43,10 @@ internal class CarPickable_HandleShowContextMenu_Patch
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared.AddButton(ContextMenuQuadrant.General, $"Follow", SpriteName.Inspect, delegate
|
||||||
|
{
|
||||||
|
CameraSelector.shared.FollowCar(car);
|
||||||
|
});
|
||||||
shared.BuildItemAngles();
|
shared.BuildItemAngles();
|
||||||
shared.StartCoroutine(shared.AnimateButtonsShown());
|
shared.StartCoroutine(shared.AnimateButtonsShown());
|
||||||
}
|
}
|
||||||
|
|||||||
25
TweaksAndThings/Patches/ContextMenu_PositionForItem_Patch.cs
Normal file
25
TweaksAndThings/Patches/ContextMenu_PositionForItem_Patch.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Railloader;
|
||||||
|
using System;
|
||||||
|
using UI.ContextMenu;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(UI.ContextMenu.ContextMenu))]
|
||||||
|
//ContextMenuQuadrant quadrant, int index, float normalizedRadius = 1f
|
||||||
|
[HarmonyPatch(nameof(UI.ContextMenu.ContextMenu.PositionForItem), typeof(ContextMenuQuadrant), typeof(int), typeof(float))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class ContextMenu_PositionForItem_Patch
|
||||||
|
{
|
||||||
|
static void Postfix(UI.ContextMenu.ContextMenu __instance, ref Vector2 __result, ContextMenuQuadrant quadrant, int index, float normalizedRadius = 1f)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!tweaksAndThings.IsEnabled) return;
|
||||||
|
|
||||||
|
float num = __instance._itemAngles[(quadrant, index)] * ((float)Math.PI / 180f);
|
||||||
|
float num2 = __instance.radius * normalizedRadius;
|
||||||
|
__result = new Vector2(1.3f * Mathf.Sin(num) * num2, Mathf.Cos(num) * num2);
|
||||||
|
}
|
||||||
|
}
|
||||||
128
TweaksAndThings/Patches/ContextMenu_Show_Patch.cs
Normal file
128
TweaksAndThings/Patches/ContextMenu_Show_Patch.cs
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Helpers;
|
||||||
|
using Railloader;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UI;
|
||||||
|
using UI.ContextMenu;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(UI.ContextMenu.ContextMenu))]
|
||||||
|
[HarmonyPatch(nameof(UI.ContextMenu.ContextMenu.Show), typeof(string))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class ContextMenu_Show_Patch
|
||||||
|
{
|
||||||
|
static bool Prefix(UI.ContextMenu.ContextMenu __instance, string centerText)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!tweaksAndThings.IsEnabled) return true;
|
||||||
|
|
||||||
|
if (!__instance.GetRootCanvas(out var rootCanvas))
|
||||||
|
{
|
||||||
|
Log.Warning("Couldn't get root canvas");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
__instance.CancelHideCoroutine();
|
||||||
|
if (__instance.contentRectTransform.childCount >= 1) __instance.contentRectTransform.GetChild(0).DestroyAllChildren(); //YOINK DEM CIRCLES!
|
||||||
|
__instance.SetupTemplate(rootCanvas);
|
||||||
|
__instance.centerLabel.text = centerText;
|
||||||
|
Canvas componentInParent = ((Component)__instance.contentRectTransform).GetComponentInParent<Canvas>();
|
||||||
|
Vector3 mousePosition = Input.mousePosition;
|
||||||
|
Vector2 val = componentInParent.ScreenToCanvasPosition(mousePosition).XY();
|
||||||
|
Vector2 renderingDisplaySize = rootCanvas.renderingDisplaySize;
|
||||||
|
float num = __instance.radius + 50f;
|
||||||
|
if (val.x < num)
|
||||||
|
{
|
||||||
|
val.x = num;
|
||||||
|
}
|
||||||
|
if (val.x > renderingDisplaySize.x - num)
|
||||||
|
{
|
||||||
|
val.x = renderingDisplaySize.x - num;
|
||||||
|
}
|
||||||
|
if (val.y < num)
|
||||||
|
{
|
||||||
|
val.y = num;
|
||||||
|
}
|
||||||
|
if (val.y > renderingDisplaySize.y - num)
|
||||||
|
{
|
||||||
|
val.y = renderingDisplaySize.y - num;
|
||||||
|
}
|
||||||
|
__instance.contentRectTransform.anchoredPosition = val;
|
||||||
|
__instance.BuildItemAngles();
|
||||||
|
|
||||||
|
((MonoBehaviour)__instance).StartCoroutine(__instance.AnimateButtonsShown());
|
||||||
|
((Component)__instance.contentRectTransform).gameObject.SetActive(true);
|
||||||
|
UI.ContextMenu.ContextMenu.IsShown = true;
|
||||||
|
__instance._blocker = __instance.CreateBlocker(rootCanvas);
|
||||||
|
GameInput.RegisterEscapeHandler(GameInput.EscapeHandler.Transient, delegate
|
||||||
|
{
|
||||||
|
__instance.Hide();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(UI.ContextMenu.ContextMenu))]
|
||||||
|
[HarmonyPatch(nameof(UI.ContextMenu.ContextMenu.DefaultAngleForItem), typeof(ContextMenuQuadrant), typeof(int), typeof(int))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class ContextMenu_DefaultAngleForItem_Patch
|
||||||
|
{
|
||||||
|
static bool Prefix(UI.ContextMenu.ContextMenu __instance, ref float __result, ContextMenuQuadrant quadrant, int index, int quadrantItemCount)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!tweaksAndThings.IsEnabled) return true;
|
||||||
|
|
||||||
|
|
||||||
|
int num = quadrant switch
|
||||||
|
{
|
||||||
|
ContextMenuQuadrant.General => 0,
|
||||||
|
ContextMenuQuadrant.Unused1 => 90,
|
||||||
|
ContextMenuQuadrant.Brakes => 180,
|
||||||
|
ContextMenuQuadrant.Unused2 => -90,
|
||||||
|
_ => throw new ArgumentOutOfRangeException("quadrant", quadrant, null),
|
||||||
|
};
|
||||||
|
if (quadrantItemCount <= 1)
|
||||||
|
{
|
||||||
|
__result = num;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int num2 = ((quadrantItemCount <= 3) ? 30 : (90 / (quadrantItemCount - 1)));
|
||||||
|
__result = (float)num + -0.5f * (float)((quadrantItemCount - 1) * num2) + (float)(num2 * index);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(UI.ContextMenu.ContextMenu))]
|
||||||
|
[HarmonyPatch(nameof(UI.ContextMenu.ContextMenu.AddButton), typeof(ContextMenuQuadrant), typeof(string), typeof(Sprite), typeof(Action))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class ContextMenu_AddButton_Patch
|
||||||
|
{
|
||||||
|
static bool Prefix(UI.ContextMenu.ContextMenu __instance, ContextMenuQuadrant quadrant, string title, Sprite sprite, Action action)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!tweaksAndThings.IsEnabled) return true;
|
||||||
|
|
||||||
|
|
||||||
|
List<ContextMenuItem> list = __instance._quadrants[(int)quadrant];
|
||||||
|
int index = list.Count;
|
||||||
|
ContextMenuItem contextMenuItem = UnityEngine.Object.Instantiate<ContextMenuItem>(__instance.itemPrefab, (Transform)(object)__instance.contentRectTransform);
|
||||||
|
contextMenuItem.image.sprite = sprite;
|
||||||
|
contextMenuItem.label.text = title;
|
||||||
|
contextMenuItem.OnClick = delegate
|
||||||
|
{
|
||||||
|
action();
|
||||||
|
__instance.Hide((quadrant, index));
|
||||||
|
};
|
||||||
|
((Component)contextMenuItem).gameObject.AddComponent<LayoutElement>().preferredHeight = 30f;
|
||||||
|
list.Add(contextMenuItem);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Model;
|
using Model;
|
||||||
using Model.Definition.Data;
|
using Model.Definition.Data;
|
||||||
using Model.OpsNew;
|
using Model.Ops;
|
||||||
using Railloader;
|
using Railloader;
|
||||||
using RMROC451.TweaksAndThings.Extensions;
|
using RMROC451.TweaksAndThings.Extensions;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|||||||
@@ -1,139 +0,0 @@
|
|||||||
using Game.State;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Model;
|
|
||||||
using Model.Definition.Data;
|
|
||||||
using Model.Ops.Definition;
|
|
||||||
using Model.OpsNew;
|
|
||||||
using Railloader;
|
|
||||||
using RMROC451.TweaksAndThings.Extensions;
|
|
||||||
using Serilog;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(CarExtensions))]
|
|
||||||
[HarmonyPatch(nameof(CarExtensions.LoadString), typeof(CarLoadInfo), typeof(Load))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class CarExtensions_LoadString_Patch
|
|
||||||
{
|
|
||||||
public static bool Prefix(CarLoadInfo info, Load load, ref string __result)
|
|
||||||
{
|
|
||||||
bool output = load.id == IndustryComponent_Service_Patch.CrewHoursLoad().id;
|
|
||||||
if (output) __result = info.Quantity.FormatCrewHours(load.description);
|
|
||||||
|
|
||||||
return !output;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(CarPrototypeLibrary))]
|
|
||||||
[HarmonyPatch(nameof(CarPrototypeLibrary.LoadForId), typeof(string))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class CarPrototypeLibrary_LoadForId_Patch
|
|
||||||
{
|
|
||||||
public static bool Prefix(string loadId, ref Load __result)
|
|
||||||
{
|
|
||||||
Load load = IndustryComponent_Service_Patch.CrewHoursLoad();
|
|
||||||
if (loadId == load.id) __result = load;
|
|
||||||
|
|
||||||
return __result == null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(TeamTrack))]
|
|
||||||
[HarmonyPatch(nameof(TeamTrack.Service), typeof(IIndustryContext))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class TeamTrack_Service_Patch
|
|
||||||
{
|
|
||||||
public static bool Prefix(IndustryComponent __instance, IIndustryContext ctx)
|
|
||||||
{
|
|
||||||
//Log.Information($"{nameof(SimplePassengerStop_Service_Patch)} => {((IndustryContext)ctx)._industry.name}");
|
|
||||||
return IndustryComponent_Service_Patch.Prefix(__instance, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(RepairTrack))]
|
|
||||||
[HarmonyPatch(nameof(RepairTrack.Service), typeof(IIndustryContext))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class RepairTrack_Service_Patch
|
|
||||||
{
|
|
||||||
public static bool Prefix(IndustryComponent __instance, IIndustryContext ctx)
|
|
||||||
{
|
|
||||||
//Log.Information($"{nameof(SimplePassengerStop_Service_Patch)} => {((IndustryContext)ctx)._industry.name}");
|
|
||||||
return IndustryComponent_Service_Patch.Prefix(__instance, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(SimplePassengerStop))]
|
|
||||||
[HarmonyPatch(nameof(SimplePassengerStop.Service), typeof(IIndustryContext))]
|
|
||||||
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
|
||||||
internal class SimplePassengerStop_Service_Patch
|
|
||||||
{
|
|
||||||
public static bool Prefix(IndustryComponent __instance, IIndustryContext ctx)
|
|
||||||
{
|
|
||||||
Log.Information($"{nameof(SimplePassengerStop_Service_Patch)} => {((IndustryContext)ctx)._industry.name}");
|
|
||||||
return IndustryComponent_Service_Patch.Prefix(__instance, ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static class IndustryComponent_Service_Patch
|
|
||||||
{
|
|
||||||
public static Load CrewHoursLoad()
|
|
||||||
{
|
|
||||||
Load load = (Load)ScriptableObject.CreateInstance(typeof(Load));
|
|
||||||
load.name = "crew-hours";
|
|
||||||
load.description = "Crew";
|
|
||||||
load.units = LoadUnits.Quantity;
|
|
||||||
|
|
||||||
return load;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Prefix(IndustryComponent __instance, IIndustryContext ctx)
|
|
||||||
{
|
|
||||||
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
|
||||||
if (!StateManager.IsHost || !tweaksAndThings.IsEnabled || !(tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false)) return true;
|
|
||||||
|
|
||||||
Load load = CrewHoursLoad();
|
|
||||||
|
|
||||||
float rate2 = 24 * 2 * 8;// carLoadRate = 8 crew hours in 30 min loading; (24h * 2 to get half hour chunks * 8 hours to load in those chunks)
|
|
||||||
float num2 = 99999999; //QuantityInStorage for crew-hours (infinite where crew can be shuffling about)
|
|
||||||
float quantityToLoad = Mathf.Min(num2, IndustryComponent.RateToValue(rate2, ctx.DeltaTime));
|
|
||||||
|
|
||||||
var carsAtPosition = ctx.CarsAtPosition();
|
|
||||||
|
|
||||||
var cabeese = from car in carsAtPosition.Where(c => c.CarType == "NE")
|
|
||||||
where car.IsEmptyOrContains(load)
|
|
||||||
orderby car.QuantityOfLoad(load).quantity descending
|
|
||||||
select car;
|
|
||||||
|
|
||||||
foreach (IOpsCar item in cabeese)
|
|
||||||
{
|
|
||||||
TrainController tc = UnityEngine.Object.FindAnyObjectByType<TrainController>();
|
|
||||||
if (tc.TryGetCarForId(item.Id, out Car car))
|
|
||||||
{
|
|
||||||
List<LoadSlot> loadSlots = car.Definition.LoadSlots;
|
|
||||||
float quantity = 0f;
|
|
||||||
float max = 0f;
|
|
||||||
for (int i = 0; i < loadSlots.Count; i++)
|
|
||||||
{
|
|
||||||
LoadSlot loadSlot = loadSlots[i];
|
|
||||||
if (loadSlot.LoadRequirementsMatch(load) && loadSlot.LoadUnits == load.units)
|
|
||||||
{
|
|
||||||
CarLoadInfo? loadInfo = car.GetLoadInfo(i);
|
|
||||||
|
|
||||||
quantity = loadInfo.HasValue ? loadInfo.Value.Quantity : 0f;
|
|
||||||
max = loadSlots[i].MaximumCapacity;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//Log.Information($"{nameof(IndustryComponent_Service_Patch)} {car} => {car.StoppedDuration} => {quantityToLoad} => {quantity}/{max}");
|
|
||||||
if (car.StoppedDuration > 30) item.Load(load, quantityToLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
//todo:crew refresh message?
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
using Game;
|
||||||
|
using Game.State;
|
||||||
|
using HarmonyLib;
|
||||||
|
using Model;
|
||||||
|
using Model.Definition.Data;
|
||||||
|
using Model.Ops.Definition;
|
||||||
|
using Model.Ops;
|
||||||
|
using Network;
|
||||||
|
using Railloader;
|
||||||
|
using RMROC451.TweaksAndThings.Extensions;
|
||||||
|
using RollingStock;
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(CarExtensions))]
|
||||||
|
[HarmonyPatch(nameof(CarExtensions.LoadString), typeof(CarLoadInfo), typeof(Load))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class CarExtensions_LoadString_Patch
|
||||||
|
{
|
||||||
|
public static bool Prefix(CarLoadInfo info, Load load, ref string __result)
|
||||||
|
{
|
||||||
|
bool output = load.id == OpsController_AnnounceCoalescedPayments_Patch.CrewHoursLoad().id;
|
||||||
|
if (output) __result = info.Quantity.FormatCrewHours(load.description);
|
||||||
|
|
||||||
|
return !output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(CarPrototypeLibrary))]
|
||||||
|
[HarmonyPatch(nameof(CarPrototypeLibrary.LoadForId), typeof(string))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class CarPrototypeLibrary_LoadForId_Patch
|
||||||
|
{
|
||||||
|
public static bool Prefix(string loadId, ref Load __result)
|
||||||
|
{
|
||||||
|
Load load = OpsController_AnnounceCoalescedPayments_Patch.CrewHoursLoad();
|
||||||
|
if (loadId == load.id) __result = load;
|
||||||
|
|
||||||
|
return __result == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(OpsController))]
|
||||||
|
[HarmonyPatch(nameof(OpsController.AnnounceCoalescedPayments))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class OpsController_AnnounceCoalescedPayments_Patch
|
||||||
|
{
|
||||||
|
static Dictionary<string, (bool spotted, bool filling)> CrewCarDict = new();
|
||||||
|
|
||||||
|
public static (bool spotted, bool filling) CrewCarStatus(Car car)
|
||||||
|
{
|
||||||
|
bool found = CrewCarDict.TryGetValue(car.id, out (bool spotted, bool filling) val);
|
||||||
|
|
||||||
|
if (!found) CrewCarDict.Add(car.id, (false, false));
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GameDateTime dateTime = TimeWeather.Now;
|
||||||
|
static readonly IEnumerable<Type> refillLocations =
|
||||||
|
new List<Type>() {
|
||||||
|
typeof(PassengerStop),
|
||||||
|
typeof(SimplePassengerStop),
|
||||||
|
typeof(TeamTrack),
|
||||||
|
typeof(RepairTrack)
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Load CrewHoursLoad()
|
||||||
|
{
|
||||||
|
Load load = (Load)ScriptableObject.CreateInstance(typeof(Load));
|
||||||
|
load.name = "crew-hours";
|
||||||
|
load.description = "Crew";
|
||||||
|
load.units = LoadUnits.Quantity;
|
||||||
|
|
||||||
|
return load;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CarLoadCrewHelper(Car car, float deltaTime)
|
||||||
|
{
|
||||||
|
float rate2 = 24 * 2 * 8;// carLoadRate = 8 crew hours in 30 min loading; (24h * 2 to get half hour chunks * 8 hours to load in those chunks)
|
||||||
|
float num2 = 99999999; //QuantityInStorage for crew-hours (infinite where crew can be shuffling about)
|
||||||
|
float quantityToLoad = Mathf.Min(num2, IndustryComponent.RateToValue(rate2, deltaTime));
|
||||||
|
|
||||||
|
if (car.IsCaboose() && !CrewCarStatus(car).spotted)
|
||||||
|
{
|
||||||
|
CrewCarDict[car.id] = (true, CrewCarDict[car.id].filling);
|
||||||
|
}
|
||||||
|
if (car.IsCabooseAndStoppedForLoadRefresh())
|
||||||
|
{
|
||||||
|
if (!CrewCarDict[car.id].filling) Multiplayer.Broadcast($"{Hyperlink.To(car)}: \"Topping off caboose crew.\"");
|
||||||
|
CrewCarDict[car.id] = (CrewCarDict[car.id].spotted, true);
|
||||||
|
var data = car.QuantityCapacityOfLoad(CrewHoursLoad());
|
||||||
|
if ((data.quantity + quantityToLoad > data.capacity) && data.quantity < data.capacity)
|
||||||
|
{
|
||||||
|
Multiplayer.Broadcast($"{Hyperlink.To(car)}: \"Caboose crew topped off.\"");
|
||||||
|
CrewCarDict[car.id] = (CrewCarDict[car.id].spotted, false);
|
||||||
|
}
|
||||||
|
new OpsCarAdapter(car, OpsController.Shared).Load(CrewHoursLoad(), quantityToLoad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool Prefix(IndustryComponent __instance)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!StateManager.IsHost || !tweaksAndThings.IsEnabled || !(tweaksAndThings?.settings?.EndGearHelpersRequirePayment ?? false)) return true;
|
||||||
|
|
||||||
|
|
||||||
|
TrainController tc = UnityEngine.Object.FindAnyObjectByType<TrainController>();
|
||||||
|
try {
|
||||||
|
|
||||||
|
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)}");
|
||||||
|
|
||||||
|
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}") ?? [])}");
|
||||||
|
|
||||||
|
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}");
|
||||||
|
CarLoadCrewHelper(caboose.c2, deltaTime);
|
||||||
|
}
|
||||||
|
dateTime = TimeWeather.Now;
|
||||||
|
} catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex, "error with announce caboose helper");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
using HarmonyLib;
|
using HarmonyLib;
|
||||||
using Model;
|
using Model;
|
||||||
using Model.OpsNew;
|
using Model.Ops;
|
||||||
using Railloader;
|
using Railloader;
|
||||||
using RMROC451.TweaksAndThings.Extensions;
|
using RMROC451.TweaksAndThings.Extensions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using UI.Tags;
|
using UI.Tags;
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings.Patches;
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
@@ -32,13 +34,17 @@ internal class TagController_UpdateTag_Patch
|
|||||||
private static void ProceedWithPostFix(Car car, TagCallout tagCallout)
|
private static void ProceedWithPostFix(Car car, TagCallout tagCallout)
|
||||||
{
|
{
|
||||||
tagCallout.callout.Title = string.Format(tagTitleFormat, "{0}", car.DisplayName);
|
tagCallout.callout.Title = string.Format(tagTitleFormat, "{0}", car.DisplayName);
|
||||||
|
List<string> tags = new();
|
||||||
|
|
||||||
|
if (OpsController_AnnounceCoalescedPayments_Patch.CrewCarStatus(car).spotted) tags.Add("+");
|
||||||
|
if (car.HasHotbox) tags.Add(TextSprites.Hotbox);
|
||||||
|
if (car.EndAirSystemIssue()) tags.Add(TextSprites.CycleWaybills);
|
||||||
|
if (car.HandbrakeApplied()) tags.Add(TextSprites.HandbrakeWheel);
|
||||||
|
|
||||||
tagCallout.callout.Title =
|
tagCallout.callout.Title =
|
||||||
(car.CarAndEndGearIssue(), car.EndAirSystemIssue(), car.HandbrakeApplied()) switch
|
tags.Any() switch
|
||||||
{
|
{
|
||||||
(true, _, _) => $"{tagCallout.callout.Title}{tagTitleAndIconDelimeter}{TextSprites.CycleWaybills}{TextSprites.HandbrakeWheel}".Replace("{0}", "2"),
|
true => $"{tagCallout.callout.Title}{tagTitleAndIconDelimeter}{string.Join("", tags)}".Replace("{0}", tags.Count().ToString()),
|
||||||
(_, true, _) => $"{tagCallout.callout.Title}{tagTitleAndIconDelimeter}{TextSprites.CycleWaybills}".Replace("{0}", "1"),
|
|
||||||
(_, _, true) => $"{tagCallout.callout.Title}{tagTitleAndIconDelimeter}{TextSprites.HandbrakeWheel}".Replace("{0}", "1"),
|
|
||||||
_ => car.DisplayName
|
_ => car.DisplayName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
20
TweaksAndThings/Patches/WedgeImage_OnPopulateMesh.cs
Normal file
20
TweaksAndThings/Patches/WedgeImage_OnPopulateMesh.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using Railloader;
|
||||||
|
using UI.ContextMenu;
|
||||||
|
using UnityEngine.UI;
|
||||||
|
|
||||||
|
namespace RMROC451.TweaksAndThings.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(WedgeImage))]
|
||||||
|
[HarmonyPatch(nameof(WedgeImage.OnPopulateMesh), typeof(VertexHelper))]
|
||||||
|
[HarmonyPatchCategory("RMROC451TweaksAndThings")]
|
||||||
|
internal class WedgeImage_OnPopulateMesh_Patch
|
||||||
|
{
|
||||||
|
private static void Postfix(VertexHelper vh)
|
||||||
|
{
|
||||||
|
TweaksAndThingsPlugin tweaksAndThings = SingletonPluginBase<TweaksAndThingsPlugin>.Shared;
|
||||||
|
if (!tweaksAndThings.IsEnabled) return;
|
||||||
|
|
||||||
|
vh.Clear(); //clear the image backgrounds for now.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using RMROC451.TweaksAndThings.Enums;
|
using RMROC451.TweaksAndThings.Enums;
|
||||||
|
using UI.Builder;
|
||||||
|
using Model;
|
||||||
|
using RMROC451.TweaksAndThings.Extensions;
|
||||||
|
|
||||||
namespace RMROC451.TweaksAndThings;
|
namespace RMROC451.TweaksAndThings;
|
||||||
|
|
||||||
@@ -18,19 +21,26 @@ public class Settings
|
|||||||
List<WebhookSettings> webhookSettingsList,
|
List<WebhookSettings> webhookSettingsList,
|
||||||
bool handBrakeAndAirTagModifiers,
|
bool handBrakeAndAirTagModifiers,
|
||||||
RosterFuelColumnSettings engineRosterFuelColumnSettings,
|
RosterFuelColumnSettings engineRosterFuelColumnSettings,
|
||||||
bool endGearHelpersRequirePayment
|
bool endGearHelpersRequirePayment,
|
||||||
|
bool requireConsistCabooseForOilerAndHotboxSpotter,
|
||||||
|
bool cabooseAllowsConsistInfo
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
WebhookSettingsList = webhookSettingsList;
|
WebhookSettingsList = webhookSettingsList;
|
||||||
HandBrakeAndAirTagModifiers = handBrakeAndAirTagModifiers;
|
HandBrakeAndAirTagModifiers = handBrakeAndAirTagModifiers;
|
||||||
EngineRosterFuelColumnSettings = engineRosterFuelColumnSettings;
|
EngineRosterFuelColumnSettings = engineRosterFuelColumnSettings;
|
||||||
EndGearHelpersRequirePayment = endGearHelpersRequirePayment;
|
EndGearHelpersRequirePayment = endGearHelpersRequirePayment;
|
||||||
|
RequireConsistCabooseForOilerAndHotboxSpotter = requireConsistCabooseForOilerAndHotboxSpotter;
|
||||||
|
CabooseAllowsConsistInfo = cabooseAllowsConsistInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly UIState<string> _selectedTabState = new UIState<string>(null);
|
||||||
public List<WebhookSettings>? WebhookSettingsList;
|
public List<WebhookSettings>? WebhookSettingsList;
|
||||||
public bool HandBrakeAndAirTagModifiers;
|
public bool HandBrakeAndAirTagModifiers;
|
||||||
public RosterFuelColumnSettings? EngineRosterFuelColumnSettings;
|
public RosterFuelColumnSettings? EngineRosterFuelColumnSettings;
|
||||||
public bool EndGearHelpersRequirePayment;
|
public bool EndGearHelpersRequirePayment;
|
||||||
|
public bool RequireConsistCabooseForOilerAndHotboxSpotter;
|
||||||
|
public bool CabooseAllowsConsistInfo;
|
||||||
|
|
||||||
internal void AddAnotherRow()
|
internal void AddAnotherRow()
|
||||||
{
|
{
|
||||||
@@ -82,13 +92,22 @@ public static class SettingsExtensions
|
|||||||
{
|
{
|
||||||
public static List<WebhookSettings> SanitizeEmptySettings(this IEnumerable<WebhookSettings>? settings)
|
public static List<WebhookSettings> SanitizeEmptySettings(this IEnumerable<WebhookSettings>? settings)
|
||||||
{
|
{
|
||||||
List<WebhookSettings> output =
|
List<WebhookSettings> output =
|
||||||
settings?.Where(s => !string.IsNullOrEmpty(s.WebhookUrl))?.ToList() ??
|
settings?.Where(s => !string.IsNullOrEmpty(s.WebhookUrl))?.ToList() ??
|
||||||
new();
|
new();
|
||||||
|
|
||||||
output.Add(new());
|
output.Add(new());
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool CabooseAllowsConsistInfo(this TweaksAndThingsPlugin input) =>
|
||||||
|
input?.settings?.CabooseAllowsConsistInfo ?? false;
|
||||||
|
public static bool EndGearHelpersRequirePayment(this TweaksAndThingsPlugin input) =>
|
||||||
|
input?.settings?.EndGearHelpersRequirePayment ?? false;
|
||||||
|
public static bool RequireConsistCabooseForOilerAndHotboxSpotter(this TweaksAndThingsPlugin input) =>
|
||||||
|
input?.settings?.RequireConsistCabooseForOilerAndHotboxSpotter ?? false;
|
||||||
|
public static bool CabooseNonMotiveAllowedSetting(this TweaksAndThingsPlugin input, Car car) =>
|
||||||
|
input.EndGearHelpersRequirePayment() && car.set.Cars.CabooseInConsist() && car.NotMotivePower();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -82,16 +82,78 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
|||||||
settings.WebhookSettingsList =
|
settings.WebhookSettingsList =
|
||||||
settings?.WebhookSettingsList.SanitizeEmptySettings();
|
settings?.WebhookSettingsList.SanitizeEmptySettings();
|
||||||
|
|
||||||
//WebhookUISection(ref builder);
|
builder.AddTabbedPanels(settings._selectedTabState, delegate (UITabbedPanelBuilder tabBuilder)
|
||||||
//builder.AddExpandingVerticalSpacer();
|
{
|
||||||
WebhooksListUISection(ref builder);
|
tabBuilder.AddTab("Caboose Mods", "cabooseUpdates", CabooseMods);
|
||||||
builder.AddExpandingVerticalSpacer();
|
tabBuilder.AddTab("UI", "rosterUi", UiUpdates);
|
||||||
HandbrakesAndAnglecocksUISection(ref builder);
|
tabBuilder.AddTab("Webhooks", "webhooks", WebhooksListUISection);
|
||||||
builder.AddExpandingVerticalSpacer();
|
});
|
||||||
EnginRosterShowsFuelStatusUISection(ref builder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EnginRosterShowsFuelStatusUISection(ref UIPanelBuilder builder)
|
private static string cabooseUse => "Caboose Use";
|
||||||
|
private static string autoAiRequirment => "AutoAI\nRequirement";
|
||||||
|
|
||||||
|
private void CabooseMods(UIPanelBuilder builder)
|
||||||
|
{
|
||||||
|
builder.AddField(
|
||||||
|
cabooseUse,
|
||||||
|
builder.AddToggle(
|
||||||
|
() => settings?.EndGearHelpersRequirePayment ?? false,
|
||||||
|
delegate (bool enabled)
|
||||||
|
{
|
||||||
|
if (settings == null) settings = new();
|
||||||
|
settings.EndGearHelpersRequirePayment = enabled;
|
||||||
|
builder.Rebuild();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).Tooltip("Enable End Gear Helper Cost", @$"Will cost 1 minute of AI Brake Crew & Caboose Crew time per car in the consist when the new inspector buttons are utilized.
|
||||||
|
|
||||||
|
1.5x multiplier penalty to AI Brake Crew cost if no sufficiently crewed caboose nearby.
|
||||||
|
|
||||||
|
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: 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)");
|
||||||
|
|
||||||
|
builder.AddField(
|
||||||
|
autoAiRequirment,
|
||||||
|
builder.AddToggle(
|
||||||
|
() => settings?.RequireConsistCabooseForOilerAndHotboxSpotter ?? false,
|
||||||
|
delegate (bool enabled)
|
||||||
|
{
|
||||||
|
if (settings == null) settings = new();
|
||||||
|
settings.RequireConsistCabooseForOilerAndHotboxSpotter = enabled;
|
||||||
|
builder.Rebuild();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).Tooltip("AI Engineer Requires Caboose", $@"A caboose is required in the consist to check for Hotboxes and perform Auto Oiler, if checked.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UiUpdates(UIPanelBuilder builder)
|
||||||
|
{
|
||||||
|
builder.AddField(
|
||||||
|
"Enable Tag Updates",
|
||||||
|
builder.AddToggle(
|
||||||
|
() => settings?.HandBrakeAndAirTagModifiers ?? false,
|
||||||
|
delegate (bool enabled)
|
||||||
|
{
|
||||||
|
if (settings == null) settings = new();
|
||||||
|
settings.HandBrakeAndAirTagModifiers = enabled;
|
||||||
|
builder.Rebuild();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
).Tooltip("Enable Tag Updates", $@"Will suffix tag title with:
|
||||||
|
{TextSprites.CycleWaybills} if Air System issue.
|
||||||
|
{TextSprites.HandbrakeWheel} if there is a handbrake set.
|
||||||
|
{TextSprites.Hotbox} if a hotbox.");
|
||||||
|
|
||||||
|
EngineRosterShowsFuelStatusUISection(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EngineRosterShowsFuelStatusUISection(UIPanelBuilder builder)
|
||||||
{
|
{
|
||||||
var columns = Enum.GetValues(typeof(EngineRosterFuelDisplayColumn)).Cast<EngineRosterFuelDisplayColumn>().Select(i => i.ToString()).ToList();
|
var columns = Enum.GetValues(typeof(EngineRosterFuelDisplayColumn)).Cast<EngineRosterFuelDisplayColumn>().Select(i => i.ToString()).ToList();
|
||||||
builder.AddSection("Fuel Display in Engine Roster", delegate (UIPanelBuilder builder)
|
builder.AddSection("Fuel Display in Engine Roster", delegate (UIPanelBuilder builder)
|
||||||
@@ -123,39 +185,7 @@ public class TweaksAndThingsPlugin : SingletonPluginBase<TweaksAndThingsPlugin>,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandbrakesAndAnglecocksUISection(ref UIPanelBuilder builder)
|
private void WebhooksListUISection(UIPanelBuilder builder)
|
||||||
{
|
|
||||||
builder.AddSection("Tag Callout Handbrake and Air System Helper", delegate (UIPanelBuilder builder)
|
|
||||||
{
|
|
||||||
builder.AddField(
|
|
||||||
"Enable Tag Updates",
|
|
||||||
builder.AddToggle(
|
|
||||||
() => settings?.HandBrakeAndAirTagModifiers ?? false,
|
|
||||||
delegate (bool enabled)
|
|
||||||
{
|
|
||||||
if (settings == null) settings = new();
|
|
||||||
settings.HandBrakeAndAirTagModifiers = enabled;
|
|
||||||
builder.Rebuild();
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).Tooltip("Enable Tag Updates", $"Will add {TextSprites.CycleWaybills} to the car tag title having Air System issues. Also prepends {TextSprites.HandbrakeWheel} if there is a handbrake set.\n\nHolding Left Alt while tags are displayed only shows tag titles that have issues.");
|
|
||||||
|
|
||||||
builder.AddField(
|
|
||||||
"Caboose Use",
|
|
||||||
builder.AddToggle(
|
|
||||||
() => settings?.EndGearHelpersRequirePayment ?? false,
|
|
||||||
delegate (bool enabled)
|
|
||||||
{
|
|
||||||
if (settings == null) settings = new();
|
|
||||||
settings.EndGearHelpersRequirePayment = enabled;
|
|
||||||
builder.Rebuild();
|
|
||||||
}
|
|
||||||
)
|
|
||||||
).Tooltip("Enable End Gear Helper Cost", $"Will cost 1 minute of AI Brake Crew & Caboose Crew time per car in the consist when the new inspector buttons are utilized.\n\n1.5x multiplier penalty to AI Brake Crew cost if no sufficiently crewed caboose nearby.\n\nCaboose starts reloading `Crew Hours` at any Team or Repair track (no waybill), after being stationary for 30 seconds.");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void WebhooksListUISection(ref UIPanelBuilder builder)
|
|
||||||
{
|
{
|
||||||
builder.AddSection("Webhooks List", delegate (UIPanelBuilder builder)
|
builder.AddSection("Webhooks List", delegate (UIPanelBuilder builder)
|
||||||
{
|
{
|
||||||
|
|||||||
12
updates.json
Normal file
12
updates.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"RMROC451.TweaksAndThings": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"changelog": [
|
||||||
|
{
|
||||||
|
"version": "*",
|
||||||
|
"date": "2024-07-26T14:31:49.0948925Z",
|
||||||
|
"desc": "https://github.com/rmroc451/TweaksAndThings/releases"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user