mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-10-16 23:49:19 +02:00
Keep the crew when a vehicle is swapped in the depot
The crew was copied to the card but not to the new cars, which are what is shown and exported, so a swapped locomotive came out unstaffed. Swapping now moves the crew over and otherwise staffs the vehicle as adding would.
This commit is contained in:
107
StarterNG.Tests/ConsistCrewTests.cs
Normal file
107
StarterNG.Tests/ConsistCrewTests.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using StarterNG.Classes;
|
||||
using StarterNG.Domain;
|
||||
using StarterNG.Domain.Vehicles;
|
||||
using StarterNG.Tests.Fakes;
|
||||
|
||||
namespace StarterNG.Tests;
|
||||
|
||||
public class ConsistCrewTests
|
||||
{
|
||||
private readonly Consist _consist;
|
||||
private readonly VehicleCatalog _catalog;
|
||||
|
||||
public ConsistCrewTests()
|
||||
{
|
||||
var installation = new TestInstallation(new InMemoryFileSystem()
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "ep07", "textures.txt"),
|
||||
"!=e\nep07-001.mat=ep07,EP07\nep07-002.mat=ep07,EP07")
|
||||
.WithFile(TestInstallation.At("dynamic", "pkp", "b111", "textures.txt"),
|
||||
"!=b\nb111-01.mat=b111,B111"));
|
||||
installation.Vehicles.Load(installation.Library.Vehicles);
|
||||
|
||||
_catalog = installation.Library.Vehicles;
|
||||
_consist = new Consist(_catalog, new VehicleInfo(_catalog));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_locomotive_added_at_the_head_gets_a_driver_in_cab_a()
|
||||
{
|
||||
var loco = Add("ep07-001", 0);
|
||||
|
||||
Assert.Equal(eDriverType.Headdriver, loco.Cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Replacing_the_locomotive_keeps_the_driver_on_the_new_one()
|
||||
{
|
||||
Add("ep07-001", 0);
|
||||
Add("b111-01", 1);
|
||||
|
||||
var replacement = Replace(0, "ep07-002");
|
||||
|
||||
Assert.Equal(eDriverType.Headdriver, replacement.Cars[0].DriverType);
|
||||
Assert.Equal(eDriverType.Headdriver, replacement.Driver);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void An_unstaffed_locomotive_replaced_at_the_head_is_staffed_in_cab_a()
|
||||
{
|
||||
var loco = Add("ep07-001", 0);
|
||||
loco.Cars[0].DriverType = eDriverType.Nobody;
|
||||
loco.Driver = eDriverType.Nobody;
|
||||
|
||||
var replacement = Replace(0, "ep07-002");
|
||||
|
||||
Assert.Equal(eDriverType.Headdriver, replacement.Cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_driver_in_cab_b_stays_in_cab_b()
|
||||
{
|
||||
var loco = Add("ep07-001", 0);
|
||||
loco.Cars[0].DriverType = eDriverType.Reardriver;
|
||||
loco.Driver = eDriverType.Reardriver;
|
||||
|
||||
var replacement = Replace(0, "ep07-002");
|
||||
|
||||
Assert.Equal(eDriverType.Reardriver, replacement.Cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_wagon_put_in_place_of_the_locomotive_gets_no_driver()
|
||||
{
|
||||
Add("ep07-001", 0);
|
||||
|
||||
var wagon = Replace(0, "b111-01");
|
||||
|
||||
Assert.Equal(eDriverType.Nobody, wagon.Cars[0].DriverType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_second_locomotive_behind_a_staffed_one_stays_unstaffed()
|
||||
{
|
||||
Add("ep07-001", 0);
|
||||
|
||||
var second = Add("ep07-002", 1);
|
||||
|
||||
Assert.Equal(eDriverType.Nobody, second.Cars[0].DriverType);
|
||||
}
|
||||
|
||||
private ConsistItem Add(string skin, int at)
|
||||
{
|
||||
var item = Item(skin);
|
||||
_consist.Staff(item, at);
|
||||
_consist.Insert(at, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ConsistItem Replace(int at, string skin)
|
||||
{
|
||||
var item = Item(skin);
|
||||
_consist.Replace(at, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
private ConsistItem Item(string skin) =>
|
||||
new() { Cars = new List<Dynamic> { _consist.MakeDynamic(_catalog.TextureForSkin(skin)!, null) } };
|
||||
}
|
||||
@@ -236,6 +236,57 @@ public sealed class Consist : IReadOnlyList<ConsistItem>
|
||||
public void Insert(int at, ConsistItem item) =>
|
||||
_items.Insert(Math.Clamp(at, 0, _items.Count), item);
|
||||
|
||||
/// <summary>
|
||||
/// Crew for a vehicle joining at position: a driver in cab A when it is powered
|
||||
/// and either leads or the consist has no driver yet, nobody otherwise.
|
||||
/// </summary>
|
||||
public void Staff(ConsistItem item, int position)
|
||||
{
|
||||
item.Driver = eDriverType.Nobody;
|
||||
foreach (var car in item.Cars)
|
||||
car.DriverType = eDriverType.Nobody;
|
||||
|
||||
if (!IsPowered(item))
|
||||
return;
|
||||
|
||||
bool staffed = _items.Any(other => !ReferenceEquals(other, item) &&
|
||||
other.Driver is eDriverType.Headdriver or eDriverType.Reardriver);
|
||||
if (position == 0 || !staffed)
|
||||
Crew(item, eDriverType.Headdriver);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Puts item in place of the vehicle at index. Its crew moves over where the
|
||||
/// replacement can take it - a driver only into something powered - and the
|
||||
/// rest is staffed as a newly added vehicle would be.
|
||||
/// </summary>
|
||||
public void Replace(int index, ConsistItem item)
|
||||
{
|
||||
var replaced = _items[index];
|
||||
_items[index] = item;
|
||||
Staff(item, index);
|
||||
|
||||
var crew = replaced.Driver;
|
||||
if (crew == eDriverType.Passenger ||
|
||||
(crew is eDriverType.Headdriver or eDriverType.Reardriver && IsPowered(item)))
|
||||
Crew(item, crew);
|
||||
}
|
||||
|
||||
// The crew lives on the cars - they are what is shown and exported - and the
|
||||
// card only mirrors it.
|
||||
private static void Crew(ConsistItem item, eDriverType crew)
|
||||
{
|
||||
if (item.Cars.Count == 0)
|
||||
return;
|
||||
|
||||
item.Cars[0].DriverType = crew;
|
||||
item.Driver = crew;
|
||||
}
|
||||
|
||||
private bool IsPowered(ConsistItem item) =>
|
||||
item.Cars.Count > 0 && _db.TextureForSkin(item.Cars[0].SkinFile) is { } texture &&
|
||||
VehicleInfo.IsPoweredCategory(VehicleInfo.CategoryOf(texture));
|
||||
|
||||
public void MoveLeft(ConsistItem item)
|
||||
{
|
||||
int i = _items.IndexOf(item);
|
||||
|
||||
@@ -573,10 +573,9 @@ public partial class Depot : UserControl
|
||||
{
|
||||
Cars = unit.Select(NewVehicle).ToList(),
|
||||
Grouped = unit.Count > 1,
|
||||
Driver = _consist.Selected.Driver,
|
||||
Flipped = _consist.Selected.Flipped
|
||||
};
|
||||
_consist[i] = item;
|
||||
_consist.Replace(i, item);
|
||||
_consist.Selected = item;
|
||||
_consist.AutoConnectAll();
|
||||
RebuildConsist();
|
||||
@@ -607,36 +606,13 @@ public partial class Depot : UserControl
|
||||
};
|
||||
|
||||
at = Math.Clamp(at, 0, _consist.Count);
|
||||
MatchOccupancy(item, at);
|
||||
_consist.Staff(item, at);
|
||||
_consist.Insert(at, item);
|
||||
_consist.Selected = item;
|
||||
_consist.AutoConnectAll();
|
||||
RebuildConsist();
|
||||
}
|
||||
|
||||
private void MatchOccupancy(ConsistItem item, int position)
|
||||
{
|
||||
item.Driver = eDriverType.Nobody;
|
||||
var lead = item.Cars.FirstOrDefault();
|
||||
if (lead is null) return;
|
||||
|
||||
foreach (var car in item.Cars)
|
||||
car.DriverType = eDriverType.Nobody;
|
||||
|
||||
var tex = _db.TextureForSkin(lead.SkinFile);
|
||||
string? cat = tex != null ? VehicleInfo.CategoryOf(tex) : null;
|
||||
if (!VehicleInfo.IsPoweredCategory(cat))
|
||||
return;
|
||||
|
||||
bool staffed = _consist.Any(i =>
|
||||
i.Driver is eDriverType.Headdriver or eDriverType.Reardriver);
|
||||
if (position == 0 || !staffed)
|
||||
{
|
||||
item.Driver = eDriverType.Headdriver;
|
||||
lead.DriverType = eDriverType.Headdriver;
|
||||
}
|
||||
}
|
||||
|
||||
private async void TextureBaseButton_OnClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||
{
|
||||
if (TopLevel.GetTopLevel(this) is not Window owner) return;
|
||||
|
||||
Reference in New Issue
Block a user