Merge efdf22412b into fd5b16abb3
|
|
@ -0,0 +1,412 @@
|
|||
#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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
using System.Numerics;
|
||||
using Content.Server.NPC;
|
||||
using Content.Server.NPC.HTN;
|
||||
using Content.Server.NPC.Systems;
|
||||
using Content.Shared._DV.Diona;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Server._DV.Diona;
|
||||
|
||||
public sealed class DVNymphNPCSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly NPCSystem _npc = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVNymphFollowerComponent, DVNymphFollowerLeadGotChangedEvent>(OnLeadGotChanged);
|
||||
}
|
||||
|
||||
private void OnLeadGotChanged(Entity<DVNymphFollowerComponent> ent, ref DVNymphFollowerLeadGotChangedEvent args)
|
||||
{
|
||||
if (ent.Comp.Lead is { } leader)
|
||||
_npc.SetBlackboard(ent, NPCBlackboard.FollowTarget, new EntityCoordinates(leader, Vector2.Zero));
|
||||
else if (TryComp<HTNComponent>(ent, out var htn))
|
||||
{
|
||||
htn.Blackboard.Remove<EntityCoordinates>(NPCBlackboard.FollowTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
using Content.Server.Mind;
|
||||
using Content.Server.Zombies;
|
||||
using Content.Shared._DV.Diona;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Actions.Components;
|
||||
using Content.Shared.Body;
|
||||
using Content.Shared.Gibbing;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.NameIdentifier;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Species.Components;
|
||||
using Content.Shared.Zombies;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._DV.Diona;
|
||||
|
||||
public sealed class DVNymphingOrganSystem : EntitySystem
|
||||
{
|
||||
private static readonly EntProtoId AssimilateAction = "DVDionaAssimilateAction";
|
||||
private static readonly TimeSpan AliveGibAssimilateCooldown = TimeSpan.FromSeconds(30);
|
||||
private static readonly TimeSpan DeadGibAssimilateCooldown = TimeSpan.FromMinutes(10);
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly MindSystem _mindSystem = default!;
|
||||
[Dependency] private readonly ZombieSystem _zombie = default!;
|
||||
[Dependency] private readonly SharedVisualBodySystem _visualBody = default!;
|
||||
[Dependency] private readonly NameModifierSystem _nameModifier = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVNymphingOrganComponent, BodyRelayedEvent<BeingGibbedEvent>>(OnBeingGibbed);
|
||||
SubscribeLocalEvent<DVNymphProfileComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
|
||||
}
|
||||
|
||||
private void OnBeingGibbed(Entity<DVNymphingOrganComponent> ent, ref BodyRelayedEvent<BeingGibbedEvent> args)
|
||||
{
|
||||
if (TerminatingOrDeleted(ent))
|
||||
return;
|
||||
|
||||
if (!_protoManager.TryIndex<EntityPrototype>(ent.Comp.EntityPrototype, out var entityProto))
|
||||
return;
|
||||
|
||||
// Get the organs' position & spawn a nymph there
|
||||
var coords = Transform(ent).Coordinates;
|
||||
var nymph = SpawnAtPosition(entityProto.ID, coords);
|
||||
SetAssimilateCooldown(nymph, GetAssimilateCooldown(args.Body));
|
||||
|
||||
if (HasComp<ZombieComponent>(args.Body)) // Zombify the new nymph if old one is a zombie
|
||||
_zombie.ZombifyEntity(nymph);
|
||||
|
||||
// Move the mind if there is one and it's supposed to be transferred
|
||||
if (ent.Comp.TransferMind && _mindSystem.TryGetMind(args.Body, out var mindId, out var mind))
|
||||
_mindSystem.TransferTo(mindId, nymph, true, mind: mind);
|
||||
|
||||
if (TryComp<DVNymphProfileComponent>(nymph, out var nymphProfile))
|
||||
{
|
||||
nymphProfile.Name = Name(args.Body);
|
||||
|
||||
if (TryComp<HumanoidProfileComponent>(args.Body, out var bodyProfile))
|
||||
{
|
||||
nymphProfile.Species = bodyProfile.Species;
|
||||
nymphProfile.Gender = bodyProfile.Gender;
|
||||
nymphProfile.Sex = bodyProfile.Sex;
|
||||
nymphProfile.Age = bodyProfile.Age;
|
||||
nymphProfile.Height = bodyProfile.Height;
|
||||
}
|
||||
|
||||
if (_visualBody.TryGatherMarkingsData(args.Body.Owner, null, out var profiles, out _, out var applied))
|
||||
{
|
||||
nymphProfile.OrganMarkings = applied;
|
||||
nymphProfile.OrganProfiles = profiles;
|
||||
}
|
||||
|
||||
Dirty(nymph, nymphProfile);
|
||||
_nameModifier.RefreshNameModifiers(nymph);
|
||||
}
|
||||
|
||||
// Delete the old organ
|
||||
QueueDel(ent);
|
||||
args.Args.Giblets.Add(nymph);
|
||||
}
|
||||
|
||||
private TimeSpan GetAssimilateCooldown(EntityUid body)
|
||||
{
|
||||
return TryComp<MobStateComponent>(body, out var mobState) && mobState.CurrentState == MobState.Alive
|
||||
? AliveGibAssimilateCooldown
|
||||
: DeadGibAssimilateCooldown;
|
||||
}
|
||||
|
||||
private void SetAssimilateCooldown(EntityUid nymph, TimeSpan cooldown)
|
||||
{
|
||||
foreach (var action in _actions.GetActions(nymph))
|
||||
{
|
||||
if (Prototype(action.Owner)?.ID != AssimilateAction.Id)
|
||||
continue;
|
||||
|
||||
_actions.SetCooldown((action.Owner, action.Comp), cooldown);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnRefreshNameModifiers(Entity<DVNymphProfileComponent> ent, ref RefreshNameModifiersEvent args)
|
||||
{
|
||||
if (ent.Comp.Name is { } name)
|
||||
args.AddModifier("nymph-name-prefix", 0, ("identityName", name));
|
||||
}
|
||||
}
|
||||
|
|
@ -9,4 +9,11 @@ namespace Content.Shared.Body;
|
|||
/// <seealso cref="GibbingSystem" />
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[Access(typeof(GibbableOrganSystem))]
|
||||
public sealed partial class GibbableOrganComponent : Component;
|
||||
public sealed partial class GibbableOrganComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// DeltaV - whether the organ will become a giblet
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Active = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ public sealed class GibbableOrganSystem : EntitySystem
|
|||
|
||||
private void OnBeingGibbed(Entity<GibbableOrganComponent> ent, ref BodyRelayedEvent<BeingGibbedEvent> args)
|
||||
{
|
||||
args.Args.Giblets.Add(ent);
|
||||
// Begin DeltaV - gibbable activation
|
||||
if (ent.Comp.Active)
|
||||
args.Args.Giblets.Add(ent);
|
||||
// End DeltaV - gibbable activation
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
using Content.Shared.Actions;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
public sealed partial class DVAssimilateNymphActionEvent : EntityTargetActionEvent;
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(DVGestaltSystem))]
|
||||
public sealed partial class DVGestaltComponent : Component
|
||||
{
|
||||
[DataField(serverOnly: true)]
|
||||
public EntityUid NymphStorageMap;
|
||||
|
||||
[DataField(serverOnly: true)]
|
||||
public HashSet<EntityUid> StoredNymphs = new();
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public int NymphCount;
|
||||
|
||||
[DataField]
|
||||
public int RequiredNymphs = 3;
|
||||
|
||||
/// <summary>
|
||||
/// The text that appears when attempting to split.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId PopupText = "diona-gib-action-use";
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVGestaltMemberComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? StoredInGestalt;
|
||||
}
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Shared.Body;
|
||||
using Content.Shared.Gibbing;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Species;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
public sealed class DVGestaltSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMapSystem _map = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||
[Dependency] private readonly HumanoidProfileSystem _profile = default!;
|
||||
[Dependency] private readonly SharedVisualBodySystem _visualBody = default!;
|
||||
|
||||
private static readonly EntProtoId<DVGestaltComponent> GestaltPrototype = "DVMobDionaGestalt";
|
||||
private static readonly EntProtoId ReformedPrototype = "MobDionaReformed";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVNymphProfileComponent, DVAssimilateNymphActionEvent>(OnNymphAssimilate);
|
||||
|
||||
SubscribeLocalEvent<DVGestaltComponent, MapInitEvent>(OnGestaltInit);
|
||||
SubscribeLocalEvent<DVGestaltComponent, ComponentShutdown>(OnGestaltShutdown);
|
||||
SubscribeLocalEvent<DVGestaltMemberComponent, ComponentShutdown>(OnGestaltMemberShutdown);
|
||||
SubscribeLocalEvent<DVGestaltComponent, DVAssimilateNymphActionEvent>(OnGestaltAssimilate);
|
||||
SubscribeLocalEvent<DVGestaltComponent, GibActionSystem.GibActionEvent>(OnGestaltGib);
|
||||
SubscribeLocalEvent<DVGestaltComponent, BeingGibbedEvent>(OnGestaltBeingGibbed);
|
||||
SubscribeLocalEvent<DVGestaltComponent, GibbedBeforeDeletionEvent>(OnGestaltGibbedBeforeDeletion);
|
||||
SubscribeLocalEvent<DVGestaltComponent, ReformSystem.ReformEvent>(OnGestaltReforming);
|
||||
}
|
||||
|
||||
private void OnGestaltInit(Entity<DVGestaltComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
var map = _map.CreateMap(runMapInit: false);
|
||||
ent.Comp.NymphStorageMap = map;
|
||||
_metadata.SetEntityName(map, $"Diona Gestalt Storage {ToPrettyString(ent)}");
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnGestaltMemberShutdown(Entity<DVGestaltMemberComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp<DVGestaltComponent>(ent.Comp.StoredInGestalt, out var gestalt))
|
||||
return;
|
||||
|
||||
gestalt.StoredNymphs.Remove(ent);
|
||||
gestalt.NymphCount--;
|
||||
Dirty(ent.Comp.StoredInGestalt.Value, gestalt);
|
||||
}
|
||||
|
||||
private void OnGestaltShutdown(Entity<DVGestaltComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (TryComp<MapComponent>(ent.Comp.NymphStorageMap, out var map))
|
||||
_map.QueueDeleteMap(map.MapId);
|
||||
}
|
||||
|
||||
private void OnGestaltAssimilate(Entity<DVGestaltComponent> ent, ref DVAssimilateNymphActionEvent args)
|
||||
{
|
||||
if (!_net.IsServer)
|
||||
return;
|
||||
|
||||
if (_mind.TryGetMind(args.Target, out _, out _))
|
||||
return;
|
||||
|
||||
Assimilate(ent, args.Target);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnNymphAssimilate(Entity<DVNymphProfileComponent> ent, ref DVAssimilateNymphActionEvent args)
|
||||
{
|
||||
if (!_net.IsServer)
|
||||
return;
|
||||
|
||||
if (_mind.TryGetMind(args.Target, out _, out _))
|
||||
return;
|
||||
|
||||
var gestalt = SpawnAtPosition(GestaltPrototype, Transform(ent).Coordinates);
|
||||
var gestaltComp = Comp<DVGestaltComponent>(gestalt);
|
||||
Assimilate((gestalt, gestaltComp), ent.Owner);
|
||||
Assimilate((gestalt, gestaltComp), args.Target);
|
||||
|
||||
if (_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
_mind.TransferTo(mindId, gestalt, true, mind: mind);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void Assimilate(Entity<DVGestaltComponent> gestalt, Entity<DVGestaltMemberComponent?> nymph)
|
||||
{
|
||||
if (!Resolve(nymph, ref nymph.Comp) || !TryComp<MapComponent>(gestalt.Comp.NymphStorageMap, out var map))
|
||||
return;
|
||||
|
||||
_transform.SetMapCoordinates(nymph, new MapCoordinates(Vector2.Zero, map.MapId));
|
||||
gestalt.Comp.StoredNymphs.Add(nymph);
|
||||
gestalt.Comp.NymphCount++;
|
||||
nymph.Comp.StoredInGestalt = gestalt;
|
||||
Dirty(nymph, nymph.Comp);
|
||||
Dirty(gestalt);
|
||||
}
|
||||
|
||||
private void OnGestaltGib(Entity<DVGestaltComponent> ent, ref GibActionSystem.GibActionEvent args)
|
||||
{
|
||||
_popup.PopupPredicted(Loc.GetString(ent.Comp.PopupText, ("name", ent)), ent, ent);
|
||||
_gibbing.Gib(ent, user: args.Performer);
|
||||
}
|
||||
|
||||
private void OnGestaltBeingGibbed(Entity<DVGestaltComponent> ent, ref BeingGibbedEvent args)
|
||||
{
|
||||
args.Giblets.UnionWith(ent.Comp.StoredNymphs);
|
||||
}
|
||||
|
||||
private void OnGestaltGibbedBeforeDeletion(Entity<DVGestaltComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||
{
|
||||
foreach (var giblet in args.Giblets)
|
||||
{
|
||||
if (!TryComp<DVNymphMindMemoryComponent>(giblet, out var memory))
|
||||
continue;
|
||||
|
||||
if (!Exists(memory.Mind) || !TryComp<MindComponent>(memory.Mind, out var mindComponent))
|
||||
continue;
|
||||
|
||||
_mind.TransferTo(memory.Mind.Value, giblet, true, mind: mindComponent);
|
||||
}
|
||||
}
|
||||
|
||||
private bool DetermineProfile(
|
||||
Entity<DVGestaltComponent> ent,
|
||||
[NotNullWhen(true)] out DVNymphProfileComponent? profile)
|
||||
{
|
||||
profile = null;
|
||||
var nymphs = ent.Comp.StoredNymphs.ToList();
|
||||
if (nymphs.Count == 0)
|
||||
return false;
|
||||
|
||||
if (nymphs.Count == 1)
|
||||
{
|
||||
profile = Comp<DVNymphProfileComponent>(nymphs[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
var headProfile = Comp<DVNymphProfileComponent>(nymphs[0]);
|
||||
foreach (var nymph in nymphs.Skip(1))
|
||||
{
|
||||
var nymphProfile = Comp<DVNymphProfileComponent>(nymph);
|
||||
|
||||
if (nymphProfile.Name != headProfile.Name
|
||||
|| nymphProfile.Species != headProfile.Species
|
||||
|| nymphProfile.Gender != headProfile.Gender
|
||||
|| nymphProfile.Sex != headProfile.Sex
|
||||
|| nymphProfile.Age != headProfile.Age
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
|| nymphProfile.Height != headProfile.Height)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
profile = headProfile;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnGestaltReforming(Entity<DVGestaltComponent> ent, ref ReformSystem.ReformEvent args)
|
||||
{
|
||||
if (ent.Comp.NymphCount < ent.Comp.RequiredNymphs)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
if (!_net.IsServer)
|
||||
return;
|
||||
|
||||
var child = SpawnNextToOrDrop(ReformedPrototype, ent);
|
||||
if (_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
_mind.TransferTo(mindId, child, mind: mind);
|
||||
|
||||
if (DetermineProfile(ent, out var profile))
|
||||
{
|
||||
if (profile.Name is { } name)
|
||||
_metadata.SetEntityName(child, name);
|
||||
|
||||
_profile.ApplyProfileTo(child,
|
||||
new HumanoidCharacterProfile()
|
||||
.WithSpecies(profile.Species)
|
||||
.WithAge(profile.Age)
|
||||
.WithSex(profile.Sex)
|
||||
.WithHeight(profile.Height)
|
||||
.WithGender(profile.Gender)
|
||||
.WithHeight(profile.Height));
|
||||
|
||||
if (profile.OrganProfiles is { } profiles)
|
||||
_visualBody.ApplyProfiles(child, profiles);
|
||||
|
||||
if (profile.OrganMarkings is { } markings)
|
||||
_visualBody.ApplyMarkings(child, markings);
|
||||
}
|
||||
|
||||
var newComp = CopyComp(ent, child, ent.Comp);
|
||||
newComp.StoredNymphs.Clear();
|
||||
newComp.StoredNymphs.UnionWith(ent.Comp.StoredNymphs);
|
||||
var newMap = Comp<MapComponent>(newComp.NymphStorageMap);
|
||||
foreach (var nymph in ent.Comp.StoredNymphs)
|
||||
{
|
||||
var gestaltMember = Comp<DVGestaltMemberComponent>(nymph);
|
||||
gestaltMember.StoredInGestalt = child;
|
||||
_transform.SetMapCoordinates(nymph, new MapCoordinates(Vector2.Zero, newMap.MapId));
|
||||
}
|
||||
ent.Comp.StoredNymphs.Clear();
|
||||
_metadata.SetEntityName(ent.Comp.NymphStorageMap, $"Diona Gestalt Storage {ToPrettyString(ent)}");
|
||||
|
||||
QueueDel(ent);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(DVNymphRelationSystem))]
|
||||
public sealed partial class DVNymphFollowerComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? Lead;
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public readonly record struct DVNymphFollowerLeadGotChangedEvent;
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(DVNymphRelationSystem))]
|
||||
public sealed partial class DVNymphLeadComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<EntityUid> Followers = new();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVNymphMindMemoryComponent : Component
|
||||
{
|
||||
[DataField(serverOnly: true)]
|
||||
public EntityUid? Mind;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using Content.Shared.Body;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Markings;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Robust.Shared.Enums;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class DVNymphProfileComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public Dictionary<ProtoId<OrganCategoryPrototype>, OrganProfileData>? OrganProfiles;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Dictionary<ProtoId<OrganCategoryPrototype>, Dictionary<HumanoidVisualLayers, List<Marking>>>? OrganMarkings;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public string? Name;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public ProtoId<SpeciesPrototype> Species = "Diona";
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Gender Gender;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public Sex Sex;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public int Age = 18;
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public float Height = 1f;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
public sealed class DVNymphRelationSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVNymphLeadComponent, ComponentShutdown>(OnLeadShutdown);
|
||||
SubscribeLocalEvent<DVNymphFollowerComponent, ComponentShutdown>(OnFollowerShutdown);
|
||||
}
|
||||
|
||||
private void OnFollowerShutdown(Entity<DVNymphFollowerComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (ent.Comp.Lead is not { } nymph || !TryComp<DVNymphLeadComponent>(nymph, out var lead))
|
||||
return;
|
||||
|
||||
lead.Followers.Remove(ent);
|
||||
Dirty(nymph, lead);
|
||||
}
|
||||
|
||||
private void OnLeadShutdown(Entity<DVNymphLeadComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
foreach (var nymph in ent.Comp.Followers)
|
||||
{
|
||||
if (!TryComp<DVNymphFollowerComponent>(nymph, out var follower))
|
||||
continue;
|
||||
|
||||
follower.Lead = null;
|
||||
Dirty(nymph, follower);
|
||||
|
||||
var evt = new DVNymphFollowerLeadGotChangedEvent();
|
||||
RaiseLocalEvent(nymph, ref evt);
|
||||
}
|
||||
}
|
||||
|
||||
[PublicAPI]
|
||||
public void Follow(Entity<DVNymphLeadComponent?> leader, Entity<DVNymphFollowerComponent?> follower)
|
||||
{
|
||||
if (!Resolve(leader, ref leader.Comp) || !Resolve(follower, ref follower.Comp))
|
||||
return;
|
||||
|
||||
leader.Comp.Followers.Add(follower);
|
||||
follower.Comp.Lead = leader;
|
||||
|
||||
var evt = new DVNymphFollowerLeadGotChangedEvent();
|
||||
RaiseLocalEvent(follower, ref evt);
|
||||
|
||||
Dirty(leader, leader.Comp);
|
||||
Dirty(follower, follower.Comp);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVNymphingBodyComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The text that appears when attempting to split.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId PopupText = "diona-gib-action-use";
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
using Content.Shared.Gibbing;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Species;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
public sealed class DVNymphingBodySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly GibbingSystem _gibbing = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly DVNymphRelationSystem _nymph = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DVNymphingBodyComponent, GibActionSystem.GibActionEvent>(OnNymphingBodyGib);
|
||||
SubscribeLocalEvent<DVNymphingBodyComponent, GibbedBeforeDeletionEvent>(OnGibbedBeforeDeletion);
|
||||
}
|
||||
|
||||
private void OnNymphingBodyGib(Entity<DVNymphingBodyComponent> ent, ref GibActionSystem.GibActionEvent args)
|
||||
{
|
||||
_popup.PopupPredicted(Loc.GetString(ent.Comp.PopupText, ("name", ent)), ent, ent);
|
||||
_gibbing.Gib(ent, user: args.Performer);
|
||||
}
|
||||
|
||||
private void OnGibbedBeforeDeletion(Entity<DVNymphingBodyComponent> ent, ref GibbedBeforeDeletionEvent args)
|
||||
{
|
||||
EntityUid? leadGiblet = null;
|
||||
var leadMind = EntityUid.Invalid;
|
||||
|
||||
foreach (var giblet in args.Giblets)
|
||||
{
|
||||
if (!_mind.TryGetMind(giblet, out leadMind, out _))
|
||||
continue;
|
||||
|
||||
leadGiblet = giblet;
|
||||
break;
|
||||
}
|
||||
|
||||
if (leadGiblet is not { } leader || !TryComp<DVNymphLeadComponent>(leader, out var leaderComp))
|
||||
return;
|
||||
|
||||
if (TryComp<DVNymphMindMemoryComponent>(leader, out var memory) && Exists(leadMind))
|
||||
{
|
||||
memory.Mind = leadMind;
|
||||
}
|
||||
|
||||
foreach (var giblet in args.Giblets)
|
||||
{
|
||||
if (!TryComp<DVNymphFollowerComponent>(giblet, out var follower))
|
||||
continue;
|
||||
|
||||
_nymph.Follow((leader, leaderComp), (giblet, follower));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._DV.Diona;
|
||||
|
||||
/// <summary>
|
||||
/// Component that will cause an organ to turn into a nymph when removed from its body.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DVNymphingOrganComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The entity to replace the organ with.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public EntProtoId EntityPrototype;
|
||||
|
||||
/// <summary>
|
||||
/// Whether to transfer the mind to this new entity.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool TransferMind;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
nymph-name-prefix = {$baseName} ({$identityName})
|
||||
|
|
@ -165,10 +165,18 @@
|
|||
- type: IgniteOnHeatDamage
|
||||
fireStacks: 1
|
||||
threshold: 12
|
||||
- type: GibAction
|
||||
actionPrototype: DionaGibAction
|
||||
allowedStates:
|
||||
- Dead
|
||||
# Begin DeltaV Changes - gib at will
|
||||
# - type: GibAction
|
||||
# actionPrototype: DionaGibAction
|
||||
# allowedStates:
|
||||
# - Alive
|
||||
# - Critical
|
||||
# - Dead
|
||||
- type: DVNymphingBody
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- DVDionaGibAction
|
||||
# End DeltaV Changes - gib at will
|
||||
- type: Rootable
|
||||
- type: MovementSpeedModifier # DeltaV
|
||||
baseWalkSpeed: 1.0
|
||||
|
|
@ -284,11 +292,20 @@
|
|||
- type: entity
|
||||
parent: [ OrganBaseBrain, OrganDionaInternal ]
|
||||
id: OrganDionaBrain
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
components:
|
||||
- type: GibbableOrgan
|
||||
active: false
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
|
||||
- type: entity
|
||||
parent: [ OrganDionaVisual, OrganBaseEyes, OrganDionaInternal ]
|
||||
id: OrganDionaEyes
|
||||
components:
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
- type: GibbableOrgan
|
||||
active: false
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
- type: VisualOrgan
|
||||
data:
|
||||
sprite: Mobs/Customization/eyes.rsi
|
||||
|
|
@ -298,6 +315,10 @@
|
|||
parent: [ OrganBaseLungs, OrganDionaInternal, OrganDionaMetabolizer ]
|
||||
id: OrganDionaLungs
|
||||
components:
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
- type: GibbableOrgan
|
||||
active: false
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: lungs
|
||||
|
|
@ -306,6 +327,10 @@
|
|||
parent: [ OrganBaseStomach, OrganDionaInternal, OrganDionaMetabolizer ]
|
||||
id: OrganDionaStomach
|
||||
components:
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
- type: GibbableOrgan
|
||||
active: false
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
- type: Metabolizer
|
||||
maxReagents: 6
|
||||
stages: [ Digestion, Bloodstream, Metabolites ]
|
||||
|
|
@ -315,7 +340,11 @@
|
|||
suffix: "Diona, Nymphing"
|
||||
id: OrganDionaBrainNymphing
|
||||
components:
|
||||
- type: Nymph
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
- type: GibbableOrgan
|
||||
active: true
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
- type: DVNymphingOrgan # DeltaV - new diona mechanics
|
||||
transferMind: true
|
||||
entityPrototype: OrganDionaNymphBrain
|
||||
|
||||
|
|
@ -324,7 +353,11 @@
|
|||
suffix: "Diona, Nymphing"
|
||||
id: OrganDionaLungsNymphing
|
||||
components:
|
||||
- type: Nymph
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
- type: GibbableOrgan
|
||||
active: true
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
- type: DVNymphingOrgan # DeltaV - new diona mechanics
|
||||
entityPrototype: OrganDionaNymphLungs
|
||||
|
||||
- type: entity
|
||||
|
|
@ -332,57 +365,64 @@
|
|||
suffix: "Diona, Nymphing"
|
||||
id: OrganDionaStomachNymphing
|
||||
components:
|
||||
- type: Nymph
|
||||
# Begin DeltaV - diona nymphing overhaul
|
||||
- type: GibbableOrgan
|
||||
active: true
|
||||
# End DeltaV - diona nymphing overhaul
|
||||
- type: DVNymphingOrgan # DeltaV - new diona mechanics
|
||||
entityPrototype: OrganDionaNymphStomach
|
||||
|
||||
- type: entity
|
||||
parent: MobDionaNymph
|
||||
parent: DVMobDionaNymph # DeltaV - new diona mechanics
|
||||
id: OrganDionaNymphBrain
|
||||
suffix: brain
|
||||
components:
|
||||
- type: IsDeadIC
|
||||
- type: EntityTableContainerFill
|
||||
containers:
|
||||
body_organs: !type:AllSelector
|
||||
children:
|
||||
- id: OrganDionaBrain
|
||||
- id: OrganAnimalLungs
|
||||
- id: OrganAnimalStomach
|
||||
- id: OrganAnimalLiver
|
||||
- id: OrganAnimalHeart
|
||||
- id: OrganAnimalKidneys
|
||||
# - type: EntityTableContainerFill
|
||||
# containers:
|
||||
# body_organs: !type:AllSelector
|
||||
# children:
|
||||
# - id: OrganDionaBrain
|
||||
# - id: OrganAnimalLungs
|
||||
# - id: OrganAnimalStomach
|
||||
# - id: OrganAnimalLiver
|
||||
# - id: OrganAnimalHeart
|
||||
# - id: OrganAnimalKidneys
|
||||
# End DeltaV - we have a uniform organ configuration
|
||||
|
||||
- type: entity
|
||||
parent: MobDionaNymph
|
||||
parent: DVMobDionaNymph # DeltaV - new diona mechanics
|
||||
id: OrganDionaNymphStomach
|
||||
suffix: stomach
|
||||
components:
|
||||
- type: IsDeadIC
|
||||
- type: EntityTableContainerFill
|
||||
containers:
|
||||
body_organs: !type:AllSelector
|
||||
children:
|
||||
- id: OrganDionaLungs
|
||||
- id: OrganAnimalStomach
|
||||
- id: OrganAnimalLiver
|
||||
- id: OrganAnimalHeart
|
||||
- id: OrganAnimalKidneys
|
||||
# - type: EntityTableContainerFill
|
||||
# containers:
|
||||
# body_organs: !type:AllSelector
|
||||
# children:
|
||||
# - id: OrganDionaLungs
|
||||
# - id: OrganAnimalStomach
|
||||
# - id: OrganAnimalLiver
|
||||
# - id: OrganAnimalHeart
|
||||
# - id: OrganAnimalKidneys
|
||||
# End DeltaV - we have a uniform organ configuration
|
||||
|
||||
- type: entity
|
||||
parent: MobDionaNymph
|
||||
parent: DVMobDionaNymph # DeltaV - new diona mechanics
|
||||
id: OrganDionaNymphLungs
|
||||
suffix: lungs
|
||||
components:
|
||||
- type: IsDeadIC
|
||||
- type: EntityTableContainerFill
|
||||
containers:
|
||||
body_organs: !type:AllSelector
|
||||
children:
|
||||
- id: OrganAnimalLungs
|
||||
- id: OrganDionaStomach
|
||||
- id: OrganAnimalLiver
|
||||
- id: OrganAnimalHeart
|
||||
- id: OrganAnimalKidneys
|
||||
# - type: EntityTableContainerFill
|
||||
# containers:
|
||||
# body_organs: !type:AllSelector
|
||||
# children:
|
||||
# - id: OrganAnimalLungs
|
||||
# - id: OrganDionaStomach
|
||||
# - id: OrganAnimalLiver
|
||||
# - id: OrganAnimalHeart
|
||||
# - id: OrganAnimalKidneys
|
||||
# End DeltaV - we have a uniform organ configuration
|
||||
|
||||
- type: entity
|
||||
parent: MobDiona
|
||||
|
|
@ -391,3 +431,21 @@
|
|||
components:
|
||||
- type: IsDeadIC
|
||||
- type: RandomHumanoidAppearance
|
||||
# Begin DeltaV - diona nymph overhaul
|
||||
- type: InitialBody
|
||||
organs:
|
||||
Torso: OrganDionaTorso
|
||||
Head: OrganDionaHead
|
||||
ArmLeft: OrganDionaArmLeft
|
||||
ArmRight: OrganDionaArmRight
|
||||
HandRight: OrganDionaHandRight
|
||||
HandLeft: OrganDionaHandLeft
|
||||
LegLeft: OrganDionaLegLeft
|
||||
LegRight: OrganDionaLegRight
|
||||
FootLeft: OrganDionaFootLeft
|
||||
FootRight: OrganDionaFootRight
|
||||
Brain: OrganDionaBrain
|
||||
Eyes: OrganDionaEyes
|
||||
Lungs: OrganDionaLungs
|
||||
Stomach: OrganDionaStomach
|
||||
# End DeltaV - diona nymph overhaul
|
||||
|
|
@ -3865,9 +3865,10 @@
|
|||
task: RuminantCompound
|
||||
|
||||
- type: entity
|
||||
abstract: true # DeltaV - we don't use this prototype
|
||||
name: diona nymph
|
||||
parent: [BaseMobAnimal, SimpleMobBase, StripableInventoryBase, DVNodeCrawler]
|
||||
id: MobDionaNymph
|
||||
parent: [BaseMobAnimal, SimpleMobBase, StripableInventoryBase]
|
||||
id: MobDionaNymphUnused # DeltaV - we don't use this prototype
|
||||
description: It's like a cat, only.... branch-ier.
|
||||
components:
|
||||
- type: Sprite
|
||||
|
|
@ -3876,26 +3877,6 @@
|
|||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: nymph
|
||||
sprite: Mobs/Animals/nymph.rsi
|
||||
# DeltaV changes begin
|
||||
- type: Carriable
|
||||
- type: GhostRole
|
||||
makeSentient: true
|
||||
allowSpeech: true
|
||||
allowMovement: true
|
||||
name: ghost-role-information-nymph-name
|
||||
description: ghost-role-information-nymph-description
|
||||
rules: ghost-role-information-nonantagonist-rules
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: IntrinsicRadioReceiver
|
||||
- type: IntrinsicRadioTransmitter
|
||||
channels:
|
||||
- Rootsong
|
||||
- type: ActiveRadio
|
||||
channels:
|
||||
- Rootsong
|
||||
- type: TypingIndicator
|
||||
proto: diona
|
||||
# DeltaV changes end
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
|
|
@ -3924,8 +3905,8 @@
|
|||
Base: nymph_sleep
|
||||
Dead:
|
||||
Base: nymph_dead
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- type: ToolRefinable
|
||||
refineResult:
|
||||
- id: MaterialWoodPlank1
|
||||
amount: 2
|
||||
- type: InteractionPopup
|
||||
|
|
@ -3966,27 +3947,11 @@
|
|||
reformTime: 10
|
||||
popupText: diona-reform-attempt
|
||||
reformPrototype: MobDionaReformed
|
||||
- type: LightReactive # DeltaV
|
||||
manual: true
|
||||
- type: LightLevelHealth # DeltaV
|
||||
darkThreshold: 0.4
|
||||
lightThreshold: 1.2
|
||||
darkDamage:
|
||||
types:
|
||||
Heat: 1.0
|
||||
lightDamage:
|
||||
types:
|
||||
Blunt: -0.1
|
||||
Piercing: -0.1
|
||||
Slash: -0.1
|
||||
Heat: -0.1
|
||||
Poison: -0.1
|
||||
Asphyxiation: -0.1
|
||||
darkMovementSpeedMultiplier: 0.7
|
||||
|
||||
- type: entity
|
||||
parent: MobDionaNymph
|
||||
id: MobDionaNymphAccent # No talky. For non-brain & wild nymphs
|
||||
abstract: true # DeltaV - we don't use this prototype
|
||||
parent: MobDionaNymphUnused # DeltaV - we don't use this prototype
|
||||
id: MobDionaNymphAccentUnused # No talky. For non-brain & wild nymphs # DeltaV - we don't use this prototype
|
||||
suffix: Accent
|
||||
components:
|
||||
- type: ReplacementAccent
|
||||
|
|
|
|||
|
|
@ -146,14 +146,33 @@
|
|||
Asphyxiation: 1
|
||||
Heat: 2
|
||||
Poison: 1
|
||||
- !type:Polymorph
|
||||
prototype: TreeMorph
|
||||
# Begin DeltaV changes - robust harvest OD makes more nymphs, not treemorph
|
||||
- !type:SpawnEntity
|
||||
entity: DVDionaNymphDeferredSpawn # deferred spawn to prevent crash from spawning a new metabolizer during metabolism
|
||||
conditions:
|
||||
- !type:MetabolizerTypeCondition
|
||||
type: [Plant]
|
||||
- !type:ReagentCondition
|
||||
reagent: RobustHarvest
|
||||
min: 80
|
||||
- !type:MetabolizerTypeCondition
|
||||
type: [Plant]
|
||||
- !type:ReagentCondition
|
||||
reagent: RobustHarvest
|
||||
min: 40
|
||||
- !type:AdjustReagent
|
||||
reagent: RobustHarvest
|
||||
amount: -20
|
||||
conditions:
|
||||
- !type:MetabolizerTypeCondition
|
||||
type: [Plant]
|
||||
- !type:ReagentCondition
|
||||
reagent: RobustHarvest
|
||||
min: 40
|
||||
# - !type:Polymorph
|
||||
# prototype: TreeMorph
|
||||
# conditions:
|
||||
# - !type:MetabolizerTypeCondition
|
||||
# type: [Plant]
|
||||
# - !type:ReagentCondition
|
||||
# reagent: RobustHarvest
|
||||
# min: 80
|
||||
# End DeltaV changes - robust harvest OD makes more nymphs, not treemorph
|
||||
|
||||
- type: reagent
|
||||
id: Sedin
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
- type: entity
|
||||
parent: BaseAction
|
||||
id: DVDionaAssimilateAction
|
||||
name: Assimilate
|
||||
description: Assimilate with another nymph.
|
||||
components:
|
||||
- type: Action
|
||||
icon:
|
||||
sprite: _DV/Mobs/Species/Diona/gestalt.rsi
|
||||
state: gestalt
|
||||
- type: TargetAction
|
||||
- type: EntityTargetAction
|
||||
event: !type:DVAssimilateNymphActionEvent
|
||||
|
||||
- type: entity
|
||||
parent: BaseSuicideAction
|
||||
id: DVDionaGibAction
|
||||
name: Split up
|
||||
description: Dissolve your gestalt and split apart.
|
||||
components:
|
||||
- type: Action
|
||||
icon:
|
||||
sprite: _DV/Mobs/Species/Diona/gestalt.rsi
|
||||
state: nymph
|
||||
- type: InstantAction
|
||||
event: !type:GibActionEvent
|
||||
|
||||
- type: entity
|
||||
parent: BaseAction
|
||||
id: DVDionaReformAction
|
||||
name: Assume Humanoid Form
|
||||
description: Assume a humanoid form. Requires three nymphs.
|
||||
components:
|
||||
- type: Action
|
||||
icon:
|
||||
sprite: Mobs/Species/Diona/parts.rsi
|
||||
state: full
|
||||
- type: InstantAction
|
||||
event: !type:ReformEvent
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
- type: entity
|
||||
abstract: true
|
||||
id: DVDionaMixin
|
||||
components:
|
||||
- type: IntrinsicRadioReceiver
|
||||
- type: IntrinsicRadioTransmitter
|
||||
channels:
|
||||
- Rootsong
|
||||
- type: ActiveRadio
|
||||
channels:
|
||||
- Rootsong
|
||||
- type: TypingIndicator
|
||||
proto: diona
|
||||
- type: Grammar
|
||||
attributes:
|
||||
gender: epicene
|
||||
- type: Speech
|
||||
speechVerb: Plant
|
||||
speechSounds: Alto
|
||||
allowedEmotes: ['Chirp']
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: UnisexDiona
|
||||
Female: UnisexDiona
|
||||
Unsexed: UnisexDiona
|
||||
- type: Emoting
|
||||
- type: BodyEmotes
|
||||
soundsId: Nymph
|
||||
- type: LightReactive # DeltaV
|
||||
manual: true
|
||||
- type: LightLevelHealth # DeltaV
|
||||
darkThreshold: 0.4
|
||||
lightThreshold: 1.2
|
||||
darkDamage:
|
||||
types:
|
||||
Heat: 1.0
|
||||
lightDamage:
|
||||
types:
|
||||
Blunt: -0.1
|
||||
Piercing: -0.1
|
||||
Slash: -0.1
|
||||
Heat: -0.1
|
||||
Poison: -0.1
|
||||
Asphyxiation: -0.1
|
||||
darkMovementSpeedMultiplier: 0.7
|
||||
- type: EntityTableContainerFill
|
||||
containers:
|
||||
body_organs: !type:AllSelector
|
||||
children:
|
||||
- id: OrganDionaBrain
|
||||
- id: OrganDionaLungs
|
||||
- id: OrganDionaStomach
|
||||
- type: Bloodstream
|
||||
bloodReferenceSolution:
|
||||
reagents:
|
||||
- ReagentId: Sap
|
||||
Quantity: 60
|
||||
|
||||
- type: entity
|
||||
parent: [DVDionaMixin, BaseMobAnimal, SimpleMobBase, StripableInventoryBase, DVNodeCrawler]
|
||||
id: DVMobDionaNymph
|
||||
name: diona nymph
|
||||
description: It's a little skittery critter. Chirp.
|
||||
components:
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
sprite: _DV/Mobs/Species/Diona/gestalt.rsi
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: nymph
|
||||
- state: eyes_nymph
|
||||
shader: unshaded
|
||||
- type: DVNymphLead
|
||||
- type: DVNymphFollower
|
||||
- type: DVNymphProfile
|
||||
- type: DVGestaltMember
|
||||
- type: DVNymphMindMemory
|
||||
- type: HTN
|
||||
rootTask:
|
||||
task: DVNymphCompound
|
||||
blackboard:
|
||||
IdleRange: !type:Single
|
||||
2.5
|
||||
FollowCloseRange: !type:Single
|
||||
1.0
|
||||
FollowRange: !type:Single
|
||||
2.0
|
||||
- type: Clothing
|
||||
quickEquip: false
|
||||
sprite: _DV/Mobs/Species/Diona/gestalt.rsi
|
||||
slots:
|
||||
- HEAD
|
||||
- NECK
|
||||
- type: Item
|
||||
size: Normal
|
||||
sprite: _DV/Mobs/Species/Diona/gestalt.rsi
|
||||
inhandVisuals:
|
||||
left:
|
||||
- state: inhand-left
|
||||
right:
|
||||
- state: inhand-right
|
||||
- type: Physics
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeCircle
|
||||
radius: 0.35
|
||||
density: 100 # High, because wood is heavy.
|
||||
mask:
|
||||
- MobMask
|
||||
layer:
|
||||
- MobLayer
|
||||
- type: Inventory
|
||||
speciesId: cat
|
||||
templateId: pet
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
Base: nymph
|
||||
Critical:
|
||||
Base: nymph_sleep
|
||||
Dead:
|
||||
Base: nymph_dead
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: MaterialWoodPlank1
|
||||
amount: 2
|
||||
- type: InteractionPopup
|
||||
successChance: 0.7
|
||||
interactSuccessString: petting-success-nymph
|
||||
interactFailureString: petting-failure-nymph
|
||||
interactSuccessSound:
|
||||
path: /Audio/Animals/nymph_chirp.ogg
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
30: Critical
|
||||
60: Dead
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 2.5
|
||||
baseSprintSpeed : 4.5
|
||||
- type: Tag
|
||||
tags:
|
||||
- DoorBumpOpener
|
||||
- VimPilot
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- DVDionaAssimilateAction
|
||||
|
||||
- type: entity
|
||||
parent: [DVDionaMixin, BaseMobAnimal, SimpleMobBase]
|
||||
id: DVMobDionaGestalt
|
||||
name: nascent diona gestalt
|
||||
description: A heaving mass of nymphs. Chirp?
|
||||
components:
|
||||
- type: DVGestalt
|
||||
- type: ComplexInteraction
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed : 1.0
|
||||
baseSprintSpeed : 1.0
|
||||
- type: Sprite
|
||||
drawdepth: Mobs
|
||||
sprite: _DV/Mobs/Species/Diona/gestalt.rsi
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: gestalt
|
||||
- state: eyes_gestalt
|
||||
shader: unshaded
|
||||
- type: ActionGrant
|
||||
actions:
|
||||
- DVDionaAssimilateAction
|
||||
- DVDionaGibAction
|
||||
- DVDionaReformAction
|
||||
|
||||
|
||||
- type: entity
|
||||
id: DVDionaNymphDeferredSpawn
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: TimedSpawner
|
||||
prototypes:
|
||||
- DVMobDionaNymph
|
||||
intervalSeconds: 1
|
||||
minimumEntitiesSpawned: 1
|
||||
maximumEntitiesSpawned: 1
|
||||
- type: TimedDespawn
|
||||
lifetime: 2
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
- type: htnCompound
|
||||
id: DVNymphCompound
|
||||
branches:
|
||||
# - preconditions:
|
||||
# - !type:HasOrdersPrecondition
|
||||
# orders: enum.RatKingOrderType.Stay
|
||||
# tasks:
|
||||
# - !type:HTNCompoundTask
|
||||
# task: IdleCompound
|
||||
# - preconditions:
|
||||
# - !type:HasOrdersPrecondition
|
||||
# orders: enum.RatKingOrderType.Follow
|
||||
- tasks:
|
||||
- !type:HTNCompoundTask
|
||||
task: FollowCompound
|
||||
# - preconditions:
|
||||
# - !type:HasOrdersPrecondition
|
||||
# orders: enum.RatKingOrderType.CheeseEm
|
||||
# tasks:
|
||||
# - !type:HTNCompoundTask
|
||||
# task: RatServantTargetAttackCompound
|
||||
# - preconditions:
|
||||
# - !type:HasOrdersPrecondition
|
||||
# orders: enum.RatKingOrderType.Loose
|
||||
# tasks:
|
||||
# - !type:HTNCompoundTask
|
||||
# task: SimpleHostileCompound
|
||||
|
|
@ -34,6 +34,6 @@
|
|||
- MindRoleGhostRoleFreeAgentHarmless
|
||||
|
||||
- type: dvSpawnableGhostRole
|
||||
id: MobDionaNymph
|
||||
entity: MobDionaNymph
|
||||
id: DVMobDionaNymph
|
||||
entity: DVMobDionaNymph
|
||||
rules: ghost-role-information-nonantagonist-rules
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 943 B |
|
After Width: | Height: | Size: 791 B |
|
After Width: | Height: | Size: 868 B |
|
After Width: | Height: | Size: 815 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 811 B |
|
After Width: | Height: | Size: 915 B |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 618 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1020 B |
|
After Width: | Height: | Size: 953 B |
|
After Width: | Height: | Size: 944 B |
|
After Width: | Height: | Size: 606 B |
|
After Width: | Height: | Size: 695 B |
|
After Width: | Height: | Size: 700 B |
|
After Width: | Height: | Size: 748 B |
|
After Width: | Height: | Size: 786 B |
|
|
@ -0,0 +1,304 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from https://github.com/Baystation12/Baystation12/blob/2753dca5a7a85d18a8c51b176cd6fd61f0e64d70/icons/mob/gestalt.dmi",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "nymph",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyes_nymph",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "nymph_sleep",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "nymph_dead"
|
||||
},
|
||||
{
|
||||
"name": "gestalt",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "eyes_gestalt",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.5,
|
||||
0.5,
|
||||
0.5
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "wall"
|
||||
},
|
||||
{
|
||||
"name": "floor"
|
||||
},
|
||||
{
|
||||
"name": "flower_back",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "flower_fore",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "intent_expel"
|
||||
},
|
||||
{
|
||||
"name": "intent_devour"
|
||||
},
|
||||
{
|
||||
"name": "health0"
|
||||
},
|
||||
{
|
||||
"name": "health1"
|
||||
},
|
||||
{
|
||||
"name": "health2"
|
||||
},
|
||||
{
|
||||
"name": "health3"
|
||||
},
|
||||
{
|
||||
"name": "health4"
|
||||
},
|
||||
{
|
||||
"name": "health5"
|
||||
},
|
||||
{
|
||||
"name": "health6"
|
||||
},
|
||||
{
|
||||
"name": "health7"
|
||||
},
|
||||
{
|
||||
"name": "held"
|
||||
},
|
||||
{
|
||||
"name": "hat"
|
||||
},
|
||||
{
|
||||
"name": "equipped-HELMET",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "equipped-NECK",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-left",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "inhand-right",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 655 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |