Xenomorphs: Part 3 (#815)

* this is definitely one of the commits

* 1

* new facehuggers

* suffix

* Burst egg

* some fix

* Update Content.Server/_White/Xenomorphs/Queen/XenomorphQueenSystem.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update Content.Server/_White/Xenomorphs/Queen/XenomorphQueenSystem.cs

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update Resources/Locale/en-US/_white/objectives/conditions/steal-target-groups.ftl

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs

* Update Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs

* Update Resources/Locale/ru-RU/_white/prototypes/entities/mobs/player/pets.ftl

* Update Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/storage/glass_box.ftl

* Update Resources/Locale/ru-RU/_white/objectives/conditions/steal-target-groups.ftl

* Update Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs

* some fix

* SelfUnBuckleDelay

* Neurotoxin now stun

* PlasmaAmmoProvider

* some fix

* fix

* some number

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Spatison
2025-08-30 22:40:47 +03:00
committed by GitHub
parent 7b502a53fc
commit bafdcfa459
82 changed files with 988 additions and 257 deletions

View File

@@ -1,3 +1,4 @@
using Content.Client.Alerts;
using Content.Shared.Pinpointer;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
@@ -8,6 +9,32 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
{
[Dependency] private readonly IEyeManager _eyeManager = default!;
// WD EDIT START
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PinpointerComponent, UpdateAlertSpriteEvent>(OnUpdateAlertSprite);
}
private void OnUpdateAlertSprite(EntityUid uid, PinpointerComponent component, ref UpdateAlertSpriteEvent args)
{
if (args.Alert.ID != component.Alert)
return;
var sprite = args.SpriteViewEnt.Comp;
var eye = _eyeManager.CurrentEye;
var angle = component.DistanceToTarget switch
{
Distance.Close or Distance.Medium or Distance.Far => component.ArrowAngle + eye.Rotation,
_ => Angle.Zero
};
sprite.LayerSetRotation(PinpointerLayers.Screen, angle);
sprite.LayerSetState(PinpointerLayers.Screen, component.DistanceToTarget.ToString().ToLower());
}
// WD EDIT END
public override void Update(float frameTime)
{
base.Update(frameTime);
@@ -20,7 +47,7 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
var query = EntityQueryEnumerator<PinpointerComponent, SpriteComponent>();
while (query.MoveNext(out var _, out var pinpointer, out var sprite))
{
if (!pinpointer.HasTarget)
if (!pinpointer.HasTarget || !sprite.LayerExists(PinpointerLayers.Screen)) // WD EDIT
continue;
var eye = _eyeManager.CurrentEye;
var angle = pinpointer.ArrowAngle + eye.Rotation;

View File

@@ -1,5 +0,0 @@
using Content.Shared._White.Inventory;
namespace Content.Client._White.Inventory;
public sealed class WhiteInventorySystem : SharedWhiteInventorySystem;

View File

@@ -68,6 +68,9 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
private void OnTakeGhostRole(Entity<GhostRoleAntagSpawnerComponent> ent, ref TakeGhostRoleEvent args)
{
if (args.TookRole)
return;
if (ent.Comp.Rule is not { } rule || ent.Comp.Definition is not { } def)
return;

View File

@@ -4,12 +4,14 @@ using System.Linq;
using System.Numerics;
using Robust.Shared.Utility;
using Content.Server.Shuttles.Events;
using Content.Shared.Alert;
using Content.Shared.IdentityManagement;
namespace Content.Server.Pinpointer;
public sealed class PinpointerSystem : SharedPinpointerSystem
{
[Dependency] private readonly AlertsSystem _alerts = default!; // WD EDIT
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
@@ -20,10 +22,28 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
base.Initialize();
_xformQuery = GetEntityQuery<TransformComponent>();
// WD EDIT START
SubscribeLocalEvent<PinpointerComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<PinpointerComponent, ComponentShutdown>(OnShutdown);
// WD EDIT END
SubscribeLocalEvent<PinpointerComponent, ActivateInWorldEvent>(OnActivate);
SubscribeLocalEvent<FTLCompletedEvent>(OnLocateTarget);
}
// WD EDIT START
private void OnMapInit(EntityUid uid, PinpointerComponent component, MapInitEvent args)
{
if (component.Alert.HasValue)
_alerts.ShowAlert(uid, component.Alert.Value);
}
private void OnShutdown(EntityUid uid, PinpointerComponent component, ComponentShutdown args)
{
if (component.Alert.HasValue)
_alerts.ClearAlert(uid, component.Alert.Value);
}
// WD EDIT END
public override bool TogglePinpointer(EntityUid uid, PinpointerComponent? pinpointer = null)
{
if (!Resolve(uid, ref pinpointer))
@@ -48,7 +68,8 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
if (args.Handled || !args.Complex)
return;
TogglePinpointer(uid, component);
if (component.CanToggle) // WD EDIT
TogglePinpointer(uid, component);
if (!component.CanRetarget)
LocateTarget(uid, component);
@@ -147,6 +168,7 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
if (target == null || !EntityManager.EntityExists(target.Value))
{
SetDistance(uid, Distance.Unknown, pinpointer);
LocateTarget(uid, pinpointer); // WD EDIT
return;
}

View File

@@ -1,9 +1,8 @@
using Content.Server.DoAfter;
using Content.Shared._White.Actions.Events;
using Content.Shared.Construction.EntitySystems;
using Content.Shared.Coordinates;
using Content.Shared.DoAfter;
using Content.Shared.Maps;
using Content.Shared.Physics;
using Robust.Server.Audio;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
@@ -16,15 +15,14 @@ namespace Content.Server._White.Actions;
public sealed class ActionsSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDef = default!;
[Dependency] private readonly AnchorableSystem _anchorable = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly MapSystem _mapSystem = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly TurfSystem _turf = default!;
public override void Initialize()
{
@@ -36,7 +34,7 @@ public sealed class ActionsSystem : EntitySystem
private void OnSpawnTileEntityAction(SpawnTileEntityActionEvent args)
{
if (args.Handled || !CreationTileEntity(args.Performer, args.Performer.ToCoordinates(), args.TileId, args.Entity, args.Audio, args.BlockedCollision))
if (args.Handled || !CreationTileEntity(args.Performer, args.Performer.ToCoordinates(), args.TileId, args.Entity, args.Audio, args.BlockedCollisionLayer, args.BlockedCollisionMask))
return;
args.Handled = true;
@@ -49,7 +47,7 @@ public sealed class ActionsSystem : EntitySystem
if (args.Length != 0)
{
if (CheckTileBlocked(args.Target, args.BlockedCollision))
if (CheckTileBlocked(args.Target, args.BlockedCollisionLayer, args.BlockedCollisionMask))
return;
var ev = new PlaceTileEntityDoAfterEvent
@@ -57,7 +55,9 @@ public sealed class ActionsSystem : EntitySystem
Target = GetNetCoordinates(args.Target),
Entity = args.Entity,
TileId = args.TileId,
Audio = args.Audio
Audio = args.Audio,
BlockedCollisionLayer = args.BlockedCollisionLayer,
BlockedCollisionMask = args.BlockedCollisionMask
};
var doAfter = new DoAfterArgs(EntityManager, args.Performer, args.Length, ev, null)
@@ -73,7 +73,7 @@ public sealed class ActionsSystem : EntitySystem
return;
}
if (!CreationTileEntity(args.Performer, args.Target, args.TileId, args.Entity, args.Audio, args.BlockedCollision))
if (!CreationTileEntity(args.Performer, args.Target, args.TileId, args.Entity, args.Audio, args.BlockedCollisionLayer, args.BlockedCollisionMask))
return;
args.Handled = true;
@@ -81,7 +81,7 @@ public sealed class ActionsSystem : EntitySystem
private void OnPlaceTileEntityDoAfter(PlaceTileEntityDoAfterEvent args)
{
if (args.Handled || !CreationTileEntity(args.User, GetCoordinates(args.Target), args.TileId, args.Entity, args.Audio, null))
if (args.Handled || !CreationTileEntity(args.User, GetCoordinates(args.Target), args.TileId, args.Entity, args.Audio, args.BlockedCollisionLayer, args.BlockedCollisionMask))
return;
args.Handled = true;
@@ -89,7 +89,7 @@ public sealed class ActionsSystem : EntitySystem
#region Helpers
private bool CreationTileEntity(EntityUid user, EntityCoordinates coordinates, string? tileId, EntProtoId? entProtoId, SoundSpecifier? audio, CollisionGroup? blockedCollision)
private bool CreationTileEntity(EntityUid user, EntityCoordinates coordinates, string? tileId, EntProtoId? entProtoId, SoundSpecifier? audio, int collisionLayer = 0, int collisionMask = 0)
{
if (_container.IsEntityOrParentInContainer(user))
return false;
@@ -107,7 +107,7 @@ public sealed class ActionsSystem : EntitySystem
_audio.PlayPvs(audio, coordinates);
if (entProtoId == null || CheckTileBlocked(coordinates, blockedCollision))
if (entProtoId == null || CheckTileBlocked(coordinates, collisionLayer, collisionMask))
return false;
Spawn(entProtoId, coordinates);
@@ -115,11 +115,13 @@ public sealed class ActionsSystem : EntitySystem
return true;
}
private bool CheckTileBlocked(EntityCoordinates coordinates, CollisionGroup? blockedCollision)
private bool CheckTileBlocked(EntityCoordinates coordinates, int collisionLayer = 0, int collisionMask = 0)
{
var tileRef = coordinates.GetTileRef(EntityManager, _mapManager);
if (_transform.GetGrid(coordinates) is not { } grid || !TryComp(grid, out MapGridComponent? mapGrid))
return true;
return !tileRef.HasValue || blockedCollision.HasValue && _turf.IsTileBlocked(tileRef.Value, blockedCollision.Value);
var tileIndices = _mapSystem.TileIndicesFor(grid, mapGrid, coordinates);
return !_anchorable.TileFree(mapGrid, tileIndices, collisionLayer, collisionMask);
}
#endregion

View File

@@ -1,17 +0,0 @@
using Content.Shared.EntityEffects;
using Content.Shared.Whitelist;
namespace Content.Server._White.Inventory.Components;
[RegisterComponent]
public sealed partial class EffectsOnEquipComponent : Component
{
[DataField(required: true)]
public string Slot;
[DataField]
public List<EntityEffect> Effects = new ();
[DataField]
public EntityWhitelist? Blacklist;
}

View File

@@ -1,30 +0,0 @@
using Content.Server._White.Inventory.Components;
using Content.Shared.EntityEffects;
using Content.Shared.Inventory.Events;
using Content.Shared.Mobs.Systems;
using Content.Shared.Whitelist;
namespace Content.Server._White.Inventory;
public sealed partial class WhiteInventorySystem
{
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
private void InitializeEquip()
{
SubscribeLocalEvent<EffectsOnEquipComponent, GotEquippedEvent>(OnGotEquipped);
}
private void OnGotEquipped(EntityUid uid, EffectsOnEquipComponent component, GotEquippedEvent args)
{
if (args.Slot != component.Slot
|| !_mobState.IsAlive(uid)
|| _entityWhitelist.IsBlacklistPass(component.Blacklist, args.Equipee))
return;
var effectsArgs = new EntityEffectBaseArgs(args.Equipee, EntityManager);
foreach (var effect in component.Effects)
effect.Effect(effectsArgs);
}
}

View File

@@ -1,13 +0,0 @@
using Content.Shared._White.Inventory;
namespace Content.Server._White.Inventory;
public sealed partial class WhiteInventorySystem : SharedWhiteInventorySystem
{
public override void Initialize()
{
base.Initialize();
InitializeEquip();
}
}

View File

@@ -1,4 +1,4 @@
using Content.Server._White.Inventory;
using Content.Server._White.Xenomorphs.FaceHugger;
using Content.Server.Popups;
using Content.Shared._White.Inventory.Components;
using Content.Shared._White.Xenomorphs.Egg;
@@ -22,8 +22,8 @@ public sealed class XenomorphEggSystem : EntitySystem
[Dependency] private readonly AppearanceSystem _appearance = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly FaceHuggerSystem _faceHugger = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly WhiteInventorySystem _whiteInventory = default!;
public override void Initialize()
{
@@ -114,12 +114,12 @@ public sealed class XenomorphEggSystem : EntitySystem
var coordinates = Transform(uid).Coordinates;
var spawned = Spawn(component.FaceHuggerPrototype, coordinates);
if (!TryComp<EquipOnMeleeHitComponent>(spawned, out var equipOn))
if (!TryComp<FaceHuggerComponent>(spawned, out var equipOn))
return;
foreach (var entity in _entityLookup.GetEntitiesInRange<InventoryComponent>(coordinates, component.BurstRange))
{
if (_whiteInventory.TryEquip(spawned, entity, equipOn))
if (_faceHugger.TryEquipFaceHugger(spawned, entity, equipOn))
return;
}
}

View File

@@ -13,6 +13,7 @@ using Content.Shared.DoAfter;
using Content.Shared.Popups;
using Content.Shared.RadialSelector;
using Content.Shared.Standing;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
@@ -28,6 +29,7 @@ public sealed class XenomorphEvolutionSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly JitteringSystem _jitter = default!;
[Dependency] private readonly MindSystem _mind = default!;
@@ -57,21 +59,33 @@ public sealed class XenomorphEvolutionSystem : EntitySystem
if (args.Handled)
return;
args.Handled = true;
if (component.EvolvesTo.Count == 1)
{
StartEvolutionDuAfter(uid, component, component.EvolvesTo.First().Prototype);
if (component.Points < component.Max)
{
_popup.PopupEntity(Loc.GetString("xenomorphs-evolution-not-enough-points", ("seconds", (component.Max - component.Points) / component.PointsPerSecond)), uid, uid);
return;
}
args.Handled = Evolve(uid, component.EvolvesTo.First().Prototype, component.EvolutionDelay);
return;
}
_ui.TryToggleUi(uid, RadialSelectorUiKey.Key, uid);
_ui.SetUiState(uid, RadialSelectorUiKey.Key, new TrackedRadialSelectorState(component.EvolvesTo));
args.Handled = true;
}
private void OnEvolutionRecieved(EntityUid uid, XenomorphEvolutionComponent component, RadialSelectorSelectedMessage args)
{
if (StartEvolutionDuAfter(uid, component, args.SelectedItem))
if (component.Points < component.Max)
{
_popup.PopupEntity(Loc.GetString("xenomorphs-evolution-not-enough-points", ("seconds", (component.Max - component.Points) / component.PointsPerSecond)), uid, uid);
return;
}
if (Evolve(uid, args.SelectedItem, component.EvolutionDelay))
return;
var actor = args.Actor;
@@ -116,7 +130,7 @@ public sealed class XenomorphEvolutionSystem : EntitySystem
var query = EntityQueryEnumerator<XenomorphEvolutionComponent>();
while (query.MoveNext(out var uid, out var alienEvolution))
{
if (alienEvolution.Points == alienEvolution.Max || time < alienEvolution.NextPointsAt)
if (alienEvolution.Points == alienEvolution.Max || time < alienEvolution.NextPointsAt || _container.IsEntityInContainer(uid))
continue;
alienEvolution.NextPointsAt = time + TimeSpan.FromSeconds(1);
@@ -129,32 +143,27 @@ public sealed class XenomorphEvolutionSystem : EntitySystem
}
}
private bool StartEvolutionDuAfter(EntityUid uid, XenomorphEvolutionComponent component, string? selectedItem)
public bool Evolve(EntityUid uid, string? evolveTo, TimeSpan evolutionDelay, bool checkNeedCasteDeath = true)
{
if (component.Points < component.Max)
{
_popup.PopupEntity(Loc.GetString("xenomorphs-evolution-not-enough-points", ("seconds", (component.Max - component.Points) / component.PointsPerSecond)), uid, uid);
return false;
}
if (selectedItem == null
|| !_protoManager.TryIndex(selectedItem, out var xenomorphPrototype)
|| !xenomorphPrototype.TryGetComponent<XenomorphComponent>(out var xenomorph, _componentFactory))
if (evolveTo == null
|| !_protoManager.TryIndex(evolveTo, out var xenomorphPrototype)
|| !xenomorphPrototype.TryGetComponent<XenomorphComponent>(out var xenomorph, _componentFactory)
|| !_mind.TryGetMind(uid, out _, out _))
return false;
var ev = new BeforeXenomorphEvolutionEvent(xenomorph.Caste);
var ev = new BeforeXenomorphEvolutionEvent(xenomorph.Caste, checkNeedCasteDeath);
RaiseLocalEvent(uid, ev);
if (ev.Cancelled)
return false;
var doAfterEvent = new XenomorphEvolutionDoAfterEvent(selectedItem, xenomorph.Caste);
var doAfter = new DoAfterArgs(EntityManager, uid, component.EvolutionDelay, doAfterEvent, uid);
var doAfterEvent = new XenomorphEvolutionDoAfterEvent(evolveTo, xenomorph.Caste, checkNeedCasteDeath);
var doAfter = new DoAfterArgs(EntityManager, uid, evolutionDelay, doAfterEvent, uid);
if (!_doAfter.TryStartDoAfter(doAfter))
return false;
_jitter.DoJitter(uid, component.EvolutionDelay, true, 80, 8, true);
_jitter.DoJitter(uid, evolutionDelay, true, 80, 8, true);
var popupOthers = Loc.GetString("xenomorphs-evolution-start-others", ("uid", uid));
_popup.PopupEntity(popupOthers, uid, Filter.PvsExcept(uid), true, PopupType.Medium);

View File

@@ -1,6 +1,6 @@
using Content.Shared.Damage;
using Content.Shared.Mobs;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server._White.Xenomorphs.FaceHugger;
@@ -8,24 +8,51 @@ namespace Content.Server._White.Xenomorphs.FaceHugger;
[RegisterComponent]
public sealed partial class FaceHuggerComponent : Component
{
[DataField(required: true)]
public string Slot;
[DataField]
public DamageSpecifier DamageOnImpact = new();
[DataField]
public DamageSpecifier DamageOnInfect = new();
[DataField]
public EntityWhitelist? Blacklist;
[DataField]
public EntProtoId? InfectionPrototype = "XenomorphInfection";
[DataField]
public string BlockingSlot = "head";
[DataField]
public string InfectionSlotId = "xenomorph_larva";
[DataField]
public EntProtoId InfectionPrototype = "XenomorphInfection";
public string Slot = "mask";
[DataField]
public int LarvaEmbryoCount = 1;
public SoundSpecifier SoundOnImpact = new SoundCollectionSpecifier("MetalThud");
[DataField]
public List<MobState> AllowedPassiveDamageStates = new();
public TimeSpan KnockdownTime = TimeSpan.FromSeconds(5);
[DataField]
public DamageSpecifier PassiveDamage = new();
public TimeSpan MaxInfectTime = TimeSpan.FromSeconds(20);
[DataField]
public TimeSpan MaxRestTime = TimeSpan.FromSeconds(20);
[DataField]
public TimeSpan MinInfectTime = TimeSpan.FromSeconds(10);
[DataField]
public TimeSpan MinRestTime = TimeSpan.FromSeconds(10);
[ViewVariables]
public bool Active = true;
[ViewVariables]
public TimeSpan InfectIn = TimeSpan.Zero;
[ViewVariables]
public TimeSpan RestIn = TimeSpan.Zero;
}

View File

@@ -1,32 +1,125 @@
using Content.Server.Body.Systems;
using Content.Shared.Damage.Components;
using Content.Server.Popups;
using Content.Server.Stunnable;
using Content.Shared.Clothing.Components;
using Content.Shared.Damage;
using Content.Shared.Hands;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Mobs.Systems;
using Content.Shared.Nutrition.Components;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Whitelist;
using Robust.Server.Audio;
using Robust.Server.Containers;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server._White.Xenomorphs.FaceHugger;
public sealed class FaceHuggerSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly BodySystem _body = default!;
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly StunSystem _stun = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FaceHuggerComponent, StartCollideEvent>(OnCollideEvent);
SubscribeLocalEvent<FaceHuggerComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<FaceHuggerComponent, GotEquippedHandEvent>(OnPickedUp);
SubscribeLocalEvent<FaceHuggerComponent, GotEquippedEvent>(OnGotEquipped);
SubscribeLocalEvent<FaceHuggerComponent, GotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<FaceHuggerComponent, BeingUnequippedAttemptEvent>(OnBeingUnequippedAttempt);
}
private void OnCollideEvent(EntityUid uid, FaceHuggerComponent component, StartCollideEvent args)
{
TryEquipFaceHugger(uid, args.OtherEntity, component);
}
private void OnMeleeHit(EntityUid uid, FaceHuggerComponent component, MeleeHitEvent args)
{
if (args.HitEntities.FirstOrNull() is not {} target)
return;
TryEquipFaceHugger(uid, target, component);
}
private void OnPickedUp(EntityUid uid, FaceHuggerComponent component, GotEquippedHandEvent args)
{
TryEquipFaceHugger(uid, args.User, component);
}
private void OnGotEquipped(EntityUid uid, FaceHuggerComponent component, GotEquippedEvent args)
{
if (args.Slot != component.Slot
|| component.LarvaEmbryoCount <= 0
|| !_mobState.IsAlive(uid)
|| _entityWhitelist.IsBlacklistPass(component.Blacklist, args.Equipee)
|| _body.GetRootPartOrNull(args.Equipee) is not {} rootPart)
|| _mobState.IsDead(uid)
|| _entityWhitelist.IsBlacklistPass(component.Blacklist, args.Equipee))
return;
_popup.PopupEntity(Loc.GetString("xenomorphs-face-hugger-equip", ("equipment", uid)), uid, args.Equipee);
_popup.PopupEntity(Loc.GetString("xenomorphs-face-hugger-equip-other", ("equipment", uid), ("target", Identity.Entity(args.Equipee, EntityManager))), uid, Filter.PvsExcept(args.Equipee), true);
_stun.TryKnockdown(args.Equipee, component.KnockdownTime, true);
if (!component.InfectionPrototype.HasValue)
return;
component.InfectIn = _timing.CurTime + _random.Next(component.MinInfectTime, component.MaxInfectTime);
}
private void OnBeingUnequippedAttempt(EntityUid uid, FaceHuggerComponent component, BeingUnequippedAttemptEvent args)
{
if (_mobState.IsDead(uid) || !component.InfectionPrototype.HasValue || args.Unequipee != args.UnEquipTarget)
return;
_popup.PopupEntity(Loc.GetString("xenomorphs-face-hugger-unequip", ("equipment", Identity.Entity(uid, EntityManager))), uid, args.Unequipee);
args.Cancel();
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var time = _timing.CurTime;
var query = EntityQueryEnumerator<FaceHuggerComponent>();
while (query.MoveNext(out var uid, out var faceHugger))
{
if (!faceHugger.Active && time > faceHugger.RestIn)
faceHugger.Active = true;
if (faceHugger.InfectIn != TimeSpan.Zero && time > faceHugger.InfectIn)
{
faceHugger.InfectIn = TimeSpan.Zero;
Infect(uid, faceHugger);
}
}
}
private void Infect(EntityUid uid, FaceHuggerComponent component)
{
if (!component.InfectionPrototype.HasValue
|| !TryComp<ClothingComponent>(uid, out var clothing)
|| clothing.InSlot != component.Slot
|| !_container.TryGetContainingContainer((uid, null, null), out var target)
|| _body.GetRootPartOrNull(target.Owner) is not {} rootPart)
return;
var organ = Spawn(component.InfectionPrototype);
@@ -38,16 +131,42 @@ public sealed class FaceHuggerSystem : EntitySystem
return;
}
component.LarvaEmbryoCount--;
_damageable.TryChangeDamage(uid, component.DamageOnInfect, true);
}
private void OnGotUnequipped(EntityUid uid, FaceHuggerComponent component, GotUnequippedEvent args)
public bool TryEquipFaceHugger(EntityUid uid, EntityUid target, FaceHuggerComponent component)
{
if (component.LarvaEmbryoCount > 0 || HasComp<PassiveDamageComponent>(uid))
return;
if (!component.Active || _mobState.IsDead(uid) || _entityWhitelist.IsBlacklistPass(component.Blacklist, target))
return false;
var passiveDamage = EnsureComp<PassiveDamageComponent>(uid);
passiveDamage.AllowedStates = component.AllowedPassiveDamageStates;
passiveDamage.Damage = component.PassiveDamage;
component.RestIn = _timing.CurTime + _random.Next(component.MinRestTime, component.MaxRestTime);
component.Active = false;
EntityUid? blocker = null;
if (_inventory.TryGetSlotEntity(target, "head", out var headUid)
&& TryComp<IngestionBlockerComponent>(headUid, out var headBlocker)
&& headBlocker.Enabled)
blocker = headUid;
if (!blocker.HasValue && _inventory.TryGetSlotEntity(target, "mask", out var maskUid))
{
if (TryComp<IngestionBlockerComponent>(maskUid, out var maskBlocker) && maskBlocker.Enabled)
blocker = maskUid;
else
_inventory.TryUnequip(target, component.Slot, true);
}
if (!blocker.HasValue)
return _inventory.TryEquip(target, uid, component.Slot, true, true);
_audio.PlayPvs(component.SoundOnImpact, uid);
_damageable.TryChangeDamage(uid, component.DamageOnImpact);
_popup.PopupEntity(Loc.GetString("xenomorphs-face-hugger-try-equip", ("equipment", uid), ("equipmentBlocker", blocker.Value)), uid);
_popup.PopupEntity(Loc.GetString("xenomorphs-face-hugger-try-equip-other", ("equipment", uid), ("equipmentBlocker", blocker.Value), ("target", Identity.Entity(target, EntityManager))), uid, Filter.PvsExcept(target), true);
return false;
}
}

View File

@@ -0,0 +1,21 @@
using Content.Shared._White.Xenomorphs.Caste;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
namespace Content.Server._White.Xenomorphs.Queen;
[RegisterComponent]
public sealed partial class XenomorphPromotionComponent : Component
{
[ViewVariables]
public EntProtoId PromoteTo = "MobXenomorphPraetorian";
[ViewVariables]
public FixedPoint2 PlasmaCost = 0;
[ViewVariables]
public List<ProtoId<XenomorphCastePrototype>> CasteWhitelist = new();
[ViewVariables]
public TimeSpan EvolutionDelay = TimeSpan.FromSeconds(3);
}

View File

@@ -0,0 +1,94 @@
using Content.Server._White.Xenomorphs.Evolution;
using Content.Server._White.Xenomorphs.Plasma;
using Content.Server.Actions;
using Content.Server.Hands.Systems;
using Content.Server.Popups;
using Content.Shared._White.Actions;
using Content.Shared._White.Xenomorphs;
using Content.Shared._White.Xenomorphs.Queen;
using Content.Shared._White.Xenomorphs.Xenomorph;
using Content.Shared.Interaction;
namespace Content.Server._White.Xenomorphs.Queen;
public sealed class XenomorphQueenSystem : EntitySystem
{
[Dependency] private readonly ActionsSystem _actions = default!;
[Dependency] private readonly HandsSystem _hands = default!;
[Dependency] private readonly PlasmaSystem _plasma = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly XenomorphEvolutionSystem _xenomorphEvolution = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<XenomorphQueenComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<XenomorphQueenComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<XenomorphQueenComponent, PromotionActionEvent>(OnPromotionAction);
SubscribeLocalEvent<XenomorphPromotionComponent, AfterInteractEvent>(OnAfterInteract);
}
private void OnMapInit(EntityUid uid, XenomorphQueenComponent component, MapInitEvent args) =>
_actions.AddAction(uid, ref component.PromotionAction, component.PromotionActionId);
private void OnShutdown(EntityUid uid, XenomorphQueenComponent component, ComponentShutdown args) =>
_actions.RemoveAction(uid, component.PromotionAction);
private void OnPromotionAction(EntityUid uid, XenomorphQueenComponent component, PromotionActionEvent args)
{
if (Exists(component.Promotion))
{
QueueDel(component.Promotion);
component.Promotion = null;
return;
}
component.Promotion = Spawn(component.PromotionId);
var promotion = EnsureComp<XenomorphPromotionComponent>(component.Promotion.Value);
promotion.CasteWhitelist = component.CasteWhitelist;
promotion.PromoteTo = component.PromoteTo;
promotion.EvolutionDelay = component.EvolutionDelay;
if (TryComp<PlasmaCostActionComponent>(component.PromotionAction, out var plasmaCostAction))
promotion.PlasmaCost = plasmaCostAction.PlasmaCost;
if (!_hands.TryForcePickupAnyHand(uid, component.Promotion.Value))
{
QueueDel(component.Promotion);
component.Promotion = null;
return;
}
args.Handled = true;
}
private void OnAfterInteract(EntityUid uid, XenomorphPromotionComponent component, AfterInteractEvent args)
{
if (!args.CanReach
|| args.Target is not { } target
|| target == args.User
|| !TryComp<XenomorphComponent>(target, out var xenomorph))
return;
if (!component.CasteWhitelist.Contains(xenomorph.Caste))
{
_popup.PopupEntity(Loc.GetString("xenomorphs-queen-promotion-didnt-pass-whitelist"), args.User);
return;
}
if (!_xenomorphEvolution.Evolve(target, component.PromoteTo, component.EvolutionDelay))
{
_popup.PopupEntity(Loc.GetString("xenomorphs-queen-promotion-no-mind"), args.User);
return;
}
if (component.PlasmaCost != 0)
_plasma.ChangePlasmaAmount(args.User, component.PlasmaCost);
QueueDel(uid);
args.Handled = true;
}
}

View File

@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Alert;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
@@ -150,6 +151,11 @@ public readonly record struct UnstrappedEvent(Entity<StrapComponent> Strap, Enti
[ByRefEvent]
public readonly record struct UnbuckledEvent(Entity<StrapComponent> Strap, Entity<BuckleComponent> Buckle);
// WD EDIT START
[Serializable, NetSerializable]
public sealed partial class UnbuckleDoAfterEvent : SimpleDoAfterEvent;
// WD EDIT END
[Serializable, NetSerializable]
public enum BuckleVisuals
{

View File

@@ -1,5 +1,6 @@
using System.Numerics;
using Content.Shared.Alert;
using Content.Shared.DoAfter;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
@@ -84,6 +85,14 @@ public sealed partial class StrapComponent : Component
/// </summary>
[DataField]
public bool BuckleOnInteractHand = true;
// WD EDIT START
/// <summary>
/// Delay, that must occur, before user can unbuckle
/// </summary>
[DataField]
public TimeSpan SelfUnBuckleDelay = TimeSpan.Zero;
// WD EDIT END
}
public enum StrapPosition

View File

@@ -32,6 +32,7 @@ public abstract partial class SharedBuckleSystem
{
public static ProtoId<AlertCategoryPrototype> BuckledAlertCategory = "Buckled";
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!; // WD EDIT
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
private void InitializeBuckle()
@@ -53,6 +54,8 @@ public abstract partial class SharedBuckleSystem
SubscribeLocalEvent<BuckleComponent, StandAttemptEvent>(OnBuckleStandAttempt);
SubscribeLocalEvent<BuckleComponent, ThrowPushbackAttemptEvent>(OnBuckleThrowPushbackAttempt);
SubscribeLocalEvent<BuckleComponent, UpdateCanMoveEvent>(OnBuckleUpdateCanMove);
SubscribeLocalEvent<BuckleComponent, UnbuckleDoAfterEvent>(OnUnbuckleDoAfter); // WD EDIT
}
private void OnBuckleComponentShutdown(Entity<BuckleComponent> ent, ref ComponentShutdown args)
@@ -174,6 +177,16 @@ public abstract partial class SharedBuckleSystem
args.Cancel();
}
// WD EDIT START
private void OnUnbuckleDoAfter(EntityUid uid, BuckleComponent component, UnbuckleDoAfterEvent args)
{
if (args.Cancelled || !CanUnbuckle((uid, component), uid, true, out var strap))
return;
Unbuckle((uid, component), strap, uid);
}
// WD EDIT END
public bool IsBuckled(EntityUid uid, BuckleComponent? component = null)
{
return Resolve(uid, ref component, false) && component.Buckled;
@@ -419,6 +432,14 @@ public abstract partial class SharedBuckleSystem
if (!CanUnbuckle(buckle, user, popup, out var strap))
return false;
// WD EDIT START
if (buckle.Owner == user && strap.Comp.SelfUnBuckleDelay != TimeSpan.Zero)
{
var doAfter = new DoAfterArgs(EntityManager, buckle.Owner, strap.Comp.SelfUnBuckleDelay, new UnbuckleDoAfterEvent(), buckle.Owner);
return _doAfter.TryStartDoAfter(doAfter);
}
// WD EDIT END
Unbuckle(buckle!, strap, user);
return true;
}

View File

@@ -1,4 +1,6 @@
using Content.Shared.Alert;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Pinpointer;
@@ -48,10 +50,24 @@ public sealed partial class PinpointerComponent : Component
[DataField("canRetarget"), ViewVariables(VVAccess.ReadWrite)]
public bool CanRetarget;
// WD EDIT START
[DataField]
public ProtoId<AlertPrototype>? Alert;
[DataField]
public bool CanToggle = true;
[DataField]
public bool CanEmag = true;
[DataField]
public bool CanExamine = true;
// WD EDIT END
[ViewVariables]
public EntityUid? Target = null;
[ViewVariables, AutoNetworkedField]
[DataField, AutoNetworkedField] // WD EDIT: ViewVariables -> DataField
public bool IsActive = false;
[ViewVariables, AutoNetworkedField]

View File

@@ -66,7 +66,7 @@ public abstract class SharedPinpointerSystem : EntitySystem
private void OnExamined(EntityUid uid, PinpointerComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange || component.TargetName == null)
if (!component.CanExamine || !args.IsInDetailsRange || component.TargetName == null) // WD EDIT
return;
args.PushMarkup(Loc.GetString("examine-pinpointer-linked", ("target", component.TargetName)));
@@ -137,6 +137,11 @@ public abstract class SharedPinpointerSystem : EntitySystem
private void OnEmagged(EntityUid uid, PinpointerComponent component, ref GotEmaggedEvent args)
{
// WD EDIT START
if (!component.CanEmag)
return;
// WD EDIT END
args.Handled = true;
component.CanRetarget = true;
}

View File

@@ -598,7 +598,7 @@ public abstract partial class SharedGunSystem : EntitySystem
}
}
protected IShootable EnsureShootable(EntityUid uid)
public IShootable EnsureShootable(EntityUid uid) // WD EDIT: protected -> public
{
if (TryComp<CartridgeAmmoComponent>(uid, out var cartridge))
return cartridge;

View File

@@ -1,10 +1,11 @@
using Content.Shared.Actions;
using Content.Shared.DoAfter;
using Content.Shared.Physics;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Physics.Dynamics;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared._White.Actions.Events;
@@ -31,8 +32,11 @@ public sealed partial class SpawnTileEntityActionEvent : InstantActionEvent
[DataField]
public SoundSpecifier? Audio;
[DataField]
public CollisionGroup? BlockedCollision;
[DataField(customTypeSerializer: typeof(FlagSerializer<CollisionMask>))]
public int BlockedCollisionMask;
[DataField(customTypeSerializer: typeof(FlagSerializer<CollisionLayer>))]
public int BlockedCollisionLayer;
}
/// <summary>
@@ -58,8 +62,11 @@ public sealed partial class PlaceTileEntityEvent : WorldTargetActionEvent
[DataField]
public SoundSpecifier? Audio;
[DataField]
public CollisionGroup? BlockedCollision;
[DataField(customTypeSerializer: typeof(FlagSerializer<CollisionMask>))]
public int BlockedCollisionMask;
[DataField(customTypeSerializer: typeof(FlagSerializer<CollisionLayer>))]
public int BlockedCollisionLayer;
/// <summary>
/// The duration of the action in seconds
@@ -79,5 +86,9 @@ public sealed partial class PlaceTileEntityDoAfterEvent : DoAfterEvent
public SoundSpecifier? Audio;
public int BlockedCollisionMask;
public int BlockedCollisionLayer;
public override DoAfterEvent Clone() => this;
}

