From bafdcfa459b4c4e932cb9c42cfecf5f7bbffaa8d Mon Sep 17 00:00:00 2001 From: Spatison <137375981+Spatison@users.noreply.github.com> Date: Sat, 30 Aug 2025 22:40:47 +0300 Subject: [PATCH] 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> --- Content.Client/Pinpointer/PinpointerSystem.cs | 29 +++- .../_White/Inventory/WhiteInventorySystem.cs | 5 - Content.Server/Antag/AntagSelectionSystem.cs | 3 + Content.Server/Pinpointer/PinpointerSystem.cs | 24 ++- .../_White/Actions/ActionsSystem.cs | 30 ++-- .../Components/EffectsOnEquipComponent.cs | 17 -- .../Inventory/WhiteInventorySystem.Equip.cs | 30 ---- .../_White/Inventory/WhiteInventorySystem.cs | 13 -- .../Xenomorphs/Egg/XenomorphEggSystem.cs | 8 +- .../Evolution/XenomorphEvolutionSystem.cs | 47 +++--- .../FaceHugger/FaceHuggerComponent.cs | 41 ++++- .../Xenomorphs/FaceHugger/FaceHuggerSystem.cs | 145 ++++++++++++++++-- .../Queen/XenomorphPromotionComponent.cs | 21 +++ .../Xenomorphs/Queen/XenomorphQueenSystem.cs | 94 ++++++++++++ .../Buckle/Components/BuckleComponent.cs | 6 + .../Buckle/Components/StrapComponent.cs | 9 ++ .../Buckle/SharedBuckleSystem.Buckle.cs | 21 +++ .../Pinpointer/PinpointerComponent.cs | 18 ++- .../Pinpointer/SharedPinpointerSystem.cs | 7 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- .../_White/Actions/Events/SpawnActionEvent.cs | 21 ++- .../Actions/PlasmaCostActionComponent.cs | 3 + .../_White/Actions/PlasmaCostActionSystem.cs | 3 +- ...Equip.cs => WhiteInventorySystem.Equip.cs} | 3 +- ...ntorySystem.cs => WhiteInventorySystem.cs} | 2 +- .../Components/PlasmaAmmoProviderComponent.cs | 15 ++ .../Systems/PlasmaAmmoProviderSystem.cs | 45 ++++++ .../Xenomorphs/Egg/XenomorphEggComponent.cs | 8 +- Content.Shared/_White/Xenomorphs/Event.cs | 11 +- .../Queen/XenomorphQueenComponent.cs | 29 ++++ .../Locale/en-US/_white/alerts/alerts.ftl | 7 +- .../conditions/steal-target-groups.ftl | 1 + .../objects/specific/chemistry/syringes.ftl | 2 - .../en-US/_white/xenomorphs/face-hugger.ftl | 7 + .../Locale/en-US/_white/xenomorphs/queen.ftl | 2 + .../ru-RU/WWDP_TRANSLATION/_MainS/entity.ftl | 4 - .../structures/furniture/xenomorph_egg.ftl | 4 + .../entities/structures/storage/glass_box.ftl | 3 + .../Locale/ru-RU/_white/alerts/alerts.ftl | 7 +- .../conditions/steal-target-groups.ftl | 1 + .../entities}/actions/xenomorph.ftl | 19 +-- .../_white/prototypes/entities/fun/toys.ftl | 6 + .../prototypes/entities/mobs/player/pets.ftl | 3 + .../objects/misc/xenomorph_promotion.ftl | 3 + .../ru-RU/_white/xenomorphs/face-hugger.ftl | 7 + .../Locale/ru-RU/_white/xenomorphs/queen.ftl | 2 + .../Entities/Objects/Specific/Mail/mail.yml | 8 +- .../Entities/Markers/Spawners/Random/toy.yml | 5 +- .../Entities/Objects/Decoration/present.yml | 8 +- .../Weapons/Guns/Projectiles/projectiles.yml | 2 +- .../Entities/Structures/Machines/lathe.yml | 1 + .../Prototypes/_White/Actions/xenomorph.yml | 54 +++++-- .../Prototypes/_White/Alerts/xenomorph.yml | 20 +++ .../_White/Body/Organs/Animal/xenomorph.yml | 9 +- .../Prototypes/_White/Entities/Fun/sanabi.yml | 17 -- .../Entities/Markers/Spawners/ghost_roles.yml | 3 - .../_White/Entities/Mobs/Player/pets.yml | 16 ++ .../_White/Entities/Mobs/Xenomorphs/base.yml | 14 +- .../Entities/Mobs/Xenomorphs/facehugger.yml | 48 ++---- .../_White/Entities/Mobs/Xenomorphs/queen.yml | 4 + .../Entities/{ => Objects}/Fun/snowball.yml | 0 .../_White/Entities/Objects/Fun/toys.yml | 81 ++++++++++ .../Objects/Misc/xenomorph_promotion.yml | 19 +++ .../Weapons/Guns/Projectiles/projectiles.yml | 7 +- .../Structures/Furniture/resin_nest.yml | 4 +- .../Structures/Furniture/xenomorph_egg.yml | 21 ++- .../Entities/Structures/Storage/glass_box.yml | 28 ++++ .../Prototypes/_White/GameRules/events.yml | 2 + .../_White/Objective/stealTargetGroups.yml | 8 + .../Prototypes/_White/Objective/thief.yml | 10 ++ .../_White/Recipes/Lathes/prizecounter.yml | 8 + .../Prototypes/_White/xenomorph_cast.yml | 2 +- .../Interface/Actions/xenomorph.rsi/meta.json | 5 +- .../Actions/xenomorph.rsi/promote.png | Bin 0 -> 388 bytes .../Alerts/queen_finder.rsi/close.png | Bin 0 -> 603 bytes .../Interface/Alerts/queen_finder.rsi/far.png | Bin 0 -> 215 bytes .../Alerts/queen_finder.rsi/medium.png | Bin 0 -> 603 bytes .../Alerts/queen_finder.rsi/meta.json | 39 +++++ .../Alerts/queen_finder.rsi/reached.png | Bin 0 -> 157 bytes .../Alerts/queen_finder.rsi/unknown.png | Bin 0 -> 96 bytes .../Misc/xenomorph_promotion.rsi/icon.png | Bin 0 -> 239 bytes .../Misc/xenomorph_promotion.rsi/meta.json | 14 ++ 82 files changed, 988 insertions(+), 257 deletions(-) delete mode 100644 Content.Client/_White/Inventory/WhiteInventorySystem.cs delete mode 100644 Content.Server/_White/Inventory/Components/EffectsOnEquipComponent.cs delete mode 100644 Content.Server/_White/Inventory/WhiteInventorySystem.Equip.cs delete mode 100644 Content.Server/_White/Inventory/WhiteInventorySystem.cs create mode 100644 Content.Server/_White/Xenomorphs/Queen/XenomorphPromotionComponent.cs create mode 100644 Content.Server/_White/Xenomorphs/Queen/XenomorphQueenSystem.cs rename Content.Shared/_White/Inventory/{SharedWhiteInventorySystem.Equip.cs => WhiteInventorySystem.Equip.cs} (97%) rename Content.Shared/_White/Inventory/{SharedWhiteInventorySystem.cs => WhiteInventorySystem.cs} (68%) create mode 100644 Content.Shared/_White/Weapons/Ranged/Components/PlasmaAmmoProviderComponent.cs create mode 100644 Content.Shared/_White/Weapons/Ranged/Systems/PlasmaAmmoProviderSystem.cs create mode 100644 Content.Shared/_White/Xenomorphs/Queen/XenomorphQueenComponent.cs create mode 100644 Resources/Locale/en-US/_white/objectives/conditions/steal-target-groups.ftl delete mode 100644 Resources/Locale/en-US/_white/prototypes/entities/objects/specific/chemistry/syringes.ftl create mode 100644 Resources/Locale/en-US/_white/xenomorphs/face-hugger.ftl create mode 100644 Resources/Locale/en-US/_white/xenomorphs/queen.ftl create mode 100644 Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/storage/glass_box.ftl create mode 100644 Resources/Locale/ru-RU/_white/objectives/conditions/steal-target-groups.ftl rename Resources/Locale/ru-RU/{WWDP_TRANSLATION/_white/prototypes => _white/prototypes/entities}/actions/xenomorph.ftl (78%) create mode 100644 Resources/Locale/ru-RU/_white/prototypes/entities/fun/toys.ftl create mode 100644 Resources/Locale/ru-RU/_white/prototypes/entities/mobs/player/pets.ftl create mode 100644 Resources/Locale/ru-RU/_white/prototypes/entities/objects/misc/xenomorph_promotion.ftl create mode 100644 Resources/Locale/ru-RU/_white/xenomorphs/face-hugger.ftl create mode 100644 Resources/Locale/ru-RU/_white/xenomorphs/queen.ftl delete mode 100644 Resources/Prototypes/_White/Entities/Fun/sanabi.yml create mode 100644 Resources/Prototypes/_White/Entities/Mobs/Player/pets.yml rename Resources/Prototypes/_White/Entities/{ => Objects}/Fun/snowball.yml (100%) create mode 100644 Resources/Prototypes/_White/Entities/Objects/Fun/toys.yml create mode 100644 Resources/Prototypes/_White/Entities/Objects/Misc/xenomorph_promotion.yml create mode 100644 Resources/Prototypes/_White/Entities/Structures/Storage/glass_box.yml create mode 100644 Resources/Prototypes/_White/Objective/stealTargetGroups.yml create mode 100644 Resources/Prototypes/_White/Objective/thief.yml create mode 100644 Resources/Textures/_White/Interface/Actions/xenomorph.rsi/promote.png create mode 100644 Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/close.png create mode 100644 Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/far.png create mode 100644 Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/medium.png create mode 100644 Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/reached.png create mode 100644 Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/unknown.png create mode 100644 Resources/Textures/_White/Objects/Misc/xenomorph_promotion.rsi/icon.png create mode 100644 Resources/Textures/_White/Objects/Misc/xenomorph_promotion.rsi/meta.json diff --git a/Content.Client/Pinpointer/PinpointerSystem.cs b/Content.Client/Pinpointer/PinpointerSystem.cs index 486241b56b..d43d5cf7a4 100644 --- a/Content.Client/Pinpointer/PinpointerSystem.cs +++ b/Content.Client/Pinpointer/PinpointerSystem.cs @@ -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(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(); 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; diff --git a/Content.Client/_White/Inventory/WhiteInventorySystem.cs b/Content.Client/_White/Inventory/WhiteInventorySystem.cs deleted file mode 100644 index 3e64f30920..0000000000 --- a/Content.Client/_White/Inventory/WhiteInventorySystem.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Content.Shared._White.Inventory; - -namespace Content.Client._White.Inventory; - -public sealed class WhiteInventorySystem : SharedWhiteInventorySystem; diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 8b75bfe7e1..8d456a0ee0 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -68,6 +68,9 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem ent, ref TakeGhostRoleEvent args) { + if (args.TookRole) + return; + if (ent.Comp.Rule is not { } rule || ent.Comp.Definition is not { } def) return; diff --git a/Content.Server/Pinpointer/PinpointerSystem.cs b/Content.Server/Pinpointer/PinpointerSystem.cs index eebf9cbbfd..47273e26fe 100644 --- a/Content.Server/Pinpointer/PinpointerSystem.cs +++ b/Content.Server/Pinpointer/PinpointerSystem.cs @@ -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(); + // WD EDIT START + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + // WD EDIT END SubscribeLocalEvent(OnActivate); SubscribeLocalEvent(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; } diff --git a/Content.Server/_White/Actions/ActionsSystem.cs b/Content.Server/_White/Actions/ActionsSystem.cs index 743e008cbd..617c32151b 100644 --- a/Content.Server/_White/Actions/ActionsSystem.cs +++ b/Content.Server/_White/Actions/ActionsSystem.cs @@ -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 diff --git a/Content.Server/_White/Inventory/Components/EffectsOnEquipComponent.cs b/Content.Server/_White/Inventory/Components/EffectsOnEquipComponent.cs deleted file mode 100644 index 5855ee67cc..0000000000 --- a/Content.Server/_White/Inventory/Components/EffectsOnEquipComponent.cs +++ /dev/null @@ -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 Effects = new (); - - [DataField] - public EntityWhitelist? Blacklist; -} diff --git a/Content.Server/_White/Inventory/WhiteInventorySystem.Equip.cs b/Content.Server/_White/Inventory/WhiteInventorySystem.Equip.cs deleted file mode 100644 index ea26e93587..0000000000 --- a/Content.Server/_White/Inventory/WhiteInventorySystem.Equip.cs +++ /dev/null @@ -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(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); - } -} diff --git a/Content.Server/_White/Inventory/WhiteInventorySystem.cs b/Content.Server/_White/Inventory/WhiteInventorySystem.cs deleted file mode 100644 index db8ee93f19..0000000000 --- a/Content.Server/_White/Inventory/WhiteInventorySystem.cs +++ /dev/null @@ -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(); - } -} diff --git a/Content.Server/_White/Xenomorphs/Egg/XenomorphEggSystem.cs b/Content.Server/_White/Xenomorphs/Egg/XenomorphEggSystem.cs index e18566c50e..4ac404fef3 100644 --- a/Content.Server/_White/Xenomorphs/Egg/XenomorphEggSystem.cs +++ b/Content.Server/_White/Xenomorphs/Egg/XenomorphEggSystem.cs @@ -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(spawned, out var equipOn)) + if (!TryComp(spawned, out var equipOn)) return; foreach (var entity in _entityLookup.GetEntitiesInRange(coordinates, component.BurstRange)) { - if (_whiteInventory.TryEquip(spawned, entity, equipOn)) + if (_faceHugger.TryEquipFaceHugger(spawned, entity, equipOn)) return; } } diff --git a/Content.Server/_White/Xenomorphs/Evolution/XenomorphEvolutionSystem.cs b/Content.Server/_White/Xenomorphs/Evolution/XenomorphEvolutionSystem.cs index 8201dbed30..80c3748c98 100644 --- a/Content.Server/_White/Xenomorphs/Evolution/XenomorphEvolutionSystem.cs +++ b/Content.Server/_White/Xenomorphs/Evolution/XenomorphEvolutionSystem.cs @@ -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(); 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(out var xenomorph, _componentFactory)) + if (evolveTo == null + || !_protoManager.TryIndex(evolveTo, out var xenomorphPrototype) + || !xenomorphPrototype.TryGetComponent(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); diff --git a/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerComponent.cs b/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerComponent.cs index 743e3a4317..5897758093 100644 --- a/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerComponent.cs +++ b/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerComponent.cs @@ -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 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; } diff --git a/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs b/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs index 6faec78625..63b283371c 100644 --- a/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs +++ b/Content.Server/_White/Xenomorphs/FaceHugger/FaceHuggerSystem.cs @@ -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(OnCollideEvent); + SubscribeLocalEvent(OnMeleeHit); + SubscribeLocalEvent(OnPickedUp); + SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent(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(); + 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(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(uid)) - return; + if (!component.Active || _mobState.IsDead(uid) || _entityWhitelist.IsBlacklistPass(component.Blacklist, target)) + return false; - var passiveDamage = EnsureComp(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(headUid, out var headBlocker) + && headBlocker.Enabled) + blocker = headUid; + + if (!blocker.HasValue && _inventory.TryGetSlotEntity(target, "mask", out var maskUid)) + { + if (TryComp(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; } } diff --git a/Content.Server/_White/Xenomorphs/Queen/XenomorphPromotionComponent.cs b/Content.Server/_White/Xenomorphs/Queen/XenomorphPromotionComponent.cs new file mode 100644 index 0000000000..6c69113924 --- /dev/null +++ b/Content.Server/_White/Xenomorphs/Queen/XenomorphPromotionComponent.cs @@ -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> CasteWhitelist = new(); + + [ViewVariables] + public TimeSpan EvolutionDelay = TimeSpan.FromSeconds(3); +} diff --git a/Content.Server/_White/Xenomorphs/Queen/XenomorphQueenSystem.cs b/Content.Server/_White/Xenomorphs/Queen/XenomorphQueenSystem.cs new file mode 100644 index 0000000000..15a3a9e7a6 --- /dev/null +++ b/Content.Server/_White/Xenomorphs/Queen/XenomorphQueenSystem.cs @@ -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(OnMapInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnPromotionAction); + + SubscribeLocalEvent(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(component.Promotion.Value); + promotion.CasteWhitelist = component.CasteWhitelist; + promotion.PromoteTo = component.PromoteTo; + promotion.EvolutionDelay = component.EvolutionDelay; + + if (TryComp(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(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; + } +} diff --git a/Content.Shared/Buckle/Components/BuckleComponent.cs b/Content.Shared/Buckle/Components/BuckleComponent.cs index 1518ccea9b..b2d93c1a96 100644 --- a/Content.Shared/Buckle/Components/BuckleComponent.cs +++ b/Content.Shared/Buckle/Components/BuckleComponent.cs @@ -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 Strap, Enti [ByRefEvent] public readonly record struct UnbuckledEvent(Entity Strap, Entity Buckle); +// WD EDIT START +[Serializable, NetSerializable] +public sealed partial class UnbuckleDoAfterEvent : SimpleDoAfterEvent; +// WD EDIT END + [Serializable, NetSerializable] public enum BuckleVisuals { diff --git a/Content.Shared/Buckle/Components/StrapComponent.cs b/Content.Shared/Buckle/Components/StrapComponent.cs index 79dc686c7d..2b18e09870 100644 --- a/Content.Shared/Buckle/Components/StrapComponent.cs +++ b/Content.Shared/Buckle/Components/StrapComponent.cs @@ -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 /// [DataField] public bool BuckleOnInteractHand = true; + + // WD EDIT START + /// + /// Delay, that must occur, before user can unbuckle + /// + [DataField] + public TimeSpan SelfUnBuckleDelay = TimeSpan.Zero; + // WD EDIT END } public enum StrapPosition diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 744d84031a..6d3b42d69b 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -32,6 +32,7 @@ public abstract partial class SharedBuckleSystem { public static ProtoId 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(OnBuckleStandAttempt); SubscribeLocalEvent(OnBuckleThrowPushbackAttempt); SubscribeLocalEvent(OnBuckleUpdateCanMove); + + SubscribeLocalEvent(OnUnbuckleDoAfter); // WD EDIT } private void OnBuckleComponentShutdown(Entity 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; } diff --git a/Content.Shared/Pinpointer/PinpointerComponent.cs b/Content.Shared/Pinpointer/PinpointerComponent.cs index e83a2e38d6..07eebf63ec 100644 --- a/Content.Shared/Pinpointer/PinpointerComponent.cs +++ b/Content.Shared/Pinpointer/PinpointerComponent.cs @@ -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? 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] diff --git a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs index 7f6b889125..cd7ee132b9 100644 --- a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs +++ b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs @@ -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; } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 83ef5943ad..770f813b2a 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -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(uid, out var cartridge)) return cartridge; diff --git a/Content.Shared/_White/Actions/Events/SpawnActionEvent.cs b/Content.Shared/_White/Actions/Events/SpawnActionEvent.cs index 11bf83e95c..6410359786 100644 --- a/Content.Shared/_White/Actions/Events/SpawnActionEvent.cs +++ b/Content.Shared/_White/Actions/Events/SpawnActionEvent.cs @@ -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))] + public int BlockedCollisionMask; + + [DataField(customTypeSerializer: typeof(FlagSerializer))] + public int BlockedCollisionLayer; } /// @@ -58,8 +62,11 @@ public sealed partial class PlaceTileEntityEvent : WorldTargetActionEvent [DataField] public SoundSpecifier? Audio; - [DataField] - public CollisionGroup? BlockedCollision; + [DataField(customTypeSerializer: typeof(FlagSerializer))] + public int BlockedCollisionMask; + + [DataField(customTypeSerializer: typeof(FlagSerializer))] + public int BlockedCollisionLayer; /// /// 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; } diff --git a/Content.Shared/_White/Actions/PlasmaCostActionComponent.cs b/Content.Shared/_White/Actions/PlasmaCostActionComponent.cs index 1168b6bb99..4374509f6b 100644 --- a/Content.Shared/_White/Actions/PlasmaCostActionComponent.cs +++ b/Content.Shared/_White/Actions/PlasmaCostActionComponent.cs @@ -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; } diff --git a/Content.Shared/_White/Actions/PlasmaCostActionSystem.cs b/Content.Shared/_White/Actions/PlasmaCostActionSystem.cs index 961bf7ecbc..c0a6320d87 100644 --- a/Content.Shared/_White/Actions/PlasmaCostActionSystem.cs +++ b/Content.Shared/_White/Actions/PlasmaCostActionSystem.cs @@ -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); } } diff --git a/Content.Shared/_White/Inventory/SharedWhiteInventorySystem.Equip.cs b/Content.Shared/_White/Inventory/WhiteInventorySystem.Equip.cs similarity index 97% rename from Content.Shared/_White/Inventory/SharedWhiteInventorySystem.Equip.cs rename to Content.Shared/_White/Inventory/WhiteInventorySystem.Equip.cs index c782194aa3..7e54900024 100644 --- a/Content.Shared/_White/Inventory/SharedWhiteInventorySystem.Equip.cs +++ b/Content.Shared/_White/Inventory/WhiteInventorySystem.Equip.cs @@ -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(OnCollideEvent); diff --git a/Content.Shared/_White/Inventory/SharedWhiteInventorySystem.cs b/Content.Shared/_White/Inventory/WhiteInventorySystem.cs similarity index 68% rename from Content.Shared/_White/Inventory/SharedWhiteInventorySystem.cs rename to Content.Shared/_White/Inventory/WhiteInventorySystem.cs index d47d890c32..87fcde7280 100644 --- a/Content.Shared/_White/Inventory/SharedWhiteInventorySystem.cs +++ b/Content.Shared/_White/Inventory/WhiteInventorySystem.cs @@ -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() { diff --git a/Content.Shared/_White/Weapons/Ranged/Components/PlasmaAmmoProviderComponent.cs b/Content.Shared/_White/Weapons/Ranged/Components/PlasmaAmmoProviderComponent.cs new file mode 100644 index 0000000000..ea2987b656 --- /dev/null +++ b/Content.Shared/_White/Weapons/Ranged/Components/PlasmaAmmoProviderComponent.cs @@ -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; +} diff --git a/Content.Shared/_White/Weapons/Ranged/Systems/PlasmaAmmoProviderSystem.cs b/Content.Shared/_White/Weapons/Ranged/Systems/PlasmaAmmoProviderSystem.cs new file mode 100644 index 0000000000..8a494fb799 --- /dev/null +++ b/Content.Shared/_White/Weapons/Ranged/Systems/PlasmaAmmoProviderSystem.cs @@ -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(OnTakeAmmo); + SubscribeLocalEvent(OnGetAmmoCount); + } + + private void OnTakeAmmo(EntityUid uid, PlasmaAmmoProviderComponent component, ref TakeAmmoEvent args) + { + if (!TryComp(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(uid, out var plasmaVessel)) + return; + + args.Capacity = (int) (plasmaVessel.MaxPlasma / component.FireCost); + args.Count = (int) (plasmaVessel.Plasma / component.FireCost); + } +} diff --git a/Content.Shared/_White/Xenomorphs/Egg/XenomorphEggComponent.cs b/Content.Shared/_White/Xenomorphs/Egg/XenomorphEggComponent.cs index 8cc6fc8142..5fd6356ded 100644 --- a/Content.Shared/_White/Xenomorphs/Egg/XenomorphEggComponent.cs +++ b/Content.Shared/_White/Xenomorphs/Egg/XenomorphEggComponent.cs @@ -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 diff --git a/Content.Shared/_White/Xenomorphs/Event.cs b/Content.Shared/_White/Xenomorphs/Event.cs index 4e2c3fcb81..d6294ac441 100644 --- a/Content.Shared/_White/Xenomorphs/Event.cs +++ b/Content.Shared/_White/Xenomorphs/Event.cs @@ -16,10 +16,14 @@ public sealed partial class XenomorphEvolutionDoAfterEvent : DoAfterEvent [DataField] public ProtoId Caste; - public XenomorphEvolutionDoAfterEvent(EntProtoId choice, ProtoId caste) + [DataField] + public bool CheckNeedCasteDeath; + + public XenomorphEvolutionDoAfterEvent(EntProtoId choice, ProtoId 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 Caste = caste; } -public sealed partial class BeforeXenomorphEvolutionEvent(ProtoId caste) : CancellableEntityEventArgs +public sealed partial class BeforeXenomorphEvolutionEvent(ProtoId caste, bool checkNeedCasteDeath = true) : CancellableEntityEventArgs { public ProtoId Caste = caste; + public bool CheckNeedCasteDeath = checkNeedCasteDeath; } public sealed partial class PlasmaAmountChangeEvent(FixedPoint2 amount) : EntityEventArgs diff --git a/Content.Shared/_White/Xenomorphs/Queen/XenomorphQueenComponent.cs b/Content.Shared/_White/Xenomorphs/Queen/XenomorphQueenComponent.cs new file mode 100644 index 0000000000..1033b9c11e --- /dev/null +++ b/Content.Shared/_White/Xenomorphs/Queen/XenomorphQueenComponent.cs @@ -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> CasteWhitelist = new() { "Drone", "Hunter", "Sentinel", }; + + [DataField] + public TimeSpan EvolutionDelay = TimeSpan.FromSeconds(3); + + [ViewVariables] + public EntityUid? Promotion; + + [ViewVariables] + public EntityUid? PromotionAction; +} diff --git a/Resources/Locale/en-US/_white/alerts/alerts.ftl b/Resources/Locale/en-US/_white/alerts/alerts.ftl index cdc300a00c..44b4bb9487 100644 --- a/Resources/Locale/en-US/_white/alerts/alerts.ftl +++ b/Resources/Locale/en-US/_white/alerts/alerts.ftl @@ -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. diff --git a/Resources/Locale/en-US/_white/objectives/conditions/steal-target-groups.ftl b/Resources/Locale/en-US/_white/objectives/conditions/steal-target-groups.ftl new file mode 100644 index 0000000000..7872da8eb4 --- /dev/null +++ b/Resources/Locale/en-US/_white/objectives/conditions/steal-target-groups.ftl @@ -0,0 +1 @@ +steal-target-groups-animal-lamarr = Lamarr diff --git a/Resources/Locale/en-US/_white/prototypes/entities/objects/specific/chemistry/syringes.ftl b/Resources/Locale/en-US/_white/prototypes/entities/objects/specific/chemistry/syringes.ftl deleted file mode 100644 index 9bf0b32e37..0000000000 --- a/Resources/Locale/en-US/_white/prototypes/entities/objects/specific/chemistry/syringes.ftl +++ /dev/null @@ -1,2 +0,0 @@ -ent-MiniSyringe = mini syringe -ent-MiniSyringe-desc = A regular syringe, reshaped to fit inside of a gun. \ No newline at end of file diff --git a/Resources/Locale/en-US/_white/xenomorphs/face-hugger.ftl b/Resources/Locale/en-US/_white/xenomorphs/face-hugger.ftl new file mode 100644 index 0000000000..f89eb1e780 --- /dev/null +++ b/Resources/Locale/en-US/_white/xenomorphs/face-hugger.ftl @@ -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 } diff --git a/Resources/Locale/en-US/_white/xenomorphs/queen.ftl b/Resources/Locale/en-US/_white/xenomorphs/queen.ftl new file mode 100644 index 0000000000..a0a22a27de --- /dev/null +++ b/Resources/Locale/en-US/_white/xenomorphs/queen.ftl @@ -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! diff --git a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_MainS/entity.ftl b/Resources/Locale/ru-RU/WWDP_TRANSLATION/_MainS/entity.ftl index ee5cd2d266..d4ed3780e0 100644 --- a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_MainS/entity.ftl +++ b/Resources/Locale/ru-RU/WWDP_TRANSLATION/_MainS/entity.ftl @@ -16631,10 +16631,6 @@ ent-SmallExplosionInstant = мгновенный взрыв (малый) ent-MediumExplosionInstant = мгновенный взрыв (средний) -ent-PlushieSanabi = плюшевая игрушка бригадира - .desc = Маленькая мягкая копия сурового бригадного генерала. Ужасно милая. - - ent-ItemSnowballMaker = снежколеп .desc = Лепит снежки. Весело и опасно. diff --git a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/furniture/xenomorph_egg.ftl b/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/furniture/xenomorph_egg.ftl index 6a027a920b..38ec569b42 100644 --- a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/furniture/xenomorph_egg.ftl +++ b/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/furniture/xenomorph_egg.ftl @@ -1,2 +1,6 @@ ent-XenomorphEgg = яйцо ксеноморфа .desc = Большое пятнистое яйцо. + +ent-XenomorphEggBurst = { ent-XenomorphEgg } + .desc = { ent-XenomorphEgg.desc } + .suffix = Открытое diff --git a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/storage/glass_box.ftl b/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/storage/glass_box.ftl new file mode 100644 index 0000000000..4e5bc3562f --- /dev/null +++ b/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/entities/structures/storage/glass_box.ftl @@ -0,0 +1,3 @@ +ent-GlassBoxLamarrFilled = { ent-GlassBox } + .desc = { ent-GlassBox.desc } + .suffix = Ламарр, Заполненная diff --git a/Resources/Locale/ru-RU/_white/alerts/alerts.ftl b/Resources/Locale/ru-RU/_white/alerts/alerts.ftl index 16ff276e01..755b2761c1 100644 --- a/Resources/Locale/ru-RU/_white/alerts/alerts.ftl +++ b/Resources/Locale/ru-RU/_white/alerts/alerts.ftl @@ -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 = Позволяет вам чувствовать общее направление движения вашей королевы. diff --git a/Resources/Locale/ru-RU/_white/objectives/conditions/steal-target-groups.ftl b/Resources/Locale/ru-RU/_white/objectives/conditions/steal-target-groups.ftl new file mode 100644 index 0000000000..45ee828a3e --- /dev/null +++ b/Resources/Locale/ru-RU/_white/objectives/conditions/steal-target-groups.ftl @@ -0,0 +1 @@ +steal-target-groups-animal-lamarr = Ламарр diff --git a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/actions/xenomorph.ftl b/Resources/Locale/ru-RU/_white/prototypes/entities/actions/xenomorph.ftl similarity index 78% rename from Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/actions/xenomorph.ftl rename to Resources/Locale/ru-RU/_white/prototypes/entities/actions/xenomorph.ftl index 88d5425db8..50d958785f 100644 --- a/Resources/Locale/ru-RU/WWDP_TRANSLATION/_white/prototypes/actions/xenomorph.ftl +++ b/Resources/Locale/ru-RU/_white/prototypes/entities/actions/xenomorph.ftl @@ -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 = Создает королевского паразита, чтобы предоставить одному из ваших детей честь стать вашим преторианцем. diff --git a/Resources/Locale/ru-RU/_white/prototypes/entities/fun/toys.ftl b/Resources/Locale/ru-RU/_white/prototypes/entities/fun/toys.ftl new file mode 100644 index 0000000000..5ec868174e --- /dev/null +++ b/Resources/Locale/ru-RU/_white/prototypes/entities/fun/toys.ftl @@ -0,0 +1,6 @@ +ent-PlushieSanabi = плюшевая игрушка бригадира + .desc = Маленькая мягкая копия сурового генерала бригадира. Ужасно милая. + +ent-FaceHuggerToys = ксеноморф лицехват + .desc = Игрушка, которую часто используют, чтобы подшутить над другими членами экипажа, подкладывая её им в кровати. После того, как она зацепится за что-нибудь, ей требуется некоторое время для перезарядки. + .suffix = Игрушка diff --git a/Resources/Locale/ru-RU/_white/prototypes/entities/mobs/player/pets.ftl b/Resources/Locale/ru-RU/_white/prototypes/entities/mobs/player/pets.ftl new file mode 100644 index 0000000000..5afa55094d --- /dev/null +++ b/Resources/Locale/ru-RU/_white/prototypes/entities/mobs/player/pets.ftl @@ -0,0 +1,3 @@ +ent-MobXenomorphFaceHuggerLamarr = Ламарр + .desc = бывший кандидат в кошмар, а ныне – примерный питомец. + diff --git a/Resources/Locale/ru-RU/_white/prototypes/entities/objects/misc/xenomorph_promotion.ftl b/Resources/Locale/ru-RU/_white/prototypes/entities/objects/misc/xenomorph_promotion.ftl new file mode 100644 index 0000000000..b85eea624e --- /dev/null +++ b/Resources/Locale/ru-RU/_white/prototypes/entities/objects/misc/xenomorph_promotion.ftl @@ -0,0 +1,3 @@ +ent-XenomorphPromotion = королевский паразит + .desc = Введите это в одну из своих взрослых дочерей, чтобы повысить её до преторианца! + .suffix = { ent-BaseItem.suffix } diff --git a/Resources/Locale/ru-RU/_white/xenomorphs/face-hugger.ftl b/Resources/Locale/ru-RU/_white/xenomorphs/face-hugger.ftl new file mode 100644 index 0000000000..904fb19219 --- /dev/null +++ b/Resources/Locale/ru-RU/_white/xenomorphs/face-hugger.ftl @@ -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 } diff --git a/Resources/Locale/ru-RU/_white/xenomorphs/queen.ftl b/Resources/Locale/ru-RU/_white/xenomorphs/queen.ftl new file mode 100644 index 0000000000..b326e1a438 --- /dev/null +++ b/Resources/Locale/ru-RU/_white/xenomorphs/queen.ftl @@ -0,0 +1,2 @@ +xenomorphs-queen-promotion-didnt-pass-whitelist = Вы можете использовать это только с вашими взрослыми детьми, не являющимися королевскими! +xenomorphs-queen-promotion-no-mind = Её разум не может выдержать повышение! diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml index fdaca20590..2d967f8039 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/Mail/mail.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml index c54301e95b..58bf06d59c 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/toy.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Objects/Decoration/present.yml b/Resources/Prototypes/Entities/Objects/Decoration/present.yml index 45ede9157b..091dd31792 100644 --- a/Resources/Prototypes/Entities/Objects/Decoration/present.yml +++ b/Resources/Prototypes/Entities/Objects/Decoration/present.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index b1cf445b8d..1f7babfbdd 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -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: diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 95df47e97d..fb7cb10dd0 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -1911,6 +1911,7 @@ - ToySword - BwoinkHammer - ThronglerToy + - FaceHuggerToys # WD EDIT - type: MaterialStorage whitelist: tags: diff --git a/Resources/Prototypes/_White/Actions/xenomorph.yml b/Resources/Prototypes/_White/Actions/xenomorph.yml index d09094f73b..ffd8a2eafb 100644 --- a/Resources/Prototypes/_White/Actions/xenomorph.yml +++ b/Resources/Prototypes/_White/Actions/xenomorph.yml @@ -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 diff --git a/Resources/Prototypes/_White/Alerts/xenomorph.yml b/Resources/Prototypes/_White/Alerts/xenomorph.yml index 46e4200ed4..99b06d1ca9 100644 --- a/Resources/Prototypes/_White/Alerts/xenomorph.yml +++ b/Resources/Prototypes/_White/Alerts/xenomorph.yml @@ -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" ] diff --git a/Resources/Prototypes/_White/Body/Organs/Animal/xenomorph.yml b/Resources/Prototypes/_White/Body/Organs/Animal/xenomorph.yml index e2e61fca3a..a6367af424 100644 --- a/Resources/Prototypes/_White/Body/Organs/Animal/xenomorph.yml +++ b/Resources/Prototypes/_White/Body/Organs/Animal/xenomorph.yml @@ -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: diff --git a/Resources/Prototypes/_White/Entities/Fun/sanabi.yml b/Resources/Prototypes/_White/Entities/Fun/sanabi.yml deleted file mode 100644 index 39d4ce81f0..0000000000 --- a/Resources/Prototypes/_White/Entities/Fun/sanabi.yml +++ /dev/null @@ -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 - diff --git a/Resources/Prototypes/_White/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/_White/Entities/Markers/Spawners/ghost_roles.yml index 31a4097398..67a35a9266 100644 --- a/Resources/Prototypes/_White/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/_White/Entities/Markers/Spawners/ghost_roles.yml @@ -15,6 +15,3 @@ rules: ghost-role-information-rules-default-team-antagonist mindRoles: - MindRoleGhostRoleTeamAntagonist - - type: GhostRoleMobSpawner - prototype: MobXenomorphLarva - - type: GhostRoleAntagSpawner diff --git a/Resources/Prototypes/_White/Entities/Mobs/Player/pets.yml b/Resources/Prototypes/_White/Entities/Mobs/Player/pets.yml new file mode 100644 index 0000000000..11cb6af153 --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Mobs/Player/pets.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/base.yml b/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/base.yml index 0915c94b48..c4a0bc2cf2 100644 --- a/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/base.yml +++ b/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/base.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/facehugger.yml b/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/facehugger.yml index 987c9003e1..1dd9a3233c 100644 --- a/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/facehugger.yml +++ b/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/facehugger.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/queen.yml b/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/queen.yml index d1ca3a5e2c..14395dbeca 100644 --- a/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/queen.yml +++ b/Resources/Prototypes/_White/Entities/Mobs/Xenomorphs/queen.yml @@ -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: diff --git a/Resources/Prototypes/_White/Entities/Fun/snowball.yml b/Resources/Prototypes/_White/Entities/Objects/Fun/snowball.yml similarity index 100% rename from Resources/Prototypes/_White/Entities/Fun/snowball.yml rename to Resources/Prototypes/_White/Entities/Objects/Fun/snowball.yml diff --git a/Resources/Prototypes/_White/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/_White/Entities/Objects/Fun/toys.yml new file mode 100644 index 0000000000..fcca50b1f7 --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Objects/Fun/toys.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Objects/Misc/xenomorph_promotion.yml b/Resources/Prototypes/_White/Entities/Objects/Misc/xenomorph_promotion.yml new file mode 100644 index 0000000000..5ef67f99b5 --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Objects/Misc/xenomorph_promotion.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index 99eb7060ab..d0490d796b 100644 --- a/Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/_White/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Structures/Furniture/resin_nest.yml b/Resources/Prototypes/_White/Entities/Structures/Furniture/resin_nest.yml index 9044cdb00b..b74b04e7c5 100644 --- a/Resources/Prototypes/_White/Entities/Structures/Furniture/resin_nest.yml +++ b/Resources/Prototypes/_White/Entities/Structures/Furniture/resin_nest.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Structures/Furniture/xenomorph_egg.yml b/Resources/Prototypes/_White/Entities/Structures/Furniture/xenomorph_egg.yml index 70be83c964..0f7a132433 100644 --- a/Resources/Prototypes/_White/Entities/Structures/Furniture/xenomorph_egg.yml +++ b/Resources/Prototypes/_White/Entities/Structures/Furniture/xenomorph_egg.yml @@ -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 diff --git a/Resources/Prototypes/_White/Entities/Structures/Storage/glass_box.yml b/Resources/Prototypes/_White/Entities/Structures/Storage/glass_box.yml new file mode 100644 index 0000000000..6b7f1b29f8 --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Structures/Storage/glass_box.yml @@ -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 diff --git a/Resources/Prototypes/_White/GameRules/events.yml b/Resources/Prototypes/_White/GameRules/events.yml index 245f11ab17..c61e0dd72c 100644 --- a/Resources/Prototypes/_White/GameRules/events.yml +++ b/Resources/Prototypes/_White/GameRules/events.yml @@ -53,6 +53,8 @@ earliestStart: 35 reoccurrenceDelay: 50 - type: VentSpawnRule + - type: AntagSpawner + prototype: MobXenomorphLarva - type: XenomorphsRule - type: AntagObjectives objectives: diff --git a/Resources/Prototypes/_White/Objective/stealTargetGroups.yml b/Resources/Prototypes/_White/Objective/stealTargetGroups.yml new file mode 100644 index 0000000000..584f15826d --- /dev/null +++ b/Resources/Prototypes/_White/Objective/stealTargetGroups.yml @@ -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 diff --git a/Resources/Prototypes/_White/Objective/thief.yml b/Resources/Prototypes/_White/Objective/thief.yml new file mode 100644 index 0000000000..ce2ff81135 --- /dev/null +++ b/Resources/Prototypes/_White/Objective/thief.yml @@ -0,0 +1,10 @@ +- type: entity + parent: BaseThiefStealAnimalObjective + id: LamarrStealObjective + components: + - type: NotJobRequirement + job: ResearchDirector + - type: StealCondition + stealGroup: AnimalLamarr + - type: Objective + difficulty: 2 diff --git a/Resources/Prototypes/_White/Recipes/Lathes/prizecounter.yml b/Resources/Prototypes/_White/Recipes/Lathes/prizecounter.yml index 736fc84b2d..8ad92cf4ce 100644 --- a/Resources/Prototypes/_White/Recipes/Lathes/prizecounter.yml +++ b/Resources/Prototypes/_White/Recipes/Lathes/prizecounter.yml @@ -5,3 +5,11 @@ completetime: 0.1 materials: PrizeTicket: 50 + +- type: latheRecipe + id: FaceHuggerToys + result: FaceHuggerToys + applyMaterialDiscount: false + completetime: 0.1 + materials: + PrizeTicket: 100 diff --git a/Resources/Prototypes/_White/xenomorph_cast.yml b/Resources/Prototypes/_White/xenomorph_cast.yml index f360ec45ad..8d224046f8 100644 --- a/Resources/Prototypes/_White/xenomorph_cast.yml +++ b/Resources/Prototypes/_White/xenomorph_cast.yml @@ -21,7 +21,7 @@ - type: xenomorphCaste id: Praetorian name: xenomorph-caste-praetorian - # needCasteDeath: Queen - TODO: Royal larva + needCasteDeath: Queen maxCount: 1 - type: xenomorphCaste diff --git a/Resources/Textures/_White/Interface/Actions/xenomorph.rsi/meta.json b/Resources/Textures/_White/Interface/Actions/xenomorph.rsi/meta.json index a38ce8eb91..6651a6c5d7 100644 --- a/Resources/Textures/_White/Interface/Actions/xenomorph.rsi/meta.json +++ b/Resources/Textures/_White/Interface/Actions/xenomorph.rsi/meta.json @@ -28,11 +28,14 @@ { "name": "tail_attack" }, + { + "name": "plasma_transfer_off" + }, { "name": "plasma_transfer_on" }, { - "name": "plasma_transfer_off" + "name": "promote" }, { "name": "acid" diff --git a/Resources/Textures/_White/Interface/Actions/xenomorph.rsi/promote.png b/Resources/Textures/_White/Interface/Actions/xenomorph.rsi/promote.png new file mode 100644 index 0000000000000000000000000000000000000000..65ea7c960c0a2f1929c9add5c4618c25480eb163 GIT binary patch literal 388 zcmV-~0ek+5P)E)2@o^`>PT?I0sW8$JQU)N91%wou zLvZ89MFz{sq7_3$2o~hS)tOXaqtV}K~Wf~76;=10000EX>4Tx04R}tkvmAkP!xv$wn{}S4rUN>$WWau_(B}D3Pq?8YK2xEOm6yuCJjl7 zi=*ILaPYBMb#QUk)xlK|1Ro%7Zcd6WQsTKup+$@bF8AZV=l{9)Tp(C4GtKH412o+> zQ;E2k$*zjwSM(qN0W%nvnPtpLQWC!Pbx*xicQKyj-}h(rsyT}R0g-r?8KzCVK|H-_ z8=Uuv1y+<*;&b9rlP*a7$aTfzH_io@gFI6()2Vr4fmkfGvC_t@Xlle$#8Fk#DLLk(|D=%yn8rNMI35kRU=q6(y8mBSyPUiiH%N$9?>Ru3sXTLaq`R zITlcX2HEw4|H1FsTKUNdFDViSI$s>;V;BhU0*#vEd>=bb;{*sj16O*>U#SB#pQP7X zTJ#9$+XgPKTbi;5TbbuX%H8p5ycZNYkv6H^9Lm zFjAoGb)R>4wa@L}p62|10K%zq$4QZZ9smFUkx4{BRA_WEyFMI97@pbAQ$0A~eRAR*aO*l^EoM)K#)fFwzhBuToPN9loyHYehtA4$BJi|;Gd zhar#aa_D!V;j_Mr-+$J8B9cz)f9pbXT9>HW*hHHF5^)cI#r8LS7&5@PE_?Wz?L*}N p;5P)gHvDEA0@R0>BuSEVUtcM9A;z1XpYQ+x002ovPDHLkV1l&A4MqR} literal 0 HcmV?d00001 diff --git a/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/far.png b/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/far.png new file mode 100644 index 0000000000000000000000000000000000000000..c08c9ae1b0a01d5a09da9406c5e7028f50857ddd GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4awdAZIEG|2 zzP)&wx7k3z_2TR|u}q-?fiAB)Vy3vtiZm|Z@>;-<&Kjwpcr)lm!TCJ5PtVUbsCZ6N z@!U1r{bggPnfjxJ@}7HUbidcW+OF9Dy68pu!iSspb>FYQR--h@?{)oar{bvTD{kFz znawCv$X|c-n|ZB-(SaR$)jwvvb$-h5z?@}=*`G9NrYr5!fyS1^$7_};9-BRP{s*Ar O7(8A5T-G@yGywn*-c~#S literal 0 HcmV?d00001 diff --git a/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/medium.png b/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/medium.png new file mode 100644 index 0000000000000000000000000000000000000000..35b71749b4d14ac085f8db1793aae3f01f22ba16 GIT binary patch literal 603 zcmV-h0;K(kP)EX>4Tx04R}tkvmAkP!xv$wn{}S4rUN>$WWau_(B}D3Pq?8YK2xEOm6yuCJjl7 zi=*ILaPYBMb#QUk)xlK|1Ro%7Zcd6WQsTKup+$@bF8AZV=l{9)Tp(C4GtKH412o+> zQ;E2k$*zjwSM(qN0W%nvnPtpLQWC!Pbx*xicQKyj-}h(rsyT}R0g-r?8KzCVK|H-_ z8=Uuv1y+<*;&b9rlP*a7$aTfzH_io@gFI6()2Vr4fmkfGvC_t@Xlle$#8Fk#DLLk(|D=%yn8rNMI35kRU=q6(y8mBSyPUiiH%N$9?>Ru3sXTLaq`R zITlcX2HEw4|H1FsTKUNdFDViSI$s>;V;BhU0*#vEd>=bb;{*sj16O*>U#SB#pQP7X zTJ#9$+XgPKTbi;5TbbuX%H8p5ycZNYkv6H^9Lm zFjAoGb)R>4wa@L}p62|10K%zq$4QZZ9smFUkx4{BRA_WEyFMI97@pbAQ$0A~eRAR*aO*l^EoM)K#)fFwzhBuToPN9loyHYehtA4$BJi|;Gd zhar#aa_D!V;j_Mr-+$J8B9cz)f9pbXT9>HW*hHHF5^)cI#r8LS7&5@PE_?Wz?L*}N p;5P)gHvDEA0@R0>BuSEVUtcM9A;z1XpYQ+x002ovPDHLkV1l&A4MqR} literal 0 HcmV?d00001 diff --git a/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/meta.json b/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/meta.json index be19d48a96..339bfbf192 100644 --- a/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/meta.json +++ b/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/meta.json @@ -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" } ] } diff --git a/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/reached.png b/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/reached.png new file mode 100644 index 0000000000000000000000000000000000000000..c5a22c96e95f13492ae4d3c297e04edfd721bd83 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQjEnx?oJHr&dIz4a>6}b978f1 z-(K0s+n^x8dg1a8!E;Xn&ZrnCrY8Az9J^C38h${1{|*iYhK81D7rWD^)Xo2%ark}B z-2J_6*Dd6V-{wy%aC?~>^v~*Txc$_94PUH*hBox*Jy((BVAa1K1LQGyy85}Sb4q9e E0CLwj<^TWy literal 0 HcmV?d00001 diff --git a/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/unknown.png b/Resources/Textures/_White/Interface/Alerts/queen_finder.rsi/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..7244b37f5c785d78eee7767f9a4aa6bef3263b07 GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ql2i3ArY-_ n4>B?Wc})uc*XMaSfSB*u1QZw;-5D2j067evu6{1-oD!ML*%&FlMU}yh$F}YP! z^Yw0#BeMlPBqR>n+W!Clzv-^kU!Y3Hk|4ie28U-i(twUHoQxSdO#zD@>8WLDwW%z)rzfE$rNMOla7duatc)35 zDi`8dt~Cj~n4==0Cf1>(Fm1&QwICMr5Kl*+4#t~eY;2C|Y;J`qjLU>nrz)|fEO-~x j_sE(}O;xqck(EJOK{$f@%MufyQy4s5{an^LB{Ts50Rl{< literal 0 HcmV?d00001 diff --git a/Resources/Textures/_White/Objects/Misc/xenomorph_promotion.rsi/meta.json b/Resources/Textures/_White/Objects/Misc/xenomorph_promotion.rsi/meta.json new file mode 100644 index 0000000000..8da687707c --- /dev/null +++ b/Resources/Textures/_White/Objects/Misc/xenomorph_promotion.rsi/meta.json @@ -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" + } + ] +}