413 lines
14 KiB
C#
413 lines
14 KiB
C#
#nullable enable
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Content.IntegrationTests.Fixtures;
|
|
using Content.IntegrationTests.Fixtures.Attributes;
|
|
using Content.Server.NPC;
|
|
using Content.Server.NPC.HTN;
|
|
using Content.Shared._DV.Diona;
|
|
using Content.Shared.Gibbing;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Humanoid.Prototypes;
|
|
using Content.Shared.Mind;
|
|
using Content.Shared.Species;
|
|
using Robust.Shared.Enums;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Map.Components;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.IntegrationTests.Tests._DV;
|
|
|
|
[TestFixture]
|
|
[TestOf(typeof(DVGestaltSystem))]
|
|
[TestOf(typeof(DVNymphingBodySystem))]
|
|
[TestOf(typeof(DVNymphRelationSystem))]
|
|
public sealed class DVDionaTest : GameTest
|
|
{
|
|
private static readonly EntProtoId NymphPrototype = "DVMobDionaNymph";
|
|
private static readonly EntProtoId ReformedPrototype = "MobDionaReformed";
|
|
|
|
private static readonly ProtoId<SpeciesPrototype> Diona = "Diona";
|
|
private static readonly Gender Gender = Gender.Epicene;
|
|
public static readonly Sex Sex = Sex.Unsexed;
|
|
public static readonly int Age = 72;
|
|
public static readonly float Height = 1f;
|
|
|
|
[SidedDependency(Side.Server)] private readonly SharedMindSystem _mind = null!;
|
|
[SidedDependency(Side.Server)] private readonly DVNymphRelationSystem _relations = null!;
|
|
[SidedDependency(Side.Server)] private readonly GibbingSystem _gibbing = null!;
|
|
[SidedDependency(Side.Server)] private readonly MetaDataSystem _metadata = null!;
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void Assimilation()
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var actor = SSpawn(NymphPrototype);
|
|
var mindlessTarget = SSpawn(NymphPrototype);
|
|
var mindedTarget = SSpawn(NymphPrototype);
|
|
|
|
var actorMind = _mind.CreateMind(null);
|
|
_mind.TransferTo(actorMind, actor);
|
|
|
|
var targetMind = _mind.CreateMind(null);
|
|
_mind.TransferTo(targetMind, mindedTarget);
|
|
|
|
var assimilate = new DVAssimilateNymphActionEvent { Target = mindlessTarget };
|
|
SEntMan.EventBus.RaiseLocalEvent(actor, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var gestalt = GetSingleGestalt();
|
|
var mapComp = SComp<MapComponent>(gestalt.Comp.NymphStorageMap);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(2));
|
|
Assert.That(gestalt.Comp.StoredNymphs, Is.EquivalentTo([actor, mindlessTarget]));
|
|
Assert.That(SComp<DVGestaltMemberComponent>(actor).StoredInGestalt, Is.EqualTo(gestalt.Owner));
|
|
Assert.That(SComp<DVGestaltMemberComponent>(mindlessTarget).StoredInGestalt, Is.EqualTo(gestalt.Owner));
|
|
Assert.That(SComp<TransformComponent>(actor).MapID, Is.EqualTo(mapComp.MapId));
|
|
Assert.That(SComp<TransformComponent>(mindlessTarget).MapID, Is.EqualTo(mapComp.MapId));
|
|
Assert.That(_mind.GetMind(gestalt), Is.EqualTo(actorMind.Owner));
|
|
}
|
|
|
|
var beforeCount = gestalt.Comp.NymphCount;
|
|
var beforeStored = gestalt.Comp.StoredNymphs.Count;
|
|
assimilate = new DVAssimilateNymphActionEvent { Target = mindedTarget };
|
|
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, assimilate);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(assimilate.Handled, Is.False);
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(beforeCount));
|
|
Assert.That(gestalt.Comp.StoredNymphs.Count, Is.EqualTo(beforeStored));
|
|
Assert.That(gestalt.Comp.StoredNymphs, Is.EquivalentTo([actor, mindlessTarget]));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void GestaltMembership()
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var actor = SSpawn(NymphPrototype);
|
|
var target = SSpawn(NymphPrototype);
|
|
|
|
var assimilate = new DVAssimilateNymphActionEvent { Target = target };
|
|
SEntMan.EventBus.RaiseLocalEvent(actor, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var gestalt = GetSingleGestalt();
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(2));
|
|
|
|
SEntMan.RemoveComponent<DVGestaltMemberComponent>(target);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(1));
|
|
Assert.That(gestalt.Comp.StoredNymphs, Is.EquivalentTo([actor]));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void GestaltReformWithDifferentIdentities()
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var first = SpawnProfiledNymph("Mismatched Rings");
|
|
var second = SpawnProfiledNymph("Different Rings");
|
|
var third = SpawnProfiledNymph("Mismatched Rings");
|
|
|
|
var assimilate = new DVAssimilateNymphActionEvent { Target = second };
|
|
SEntMan.EventBus.RaiseLocalEvent(first, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var gestalt = GetSingleGestalt();
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(2));
|
|
|
|
assimilate = new DVAssimilateNymphActionEvent { Target = third };
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var reform = new ReformSystem.ReformEvent();
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, reform);
|
|
Assert.That(reform.Handled, Is.True);
|
|
|
|
var reformed = FindEntityByPrototype(ReformedPrototype);
|
|
Assert.That(reformed, Is.Not.Null);
|
|
|
|
Assert.That(SComp<MetaDataComponent>(reformed.Value).EntityName, Is.Not.EqualTo("Mismatched Rings"));
|
|
Assert.That(SComp<MetaDataComponent>(reformed.Value).EntityName, Is.Not.EqualTo("Different Rings"));
|
|
}
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void GestaltReformWithSameIdentities()
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var first = SpawnProfiledNymph("Identical Rings");
|
|
var second = SpawnProfiledNymph("Identical Rings");
|
|
var third = SpawnProfiledNymph("Identical Rings");
|
|
|
|
var firstMind = _mind.CreateMind(null);
|
|
_mind.TransferTo(firstMind, first);
|
|
|
|
var assimilate = new DVAssimilateNymphActionEvent { Target = second };
|
|
SEntMan.EventBus.RaiseLocalEvent(first, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var gestalt = GetSingleGestalt();
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(2));
|
|
|
|
assimilate = new DVAssimilateNymphActionEvent { Target = third };
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var reform = new ReformSystem.ReformEvent();
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, reform);
|
|
Assert.That(reform.Handled, Is.True);
|
|
|
|
var reformed = FindEntityByPrototype(ReformedPrototype);
|
|
Assert.That(reformed, Is.Not.Null);
|
|
|
|
var profile = SComp<HumanoidProfileComponent>(reformed.Value);
|
|
|
|
Assert.Multiple(() =>
|
|
{
|
|
Assert.That(_mind.GetMind(reformed.Value), Is.EqualTo(firstMind.Owner));
|
|
Assert.That(SComp<MetaDataComponent>(reformed.Value).EntityName, Is.EqualTo("Identical Rings"));
|
|
Assert.That(profile.Species, Is.EqualTo(Diona));
|
|
Assert.That(profile.Gender, Is.EqualTo(Gender));
|
|
Assert.That(profile.Sex, Is.EqualTo(Sex));
|
|
Assert.That(profile.Age, Is.EqualTo(Age));
|
|
Assert.That(profile.Height, Is.EqualTo(Height));
|
|
});
|
|
}
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void GestaltMapPreservation([Range(1, 4)] int additionalNymphCount)
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var first = SpawnProfiledNymph("Identical Rings");
|
|
var others = new List<EntityUid>();
|
|
for (var i = 0; i < additionalNymphCount; i++)
|
|
{
|
|
others.Add(SpawnProfiledNymph("Identical Rings"));
|
|
}
|
|
|
|
var second = SpawnProfiledNymph("Identical Rings");
|
|
|
|
var assimilate = new DVAssimilateNymphActionEvent { Target = second };
|
|
SEntMan.EventBus.RaiseLocalEvent(first, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
|
|
var gestalt = GetSingleGestalt();
|
|
|
|
foreach (var other in others)
|
|
{
|
|
assimilate = new DVAssimilateNymphActionEvent { Target = other };
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, assimilate);
|
|
Assert.That(assimilate.Handled, Is.True);
|
|
}
|
|
|
|
Assert.That(gestalt.Comp.NymphCount, Is.EqualTo(2 + additionalNymphCount));
|
|
|
|
var gestaltMap = SComp<MapComponent>(gestalt.Comp.NymphStorageMap);
|
|
|
|
foreach (var other in others)
|
|
{
|
|
Assert.That(SComp<TransformComponent>(other).MapID, Is.EqualTo(gestaltMap.MapId));
|
|
}
|
|
|
|
var reform = new ReformSystem.ReformEvent();
|
|
SEntMan.EventBus.RaiseLocalEvent(gestalt, reform);
|
|
Assert.That(reform.Handled, Is.True);
|
|
|
|
var reformed = FindEntityByPrototype(ReformedPrototype);
|
|
Assert.That(reformed, Is.Not.Null);
|
|
|
|
var reformedGestalt = SComp<DVGestaltComponent>(reformed.Value);
|
|
Assert.That(reformedGestalt.NymphCount, Is.EqualTo(2 + additionalNymphCount));
|
|
|
|
var reformedGestaltMap = SComp<MapComponent>(reformedGestalt.NymphStorageMap);
|
|
|
|
foreach (var other in others)
|
|
{
|
|
Assert.That(SComp<TransformComponent>(other).MapID, Is.EqualTo(reformedGestaltMap.MapId));
|
|
}
|
|
}
|
|
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void Relations()
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var leader = SSpawn(NymphPrototype);
|
|
var follower = SSpawn(NymphPrototype);
|
|
|
|
_relations.Follow(
|
|
(leader, SComp<DVNymphLeadComponent>(leader)),
|
|
(follower, SComp<DVNymphFollowerComponent>(follower)));
|
|
|
|
var leaderComp = SComp<DVNymphLeadComponent>(leader);
|
|
var followerComp = SComp<DVNymphFollowerComponent>(follower);
|
|
var htn = SComp<HTNComponent>(follower);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(leaderComp.Followers, Does.Contain(follower));
|
|
Assert.That(followerComp.Lead, Is.EqualTo(leader));
|
|
Assert.That(htn.Blackboard.TryGetValue<EntityCoordinates>(NPCBlackboard.FollowTarget, out var coords, SEntMan), Is.True);
|
|
Assert.That(coords!.EntityId, Is.EqualTo(leader));
|
|
}
|
|
|
|
SEntMan.RemoveComponent<DVNymphLeadComponent>(leader);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(followerComp.Lead, Is.Null);
|
|
Assert.That(htn.Blackboard.TryGetValue<EntityCoordinates>(NPCBlackboard.FollowTarget, out _, SEntMan), Is.False);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
[RunOnSide(Side.Server)]
|
|
public void GibRelations()
|
|
{
|
|
using var cleanup = Cleanup();
|
|
|
|
var body = SSpawn("MobDiona");
|
|
_metadata.SetEntityName(body, "Remembered Rings");
|
|
|
|
var bodyMind = _mind.CreateMind(null);
|
|
_mind.TransferTo(bodyMind, body);
|
|
|
|
var giblets = _gibbing.Gib(body);
|
|
Assert.That(giblets.Count, Is.GreaterThanOrEqualTo(3));
|
|
|
|
var nymphs = giblets
|
|
.Where(SEntMan.EntityExists)
|
|
.Where(SEntMan.HasComponent<DVNymphProfileComponent>)
|
|
.ToList();
|
|
|
|
Assert.That(nymphs.Count, Is.EqualTo(3));
|
|
|
|
var lead = nymphs.Single(uid => _mind.GetMind(uid) == bodyMind);
|
|
var leadComp = SComp<DVNymphLeadComponent>(lead);
|
|
var memory = SComp<DVNymphMindMemoryComponent>(lead);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(memory.Mind, Is.EqualTo(bodyMind.Owner));
|
|
Assert.That(leadComp.Followers, Is.EquivalentTo(nymphs));
|
|
}
|
|
|
|
foreach (var nymph in nymphs)
|
|
{
|
|
var profile = SComp<DVNymphProfileComponent>(nymph);
|
|
var follower = SComp<DVNymphFollowerComponent>(nymph);
|
|
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
Assert.That(profile.Name, Is.EqualTo("Remembered Rings"));
|
|
Assert.That(follower.Lead, Is.EqualTo(lead));
|
|
}
|
|
}
|
|
}
|
|
|
|
private EntityUid SpawnProfiledNymph(string name)
|
|
{
|
|
var uid = SSpawn(NymphPrototype);
|
|
var profile = SComp<DVNymphProfileComponent>(uid);
|
|
|
|
profile.Name = name;
|
|
profile.Species = Diona;
|
|
profile.Gender = Gender;
|
|
profile.Sex = Sex;
|
|
profile.Age = Age;
|
|
profile.Height = Height;
|
|
|
|
return uid;
|
|
}
|
|
|
|
private sealed class ActionDisposable(Action action) : IDisposable
|
|
{
|
|
public void Dispose()
|
|
{
|
|
action.Invoke();
|
|
}
|
|
}
|
|
|
|
private ActionDisposable Cleanup()
|
|
{
|
|
return new ActionDisposable(() =>
|
|
{
|
|
var gestalts = SEntMan.EntityQueryEnumerator<DVGestaltComponent>();
|
|
|
|
while (gestalts.MoveNext(out var uid, out _))
|
|
{
|
|
if (SEntMan.Deleted(uid))
|
|
continue;
|
|
|
|
SEntMan.QueueDeleteEntity(uid);
|
|
}
|
|
|
|
var nymphs = SEntMan.EntityQueryEnumerator<DVNymphFollowerComponent>();
|
|
|
|
while (nymphs.MoveNext(out var uid, out _))
|
|
{
|
|
if (SEntMan.Deleted(uid))
|
|
continue;
|
|
|
|
SEntMan.QueueDeleteEntity(uid);
|
|
}
|
|
});
|
|
}
|
|
|
|
private Entity<DVGestaltComponent> GetSingleGestalt()
|
|
{
|
|
EntityUid foundUid = default;
|
|
DVGestaltComponent? foundComp = null;
|
|
var count = 0;
|
|
var query = SEntMan.EntityQueryEnumerator<DVGestaltComponent>();
|
|
|
|
while (query.MoveNext(out var uid, out var comp))
|
|
{
|
|
if (SEntMan.Deleted(uid))
|
|
continue;
|
|
|
|
foundUid = uid;
|
|
foundComp = comp;
|
|
count++;
|
|
}
|
|
|
|
Assert.That(count, Is.EqualTo(1));
|
|
return (foundUid, foundComp!);
|
|
}
|
|
|
|
private EntityUid? FindEntityByPrototype(EntProtoId prototype)
|
|
{
|
|
var query = SEntMan.EntityQueryEnumerator<MetaDataComponent>();
|
|
while (query.MoveNext(out var uid, out var meta))
|
|
{
|
|
if (SEntMan.Deleted(uid))
|
|
continue;
|
|
|
|
if (meta.EntityPrototype?.ID == prototype.Id)
|
|
return uid;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|