View File

@@ -6,6 +6,9 @@ namespace Content.Shared._White.Actions;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class PlasmaCostActionComponent : Component
{
[DataField]
public bool ShouldChangePlasma = true;
[DataField, AutoNetworkedField]
public FixedPoint2 PlasmaCost = 50;
}

View File

@@ -23,6 +23,7 @@ public sealed class PlasmaCostActionSystem : EntitySystem
private void OnActionPerformed(EntityUid uid, PlasmaCostActionComponent component, ActionPerformedEvent args)
{
_plasma.ChangePlasmaAmount(args.Performer, -component.PlasmaCost);
if (component.ShouldChangePlasma)
_plasma.ChangePlasmaAmount(args.Performer, -component.PlasmaCost);
}
}

View File

@@ -13,7 +13,7 @@ using Robust.Shared.Utility;
namespace Content.Shared._White.Inventory;
public abstract partial class SharedWhiteInventorySystem
public sealed partial class WhiteInventorySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
@@ -21,6 +21,7 @@ public abstract partial class SharedWhiteInventorySystem
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly InventorySystem _inventory = default!;
private void InitializeEquip()
{
SubscribeLocalEvent<EquipOnCollideComponent, StartCollideEvent>(OnCollideEvent);

View File

@@ -1,6 +1,6 @@
namespace Content.Shared._White.Inventory;
public abstract partial class SharedWhiteInventorySystem : EntitySystem
public sealed partial class WhiteInventorySystem : EntitySystem
{
public override void Initialize()
{

View File

@@ -0,0 +1,15 @@
using Content.Shared.FixedPoint;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Shared.Prototypes;
namespace Content.Shared._White.Weapons.Ranged.Components;
[RegisterComponent]
public sealed partial class PlasmaAmmoProviderComponent : AmmoProviderComponent
{
[DataField(required: true)]
public EntProtoId Proto;
[DataField]
public FixedPoint2 FireCost = 55f;
}

View File

@@ -0,0 +1,45 @@
using Content.Shared._White.Weapons.Ranged.Components;
using Content.Shared._White.Xenomorphs.Plasma;
using Content.Shared._White.Xenomorphs.Plasma.Components;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Weapons.Ranged.Systems;
namespace Content.Shared._White.Weapons.Ranged.Systems;
public sealed class PlasmaAmmoProviderSystem : EntitySystem
{
[Dependency] private readonly SharedGunSystem _gun = default!;
[Dependency] private readonly SharedPlasmaSystem _plasma = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlasmaAmmoProviderComponent, TakeAmmoEvent>(OnTakeAmmo);
SubscribeLocalEvent<PlasmaAmmoProviderComponent, GetAmmoCountEvent>(OnGetAmmoCount);
}
private void OnTakeAmmo(EntityUid uid, PlasmaAmmoProviderComponent component, ref TakeAmmoEvent args)
{
if (!TryComp<PlasmaVesselComponent>(uid, out var plasmaVessel))
return;
for (var i = 0; i < args.Shots; i++)
{
if (!_plasma.ChangePlasmaAmount(uid, -component.FireCost, plasmaVessel))
return;
var shot = Spawn(component.Proto, args.Coordinates);
args.Ammo.Add((shot, _gun.EnsureShootable(shot)));
}
}
private void OnGetAmmoCount(EntityUid uid, PlasmaAmmoProviderComponent component, ref GetAmmoCountEvent args)
{
if (!TryComp<PlasmaVesselComponent>(uid, out var plasmaVessel))
return;
args.Capacity = (int) (plasmaVessel.MaxPlasma / component.FireCost);
args.Count = (int) (plasmaVessel.Plasma / component.FireCost);
}
}

View File

@@ -8,7 +8,7 @@ namespace Content.Shared._White.Xenomorphs.Egg;
public sealed partial class XenomorphEggComponent : Component
{
[DataField]
public EntProtoId FaceHuggerPrototype = "MobXenomorphFaceHugger";
public EntProtoId? FaceHuggerPrototype = "MobXenomorphFaceHugger";
[DataField]
public float BurstRange = 1f;
@@ -28,6 +28,9 @@ public sealed partial class XenomorphEggComponent : Component
[DataField]
public TimeSpan MinGrowthTime = TimeSpan.FromSeconds(90);
[DataField]
public XenomorphEggStatus Status = XenomorphEggStatus.Growning;
[ViewVariables]
public TimeSpan BurstAt = TimeSpan.Zero;
@@ -36,9 +39,6 @@ public sealed partial class XenomorphEggComponent : Component
[ViewVariables]
public TimeSpan GrownAt = TimeSpan.Zero;
[ViewVariables]
public XenomorphEggStatus Status = XenomorphEggStatus.Growning;
}
public enum XenomorphEggStatus : byte

View File

@@ -16,10 +16,14 @@ public sealed partial class XenomorphEvolutionDoAfterEvent : DoAfterEvent
[DataField]
public ProtoId<XenomorphCastePrototype> Caste;
public XenomorphEvolutionDoAfterEvent(EntProtoId choice, ProtoId<XenomorphCastePrototype> caste)
[DataField]
public bool CheckNeedCasteDeath;
public XenomorphEvolutionDoAfterEvent(EntProtoId choice, ProtoId<XenomorphCastePrototype> caste, bool checkNeedCasteDeath = true)
{
Choice = choice;
Caste = caste;
CheckNeedCasteDeath = checkNeedCasteDeath;
}
public override DoAfterEvent Clone() => this;
@@ -36,6 +40,8 @@ public sealed partial class TransferPlasmaActionEvent : EntityTargetActionEvent
public sealed partial class EvolutionsActionEvent : InstantActionEvent;
public sealed partial class PromotionActionEvent : InstantActionEvent;
public sealed partial class TailLashActionEvent : WorldTargetActionEvent;
public sealed partial class AcidActionEvent : EntityTargetActionEvent;
@@ -47,9 +53,10 @@ public sealed partial class AfterXenomorphEvolutionEvent(EntityUid evolvedInto,
public ProtoId<XenomorphCastePrototype> Caste = caste;
}
public sealed partial class BeforeXenomorphEvolutionEvent(ProtoId<XenomorphCastePrototype> caste) : CancellableEntityEventArgs
public sealed partial class BeforeXenomorphEvolutionEvent(ProtoId<XenomorphCastePrototype> caste, bool checkNeedCasteDeath = true) : CancellableEntityEventArgs
{
public ProtoId<XenomorphCastePrototype> Caste = caste;
public bool CheckNeedCasteDeath = checkNeedCasteDeath;
}
public sealed partial class PlasmaAmountChangeEvent(FixedPoint2 amount) : EntityEventArgs

View File

@@ -0,0 +1,29 @@
using Content.Shared._White.Xenomorphs.Caste;
using Robust.Shared.Prototypes;
namespace Content.Shared._White.Xenomorphs.Queen;
[RegisterComponent]
public sealed partial class XenomorphQueenComponent : Component
{
[DataField]
public EntProtoId PromotionActionId = "ActionXenomorphPromotion";
[DataField]
public EntProtoId PromotionId = "XenomorphPromotion";
[DataField]
public EntProtoId PromoteTo = "MobXenomorphPraetorian";
[DataField]
public List<ProtoId<XenomorphCastePrototype>> CasteWhitelist = new() { "Drone", "Hunter", "Sentinel", };
[DataField]
public TimeSpan EvolutionDelay = TimeSpan.FromSeconds(3);
[ViewVariables]
public EntityUid? Promotion;
[ViewVariables]
public EntityUid? PromotionAction;
}

View File

@@ -4,5 +4,8 @@ alerts-blocked-desc = I can't block for a while!
alerts-knockdown-name = [color=yellow]Knocked down[/color]
alerts-knockdown-desc = You're [color=yellow]knocked down[/color]! Something is impairing your ability to get up.
alerts-plasma-name = [color='#ff2da4']Plasma[/color]
alerts-plasma-desc = The amount of [color='#ff2da4']plasma[/color] you have to use your abilities.
alerts-plasma-name = [color=#ff2da4]Plasma[/color]
alerts-plasma-desc = The amount of [color=#ff2da4]plasma[/color] you have to use your abilities.
alerts-queen-finder-name = Queen sense
alerts-queen-finder-desc = Allows you to sense the general direction of your Queen.

View File

@@ -0,0 +1 @@
steal-target-groups-animal-lamarr = Lamarr

View File

@@ -1,2 +0,0 @@
ent-MiniSyringe = mini syringe
ent-MiniSyringe-desc = A regular syringe, reshaped to fit inside of a gun.

View File

@@ -0,0 +1,7 @@
xenomorphs-face-hugger-equip = { $equipment } leaps at your face!
xenomorphs-face-hugger-equip-other = { $equipment } leaps at { $target }'s face!
xenomorphs-face-hugger-unequip = { $equipment } is latched on too tight!
xenomorphs-face-hugger-try-equip = { $equipment } smashes against your { $equipmentBlocker }
xenomorphs-face-hugger-try-equip-other = { $equipment } smashes against { $target }'s { $equipmentBlocker }

View File

@@ -0,0 +1,2 @@
xenomorphs-queen-promotion-didnt-pass-whitelist = You may only use this with your adult, non-royal children!
xenomorphs-queen-promotion-no-mind = Her mind can't support the promotion!

View File

@@ -16631,10 +16631,6 @@ ent-SmallExplosionInstant = мгновенный взрыв (малый)
ent-MediumExplosionInstant = мгновенный взрыв (средний)
ent-PlushieSanabi = плюшевая игрушка бригадира
.desc = Маленькая мягкая копия сурового бригадного генерала. Ужасно милая.
ent-ItemSnowballMaker = снежколеп
.desc = Лепит снежки. Весело и опасно.

View File

@@ -1,2 +1,6 @@
ent-XenomorphEgg = яйцо ксеноморфа
.desc = Большое пятнистое яйцо.
ent-XenomorphEggBurst = { ent-XenomorphEgg }
.desc = { ent-XenomorphEgg.desc }
.suffix = Открытое

View File

@@ -0,0 +1,3 @@
ent-GlassBoxLamarrFilled = { ent-GlassBox }
.desc = { ent-GlassBox.desc }
.suffix = Ламарр, Заполненная

View File

@@ -4,5 +4,8 @@ alerts-blocked-desc = Невозможно блокировать некотор
alerts-knockdown-name = [color=yellow]Сбиты с ног[/color]
alerts-knockdown-desc = Вы [color=yellow]сбиты с ног[/color]! Что-то мешает вам встать.
alerts-plasma-name = [color='#ff2da4']Плазма[/color]
alerts-plasma-desc = Количество [color='#ff2da4']плазмы[/color] которое у тебя есть для использования своих способностей.
alerts-plasma-name = [color=#ff2da4]Плазма[/color]
alerts-plasma-desc = Количество [color=#ff2da4]плазмы[/color] которое у тебя есть для использования своих способностей.
alerts-queen-finder-name = Чувство королевы
alerts-queen-finder-desc = Позволяет вам чувствовать общее направление движения вашей королевы.

View File

@@ -0,0 +1 @@
steal-target-groups-animal-lamarr = Ламарр

View File

@@ -1,51 +1,44 @@
ent-ActionCombatModeToggleXenomorph = { ent-ActionCombatModeToggle }
.desc = { ent-ActionCombatModeToggle.desc }
ent-ToggleThermalVisionXenomorph = { ent-ActionCombatModeToggle }
.desc = { ent-ActionCombatModeToggle.desc }
ent-ActionEvolution = Эволюционировать
.desc = Эволюционирует в высшую касту ксеноморфов.
ent-ActionEvolutionPraetorian = Эволюционировать в преторианца (500)
.desc = Эволюционирует в главного защитника улья.
ent-ActionEvolutionQueen = Эволюционировать в королеву (500)
.desc = Формирует внутренний яйцевой мешок, способный производить потомство. Одновременно может существовать только одна королева.
ent-ActionSpawnResinWeedNode = Посадить траву (50)
.desc = Сажает траву ксеноморфов.
ent-ActionSpawnXenomorphEgg = Отложить яйцо (75)
.desc = Отложить яйцо, чтобы произвести на свет лицехватов, с помощью которых можно оплодотворить добычу.
ent-ActionSpawnWallResin = Выделить смолу (50)
ent-ActionSpawnWallResin = Построить смоляную стену (50)
.desc = Выделяют вязкую, пластичную смолу.
ent-ActionSpawnResinMembrane = Выделить смолу (50)
ent-ActionSpawnResinMembrane = Построить смоляную мембрану (50)
.desc = Выделяют вязкую, пластичную смолу.
ent-ActionSpawnResinNest = Выделить смолу (50)
ent-ActionSpawnResinNest = Построить смоляное гнездо (50)
.desc = Выделяют вязкую, пластичную смолу.
ent-ActionTailLash = Удар хвостом
.desc = Ударь противника хвостом.
ent-ActionAcid = Едкая кислота (200)
.desc = Покройте предмет кислотой, которая со временем его разрушит.
ent-ActionJumpXenomorph = Прыжок
.desc = Оглушите врагов быстрым прыжком.
ent-ActionTransferPlasma = Передача плазмы (50)
.desc = Передаёт плазму вашему другу.
ent-ActionXenomorphPromotion = Создать королевского паразита (500)
.desc = Создает королевского паразита, чтобы предоставить одному из ваших детей честь стать вашим преторианцем.

View File

@@ -0,0 +1,6 @@
ent-PlushieSanabi = плюшевая игрушка бригадира
.desc = Маленькая мягкая копия сурового генерала бригадира. Ужасно милая.
ent-FaceHuggerToys = ксеноморф лицехват
.desc = Игрушка, которую часто используют, чтобы подшутить над другими членами экипажа, подкладывая её им в кровати. После того, как она зацепится за что-нибудь, ей требуется некоторое время для перезарядки.
.suffix = Игрушка

View File

@@ -0,0 +1,3 @@
ent-MobXenomorphFaceHuggerLamarr = Ламарр
.desc = бывший кандидат в кошмар, а ныне примерный питомец.

View File

@@ -0,0 +1,3 @@
ent-XenomorphPromotion = королевский паразит
.desc = Введите это в одну из своих взрослых дочерей, чтобы повысить её до преторианца!
.suffix = { ent-BaseItem.suffix }

View File

@@ -0,0 +1,7 @@
xenomorphs-face-hugger-equip = { $equipment } прыгает тебе на лицо!
xenomorphs-face-hugger-equip-other = { $equipment } прыгает на лицо { $target }!
xenomorphs-face-hugger-unequip = { $equipment } прицепился слишком крепко!
xenomorphs-face-hugger-try-equip = { $equipment } врезается в твой { $equipmentBlocker }
xenomorphs-face-hugger-try-equip-other = { $equipment } врезается в { $equipmentBlocker } { $target }

View File

@@ -0,0 +1,2 @@
xenomorphs-queen-promotion-didnt-pass-whitelist = Вы можете использовать это только с вашими взрослыми детьми, не являющимися королевскими!
xenomorphs-queen-promotion-no-mind = Её разум не может выдержать повышение!

View File

@@ -771,8 +771,6 @@
orGroup: Plushie
- id: PlushieMothRandom
orGroup: Plushie
- id: PlushieSanabi # WWDP edit
orGroup: Plushie
- id: PlushieMoth
prob: 0.5
orGroup: Plushie
@@ -785,6 +783,12 @@
- id: PlushieShadowkin
prob: 0.5
orGroup: Plushie
# WD EDIT START
- id: PlushieSanabi
orGroup: Plushie
- id: FaceHuggerToys
orGroup: Plushie
# WD EDIT END
# Random snacks, replaces MailChocolate (lousy animal organs)
- type: entity

View File

@@ -71,8 +71,11 @@
- PlushieJester
- PlushieHarpy
- PlushieMort
- PlushieSanabi #WWDP edit
- PlushieShadowkin
# WD EDIT START
- PlushieSanabi
- FaceHuggerToys
# WD EDIT END
chance: 0.5
offset: 0.2

View File

@@ -84,8 +84,6 @@
orGroup: GiftPool
- id: PlushieRatvar
orGroup: GiftPool
- id: PlushieSanabi #WWDP edit
orGroup: GiftPool
- id: PlushieSpaceLizard
orGroup: GiftPool
- id: PlushieSharkBlue
@@ -386,6 +384,12 @@
orGroup: GiftPool
- id: ToySiobhan # DeltaV Toy, see Resources/Prototypes/DeltaV/Entities/Objects/Fun/toys.yml
orGroup: GiftPool
# WD EDIT START
- id: PlushieSanabi
orGroup: GiftPool
- id: FaceHuggerToys
orGroup: GiftPool
# WD EDIT END
sound:
path: /Audio/Effects/unwrap.ogg

View File

@@ -910,7 +910,7 @@
- type: Projectile
damage:
types:
Caustic: 15 # WD EDIT: 5 -> 15
Caustic: 5
- type: Sprite
sprite: Objects/Weapons/Guns/Projectiles/xeno_toxic.rsi
layers:

View File

@@ -1911,6 +1911,7 @@
- ToySword
- BwoinkHammer
- ThronglerToy
- FaceHuggerToys # WD EDIT
- type: MaterialStorage
whitelist:
tags:

View File

@@ -62,7 +62,12 @@
icon: { sprite: _White/Interface/Actions/xenomorph.rsi, state: plant_seed }
event: !type:SpawnTileEntityActionEvent
entity: ResinWeedNode
blockedCollision: SlipLayer
blockedCollisionMask:
- SlipLayer
blockedCollisionLayer:
- Impassable
- MidImpassable
- LowImpassable
- type: PlasmaCostAction
- type: entity
@@ -77,62 +82,73 @@
icon: { sprite: _White/Interface/Actions/xenomorph.rsi, state: egg }
event: !type:SpawnTileEntityActionEvent
entity: XenomorphEgg
blockedCollision: TableMask
blockedCollisionMask:
- TableMask
blockedCollisionLayer:
- TableLayer
- BulletImpassable
- type: PlasmaCostAction
plasmaCost: 75
# TODO: delete it
- type: entity
id: ActionSpawnWallResin
name: Secrete resin (50)
name: Build a resin wall (50)
description: Secrete tough malleable resin.
components:
- type: WorldTargetAction
useDelay: 1
range: 2
itemIconStyle: BigAction
checkCanAccess: false
icon: { sprite: _White/Structures/Walls/resin.rsi, state: full }
event: !type:PlaceTileEntityEvent
entity: WallResin
length: 0.5
blockedCollision: FullTileMask
blockedCollisionMask:
- FullTileMask
blockedCollisionLayer:
- WallLayer
- type: PlasmaCostAction
# TODO: delete it
- type: entity
id: ActionSpawnResinMembrane
name: Secrete resin (50)
name: Build a resin membrane (50)
description: Secrete tough malleable resin.
components:
- type: WorldTargetAction
useDelay: 1
range: 2
itemIconStyle: BigAction
checkCanAccess: false
icon: { sprite : _White/Structures/Windows/resin_membrane.rsi, state: full }
event: !type:PlaceTileEntityEvent
entity: ResinMembrane
length: 0.5
blockedCollision: GlassLayer
blockedCollisionMask:
- FullTileMask
blockedCollisionLayer:
- GlassLayer
- type: PlasmaCostAction
# TODO: delete it
- type: entity
id: ActionSpawnResinNest
name: Secrete resin (50)
name: Build a resin nest (50)
description: Secrete tough malleable resin.
components:
- type: WorldTargetAction
useDelay: 1
range: 2
itemIconStyle: BigAction
checkCanAccess: false
icon: { sprite : _White/Structures/Windows/resin_membrane.rsi, state: full }
event: !type:PlaceTileEntityEvent
entity: ResinNest
length: 0.5
blockedCollision: TableMask
blockedCollisionMask:
- TableMask
blockedCollisionLayer:
- TableLayer
- BulletImpassable
- type: PlasmaCostAction
# Tail lash action
@@ -145,7 +161,6 @@
useDelay: 11
range: 10
itemIconStyle: BigAction
checkCanAccess: false
icon: { sprite : _White/Interface/Actions/xenomorph.rsi, state: tail_attack }
event: !type:TailLashActionEvent
@@ -188,3 +203,18 @@
icon: { sprite : _White/Interface/Actions/xenomorph.rsi, state: plasma_transfer_off }
iconOn: { sprite : _White/Interface/Actions/xenomorph.rsi, state: plasma_transfer_on }
event: !type:TransferPlasmaActionEvent
# Promotion action
- type: entity
id: ActionXenomorphPromotion
name: Create royal parasite (500)
description: Produce a royal parasite to grant one of your children the honor of being your Praetorian.
components:
- type: InstantAction
checkCanInteract: false
itemIconStyle: BigAction
useDelay: 0
icon: { sprite : _White/Interface/Actions/xenomorph.rsi, state: promote }
event: !type:PromotionActionEvent
- type: PlasmaCostAction
plasmaCost: 500

View File

@@ -63,3 +63,23 @@
offset: 0.175, 0
- map: [ "enum.PlasmaVisualLayers.Digit3" ]
offset: 0.35, 0
# Queen Finder Alert
- type: alert
id: QueenFinder
icons:
- sprite: /Textures/_White/Interface/Alerts/queen_finder.rsi
state: queen_finder
alertViewEntity: AlertQueenFinderSpriteView
name: alerts-queen-finder-name
description: alerts-queen-finder-desc
- type: entity
id: AlertQueenFinderSpriteView
categories: [ HideSpawnMenu ]
components:
- type: Sprite
sprite: /Textures/_White/Interface/Alerts/queen_finder.rsi
layers:
- map: [ "enum.AlertVisualLayers.Base" ]
- map: [ "enum.PinpointerLayers.Screen" ]

View File

@@ -107,12 +107,11 @@
onAdd:
- type: RechargeBasicEntityAmmo
rechargeCooldown: 0.75
- type: BasicEntityAmmoProvider
proto: BulletAcidLarge
capacity: 1
count: 1
- type: PlasmaAmmoProvider
fireCost: 55
proto: BulletNeurotoxin
- type: Gun
fireRate: 0.25
fireRate: 0.75
useKey: false
selectedMode: FullAuto
availableModes:

View File

@@ -1,17 +0,0 @@
- type: entity
parent: BasePlushie
id: PlushieSanabi
name: brigadier plushie
description: A small stuffed doll of the brigadier general.
components:
- type: Item
size: Normal
inhandVisuals:
left:
- state: sanabi-inhand-left
right:
- state: sanabi-inhand-right
- type: Sprite
sprite: _White/Objects/Fun/sanabi.rsi
state: sanabi

View File

@@ -15,6 +15,3 @@
rules: ghost-role-information-rules-default-team-antagonist
mindRoles:
- MindRoleGhostRoleTeamAntagonist
- type: GhostRoleMobSpawner
prototype: MobXenomorphLarva
- type: GhostRoleAntagSpawner

View File

@@ -0,0 +1,16 @@
- type: entity
id: MobXenomorphFaceHuggerLamarr
parent: MobXenomorphFaceHugger
name: Lamarr
description: A former nightmare candidate, now an exemplary pet.
components:
- type: FaceHugger
knockdownTime: 0
infectionPrototype: null
damageOnImpact:
types:
Blunt: 2
- type: UseDelay
delay: 7
- type: StealTarget
stealGroup: AnimalLamarr

View File

@@ -1,6 +1,8 @@
- type: entity
parent:
- BaseSimpleMob
- BaseMob
- MobDamageable
- MobPolymorphable
- MobCombat
- MobBloodstream
- MobFlammable
@@ -14,10 +16,20 @@
Toxin: -5
Airloss: -10
Brute: -5
- type: Pinpointer
component: XenomorphQueen
alert: QueenFinder
isActive: true
canToggle: false
canEmag: false
canExamine: false
- type: ThermalVision
toggleAction: ToggleThermalVisionXenomorph
color: "#7d0cc9"
lightRadius: 10
strength: 0
noise: 0
tint: 3, 3, 3
- type: NameIdentifier
group: GenericNumber
- type: CombatMode

View File

@@ -46,53 +46,23 @@
heatDamageThreshold: 360
coldDamageThreshold: -150
currentTemperature: 310.15
- type: EquipOnCollide
slot: mask
blockingSlot: head
blacklist:
components:
- XenomorphInfected
- XenomorphLarvaVictim
- Ghost
- type: EquipOnPickUp
slot: mask
blockingSlot: head
blacklist:
components:
- XenomorphInfected
- XenomorphLarvaVictim
- Ghost
- type: EquipOnMeleeHit
slot: mask
blockingSlot: head
blacklist:
components:
- XenomorphInfected
- XenomorphLarvaVictim
- Ghost
- type: EffectsOnEquip
slot: mask
blacklist:
components:
- XenomorphInfected
- XenomorphLarvaVictim
- Ghost
effects:
- !type:Paralyze
paralyzeTime: 5
- type: Butcherable
spawned:
- id: FoodMeatXeno
amount: 1
- type: FaceHugger
slot: mask
blacklist:
components:
- XenomorphInfected
- XenomorphLarvaVictim
- Silicon
- Ghost
allowedPassiveDamageStates:
- Alive
passiveDamage:
damageOnImpact:
types:
Blunt: 15
damageOnInfect:
groups:
Genetic: 1
Genetic: 100
- type: NameIdentifier
group: GenericNumber
- type: NpcFactionMember

View File

@@ -15,6 +15,7 @@
- map: [ "pocket2" ]
- type: Xenomorph
caste: Queen
- type: XenomorphQueen
- type: TailLash
tailDamage:
groups:
@@ -54,6 +55,9 @@
600: 0.9
645: 0.7
690: 0.6
- type: MovementSpeedModifier
baseWalkSpeed: 2
baseSprintSpeed: 2.5
- type: MeleeWeapon
damage:
groups:

View File

@@ -0,0 +1,81 @@
## Plushies
- type: entity
parent: BasePlushie
id: PlushieSanabi
name: brigadier plushie
description: A small stuffed doll of the brigadier general.
components:
- type: Item
size: Normal
inhandVisuals:
left:
- state: sanabi-inhand-left
right:
- state: sanabi-inhand-right
- type: Sprite
sprite: _White/Objects/Fun/sanabi.rsi
state: sanabi
# MISC
- type: entity
parent: ClothingMaskBase
id: FaceHuggerToys
name: xenomorph facehugger
description: A toy often used to play pranks on other crew members by putting it in their beds. It takes a bit to recharge after latching onto something.
suffix: Toys
components:
- type: Sprite
noRot: true
sprite: _White/Mobs/Aliens/Xenomorphs/facehugger.rsi
layers:
- map: ["enum.DamageStateVisualLayers.Base"]
state: facehugger
- type: Clothing
sprite: _White/Mobs/Aliens/Xenomorphs/facehugger.rsi
slots: [mask]
- type: IngestionBlocker
- type: Blindfold
- type: AddAccentClothing
accent: ReplacementAccent
replacement: mumble
- type: FaceHugger
blacklist:
components:
- Ghost
knockdownTime: 0
infectionPrototype: null
damageOnImpact:
types:
Blunt: 0
- type: MeleeWeapon
hidden: true
canHeavyAttack: false
angle: 0
damage:
types:
Blunt: 0
- type: Physics
bodyType: Dynamic
- type: CollisionWake
enabled: false
- type: Fixtures
fixtures:
slips:
shape:
!type:PhysShapeCircle
radius: 0.35
layer:
- SlipLayer
hard: false
fix1:
shape:
!type:PhysShapeCircle
radius: 0.35
density: 10
mask:
- ItemMask
- type: Tag
tags:
- XenomorphItem

View File

@@ -0,0 +1,19 @@
- type: entity
parent: BaseItem
id: XenomorphPromotion
name: royal parasite
description: Inject this into one of your grown children to promote her to a Praetorian!
categories: [ HideSpawnMenu ]
components:
- type: Sprite
sprite: _White/Objects/Misc/xenomorph_promotion.rsi
state: icon
- type: Item
size: Ginormous
- type: Unremoveable
deleteOnDrop: true
- type: DeleteOnDrop
- type: XenomorphPromotion
- type: Tag
tags:
- XenomorphItem

View File

@@ -1,9 +1,12 @@
- type: entity
id: BulletAcidLarge
id: BulletNeurotoxin
parent: BulletAcid
name: neurotoxin spit
categories: [ HideSpawnMenu ]
components:
- type: StaminaDamageOnCollide
damage: 65
- type: Projectile
damage:
types:
Caustic: 35
Caustic: 1

View File

@@ -21,10 +21,7 @@
!type:PhysShapeAabb
bounds: "-0.45,-0.45,0.45,0.05"
density: 190
mask:
- TableMask
layer:
- TableLayer
- BulletImpassable
- type: RequireProjectileTarget
- type: Damageable
@@ -63,6 +60,7 @@
- type: Strap
position: Down
rotation: -90
selfUnBuckleDelay: 100
- type: Transform
anchored: true
noRot: true

View File

@@ -63,8 +63,23 @@
!type:PhysShapeAabb
bounds: "-0.45,-0.45,0.45,0.05"
density: 190
mask:
- TableMask
layer:
- TableLayer
- BulletImpassable
- type: entity
parent: XenomorphEgg
id: XenomorphEggBurst
suffix: Burst
components:
- type: Sprite
sprite: _White/Structures/Furniture/xenomorph_egg.rsi
noRot: true
layers:
- state: egg_burst
map: [ "status" ]
- type: Icon
sprite: _White/Structures/Furniture/xenomorph_egg.rsi
state: egg_burst
- type: XenomorphEgg
faceHuggerPrototype: null
status: Burst

View File

@@ -0,0 +1,28 @@
- type: entity
parent: GlassBox
id: GlassBoxLamarrFilled
suffix: Lamarr, Filled
components:
- type: Sprite
sprite: Structures/Storage/glassbox.rsi
layers:
- state: base
- sprite: _White/Mobs/Aliens/Xenomorphs/facehugger.rsi
state: facehugger
map: ["enum.ItemCabinetVisuals.Layer"]
visible: true
- state: glass
map: ["enum.OpenableVisuals.Layer"]
- state: locked
shader: unshaded
map: ["enum.LockVisualLayers.Lock"]
- type: AccessReader
access: [["ResearchDirector"]]
- type: ItemSlots
slots:
ItemCabinet:
startingItem: MobXenomorphFaceHuggerLamarr
ejectOnInteract: true
whitelist:
components:
- FaceHugger

View File

@@ -53,6 +53,8 @@
earliestStart: 35
reoccurrenceDelay: 50
- type: VentSpawnRule
- type: AntagSpawner
prototype: MobXenomorphLarva
- type: XenomorphsRule
- type: AntagObjectives
objectives:

View File

@@ -0,0 +1,8 @@
# Thief Animal
- type: stealTargetGroup
id: AnimalLamarr
name: steal-target-groups-animal-lamarr
sprite:
sprite: _White/Mobs/Aliens/Xenomorphs/facehugger.rsi
state: facehugger

View File

@@ -0,0 +1,10 @@
- type: entity
parent: BaseThiefStealAnimalObjective
id: LamarrStealObjective
components:
- type: NotJobRequirement
job: ResearchDirector
- type: StealCondition
stealGroup: AnimalLamarr
- type: Objective
difficulty: 2

View File

@@ -5,3 +5,11 @@
completetime: 0.1
materials:
PrizeTicket: 50
- type: latheRecipe
id: FaceHuggerToys
result: FaceHuggerToys
applyMaterialDiscount: false
completetime: 0.1
materials:
PrizeTicket: 100

View File

@@ -21,7 +21,7 @@
- type: xenomorphCaste
id: Praetorian
name: xenomorph-caste-praetorian
# needCasteDeath: Queen - TODO: Royal larva
needCasteDeath: Queen
maxCount: 1
- type: xenomorphCaste

View File

@@ -28,11 +28,14 @@
{
"name": "tail_attack"
},
{
"name": "plasma_transfer_off"
},
{
"name": "plasma_transfer_on"
},
{
"name": "plasma_transfer_off"
"name": "promote"
},
{
"name": "acid"

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

View File

@@ -7,8 +7,47 @@
"y": 32
},
"states": [
{
"name": "close",
"delays": [
[
1.0,
1.0
]
]
},
{
"name": "far",
"delays": [
[
4.0,
4.0
]
]
},
{
"name": "medium",
"delays": [
[
2.0,
2.0
]
]
},
{
"name": "queen_finder"
},
{
"name": "reached",
"delays": [
[
0.5,
0.5
]
]
},
{
"name": "unknown"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

View File

@@ -0,0 +1,14 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "from https://github.com/tgstation/tgstation/blob/icons/mob/actions/actions_xeno.dmi",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
}
]
}