diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.Magazine.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.Magazine.cs index eaab8401bc..0df95e4c02 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.Magazine.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.Magazine.cs @@ -8,6 +8,7 @@ protected override void InitializeMagazine() { base.InitializeMagazine(); SubscribeLocalEvent(OnMagazineAmmoUpdate); + SubscribeLocalEvent(OnMagazineControl); } private void OnMagazineAmmoUpdate(EntityUid uid, MagazineAmmoProviderComponent component, UpdateAmmoCounterEvent args) @@ -26,4 +27,12 @@ private void OnMagazineAmmoUpdate(EntityUid uid, MagazineAmmoProviderComponent c RaiseLocalEvent(ent.Value, args, false); } + + private void OnMagazineControl(EntityUid uid, MagazineAmmoProviderComponent component, AmmoCounterControlEvent args) + { + var ent = GetMagazineEntity(uid); + if (ent == null) + return; + RaiseLocalEvent(ent.Value, args, false); + } } diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.cs b/Content.Server/Administration/Systems/AdminVerbSystem.cs index e678abb0c4..c4754af934 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.cs @@ -67,7 +67,7 @@ public sealed partial class AdminVerbSystem : EntitySystem [Dependency] private readonly StationSystem _stations = default!; [Dependency] private readonly StationSpawningSystem _spawning = default!; - private readonly Dictionary _openSolutionUis = new(); + private readonly Dictionary> _openSolutionUis = new(); public override void Initialize() { @@ -486,10 +486,13 @@ private void AddDebugVerbs(GetVerbsEvent args) #region SolutionsEui private void OnSolutionChanged(Entity entity, ref SolutionContainerChangedEvent args) { - foreach (var eui in _openSolutionUis.Values) + foreach (var list in _openSolutionUis.Values) { - if (eui.Target == entity.Owner) - eui.StateDirty(); + foreach (var eui in list) + { + if (eui.Target == entity.Owner) + eui.StateDirty(); + } } } @@ -498,21 +501,33 @@ public void OpenEditSolutionsEui(ICommonSession session, EntityUid uid) if (session.AttachedEntity == null) return; - if (_openSolutionUis.ContainsKey(session)) - _openSolutionUis[session].Close(); - - var eui = _openSolutionUis[session] = new EditSolutionsEui(uid); + var eui = new EditSolutionsEui(uid); _euiManager.OpenEui(eui, session); eui.StateDirty(); + + if (!_openSolutionUis.ContainsKey(session)) { + _openSolutionUis[session] = new List(); + } + + _openSolutionUis[session].Add(eui); } - public void OnEditSolutionsEuiClosed(ICommonSession session) + public void OnEditSolutionsEuiClosed(ICommonSession session, EditSolutionsEui eui) { - _openSolutionUis.Remove(session, out var eui); + _openSolutionUis[session].Remove(eui); + if (_openSolutionUis[session].Count == 0) + _openSolutionUis.Remove(session); } private void Reset(RoundRestartCleanupEvent ev) { + foreach (var euis in _openSolutionUis.Values) + { + foreach (var eui in euis.ToList()) + { + eui.Close(); + } + } _openSolutionUis.Clear(); } #endregion diff --git a/Content.Server/Administration/UI/EditSolutionsEui.cs b/Content.Server/Administration/UI/EditSolutionsEui.cs index 2a78a27bc0..b4904d969e 100644 --- a/Content.Server/Administration/UI/EditSolutionsEui.cs +++ b/Content.Server/Administration/UI/EditSolutionsEui.cs @@ -36,7 +36,7 @@ public override void Opened() public override void Closed() { base.Closed(); - _entityManager.System().OnEditSolutionsEuiClosed(Player); + _entityManager.System().OnEditSolutionsEuiClosed(Player, this); } public override EuiStateBase GetNewState() diff --git a/Content.Server/Kitchen/EntitySystems/SharpSystem.cs b/Content.Server/Kitchen/EntitySystems/SharpSystem.cs index 814a64a4e3..dfd3bc613c 100644 --- a/Content.Server/Kitchen/EntitySystems/SharpSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/SharpSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Database; using Content.Shared.Interaction; using Content.Shared.Nutrition.Components; +using Content.Server.Nutrition.EntitySystems; using Content.Shared.Popups; using Content.Shared.Storage; using Content.Shared.Verbs; @@ -34,7 +35,7 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnAfterInteract, before: new[] { typeof(UtensilSystem) }); SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent>(OnGetInteractionVerbs); @@ -42,31 +43,34 @@ public override void Initialize() private void OnAfterInteract(EntityUid uid, SharpComponent component, AfterInteractEvent args) { + if (args.Handled) + return; + if (args.Target is null || !args.CanReach) return; - TryStartButcherDoafter(uid, args.Target.Value, args.User); + args.Handled = TryStartButcherDoAfter(uid, args.Target.Value, args.User); } - private void TryStartButcherDoafter(EntityUid knife, EntityUid target, EntityUid user) + private bool TryStartButcherDoAfter(EntityUid knife, EntityUid target, EntityUid user) { if (!TryComp(target, out var butcher)) - return; + return false; if (!TryComp(knife, out var sharp)) - return; + return false; + + if (TryComp(target, out var mobState) && !_mobStateSystem.IsDead(target, mobState)) + return false; if (butcher.Type != ButcheringType.Knife) { _popupSystem.PopupEntity(Loc.GetString("butcherable-different-tool", ("target", target)), knife, user); - return; + return true; } - if (TryComp(target, out var mobState) && !_mobStateSystem.IsDead(target, mobState)) - return; - if (!sharp.Butchering.Add(target)) - return; + return true; var doAfter = new DoAfterArgs(EntityManager, user, sharp.ButcherDelayModifier * butcher.ButcherDelay, new SharpDoAfterEvent(), knife, target: target, used: knife) @@ -77,6 +81,7 @@ private void TryStartButcherDoafter(EntityUid knife, EntityUid target, EntityUid NeedHand = true }; _doAfterSystem.TryStartDoAfter(doAfter); + return true; } private void OnDoAfter(EntityUid uid, SharpComponent component, DoAfterEvent args) @@ -161,7 +166,7 @@ private void OnGetInteractionVerbs(EntityUid uid, ButcherableComponent component Act = () => { if (!disabled) - TryStartButcherDoafter(args.Using!.Value, args.Target, args.User); + TryStartButcherDoAfter(args.Using!.Value, args.Target, args.User); }, Message = message, Disabled = disabled, diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs index 25378bb3ed..61d36f98b9 100644 --- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs +++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerComponent.cs @@ -15,7 +15,7 @@ public sealed partial class BiomassReclaimerComponent : Component /// /// The interval for . /// - [ViewVariables(VVAccess.ReadWrite), DataField("randomMessInterval")] + [ViewVariables(VVAccess.ReadWrite), DataField] public TimeSpan RandomMessInterval = TimeSpan.FromSeconds(5); /// @@ -28,9 +28,10 @@ public sealed partial class BiomassReclaimerComponent : Component /// /// Amount of biomass that the mob being processed will yield. /// This is calculated from the YieldPerUnitMass. + /// Also stores non-integer leftovers. /// [ViewVariables] - public int CurrentExpectedYield = default; + public float CurrentExpectedYield = 0f; /// /// The reagent that will be spilled while processing a mob. @@ -49,6 +50,18 @@ public sealed partial class BiomassReclaimerComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public float YieldPerUnitMass = 0.4f; + /// + /// How many seconds to take to insert an entity per unit of its mass. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float BaseInsertionDelay = 0.1f; + + /// + /// How much to multiply biomass yield from botany produce. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float ProduceYieldMultiplier = 0.25f; + /// /// The time it takes to process a mob, per mass. /// @@ -58,7 +71,7 @@ public sealed partial class BiomassReclaimerComponent : Component /// /// Will this refuse to gib a living mob? /// - [ViewVariables(VVAccess.ReadWrite), DataField("safetyEnabled")] + [ViewVariables(VVAccess.ReadWrite), DataField] public bool SafetyEnabled = true; } } diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs index b126c74a10..d07858aec5 100644 --- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs +++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs @@ -1,5 +1,6 @@ using System.Numerics; using Content.Server.Body.Components; +using Content.Server.Botany.Components; using Content.Server.Fluids.EntitySystems; using Content.Server.Materials; using Content.Server.Power.Components; @@ -17,6 +18,7 @@ using Content.Shared.Jittering; using Content.Shared.Medical; using Content.Shared.Mind; +using Content.Shared.Materials; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Nutrition.Components; @@ -26,6 +28,7 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Medical.BiomassReclaimer @@ -47,6 +50,9 @@ public sealed class BiomassReclaimerSystem : EntitySystem [Dependency] private readonly MaterialStorageSystem _material = default!; [Dependency] private readonly SharedMindSystem _minds = default!; + [ValidatePrototypeId] + public const string BiomassPrototype = "Biomass"; + public override void Update(float frameTime) { base.Update(frameTime); @@ -79,7 +85,9 @@ public override void Update(float frameTime) continue; } - _material.SpawnMultipleFromMaterial(reclaimer.CurrentExpectedYield, "Biomass", Transform(uid).Coordinates); + var actualYield = (int) (reclaimer.CurrentExpectedYield); // can only have integer biomass + reclaimer.CurrentExpectedYield = reclaimer.CurrentExpectedYield - actualYield; // store non-integer leftovers + _material.SpawnMultipleFromMaterial(actualYield, BiomassPrototype, Transform(uid).Coordinates); reclaimer.BloodReagent = null; reclaimer.SpawnedEntities.Clear(); @@ -148,10 +156,14 @@ private void OnAfterInteractUsing(Entity reclaimer, r if (!args.CanReach || args.Target == null) return; - if (!HasComp(args.Used) || !CanGib(reclaimer, args.Used)) + if (!CanGib(reclaimer, args.Used)) + return; + + if (!TryComp(args.Used, out var physics)) return; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, 7f, new ReclaimerDoAfterEvent(), reclaimer, target: args.Target, used: args.Used) + var delay = reclaimer.Comp.BaseInsertionDelay * physics.FixturesMass; + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, delay, new ReclaimerDoAfterEvent(), reclaimer, target: args.Target, used: args.Used) { BreakOnTargetMove = true, BreakOnUserMove = true, @@ -174,11 +186,14 @@ private void OnClimbedOn(Entity reclaimer, ref Climbe private void OnDoAfter(Entity reclaimer, ref ReclaimerDoAfterEvent args) { - if (args.Handled || args.Cancelled || args.Args.Target == null || HasComp(args.Args.Target.Value)) + if (args.Handled || args.Cancelled) + return; + + if (args.Args.Used == null || args.Args.Target == null || !HasComp(args.Args.Target.Value)) return; _adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(args.Args.User):player} used a biomass reclaimer to gib {ToPrettyString(args.Args.Target.Value):target} in {ToPrettyString(reclaimer):reclaimer}"); - StartProcessing(args.Args.Target.Value, reclaimer); + StartProcessing(args.Args.Used.Value, reclaimer); args.Handled = true; } @@ -200,8 +215,13 @@ private void StartProcessing(EntityUid toProcess, Entity(toProcess)) + expectedYield *= component.ProduceYieldMultiplier; + component.CurrentExpectedYield += expectedYield; + component.ProcessingTimer = physics.FixturesMass * component.ProcessingTimePerUnitMass; + QueueDel(toProcess); } @@ -210,7 +230,8 @@ private bool CanGib(Entity reclaimer, EntityUid dragg if (HasComp(reclaimer)) return false; - if (!HasComp(dragged)) + bool isPlant = HasComp(dragged); + if (!isPlant && !HasComp(dragged)) return false; if (!Transform(reclaimer).Anchored) @@ -219,7 +240,7 @@ private bool CanGib(Entity reclaimer, EntityUid dragg if (TryComp(reclaimer, out var power) && !power.Powered) return false; - if (reclaimer.Comp.SafetyEnabled && !_mobState.IsDead(dragged)) + if (!isPlant && reclaimer.Comp.SafetyEnabled && !_mobState.IsDead(dragged)) return false; // Reject souled bodies in easy mode. diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index 925e50b949..6327cf6ae2 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -311,6 +311,9 @@ private void OnDoAfter(Entity entity, ref ConsumeDoAfterEvent ar if (args.Used is null || !_solutionContainer.TryGetSolution(args.Used.Value, args.Solution, out var soln, out var solution)) return; + if (_openable.IsClosed(args.Used.Value, args.Target.Value)) + return; + // TODO this should really be checked every tick. if (_food.IsMouthBlocked(args.Target.Value)) return; diff --git a/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs b/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs index f9feed955f..0edd0711b6 100644 --- a/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Containers.ItemSlots; using Content.Server.Nutrition.Components; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; @@ -25,7 +26,7 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(ItemSlotsSystem) }); } /// @@ -33,6 +34,9 @@ public override void Initialize() /// private void OnAfterInteract(EntityUid uid, UtensilComponent component, AfterInteractEvent ev) { + if (ev.Handled) + return; + if (ev.Target == null || !ev.CanReach) return; diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 1b4f2f1c5b..daadd4b518 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -141,7 +141,10 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) var melee = EnsureComp(target); melee.Animation = zombiecomp.AttackAnimation; melee.WideAnimation = zombiecomp.AttackAnimation; + melee.AltDisarm = false; melee.Range = 1.2f; + melee.Angle = 0.0f; + melee.HitSound = zombiecomp.BiteSound; if (mobState.CurrentState == MobState.Alive) { diff --git a/Content.Shared/Chemistry/Components/InjectorComponent.cs b/Content.Shared/Chemistry/Components/InjectorComponent.cs index e29047b6de..188028c8f8 100644 --- a/Content.Shared/Chemistry/Components/InjectorComponent.cs +++ b/Content.Shared/Chemistry/Components/InjectorComponent.cs @@ -53,8 +53,7 @@ public sealed partial class InjectorComponent : Component /// The maximum amount of solution that can be transferred at once from this solution. /// [DataField("maxTransferAmount")] - [ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 MaximumTransferAmount = FixedPoint2.New(50); + public FixedPoint2 MaximumTransferAmount = FixedPoint2.New(15); /// /// Amount to inject or draw on each usage. If the injector is inject only, it will diff --git a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs index dad8eb4091..7e41cb39bd 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs @@ -39,12 +39,34 @@ private void AddSetTransferVerbs(Entity entity, ref GetVerbsE if (!HasComp(args.User)) return; + var user = args.User; var (_, component) = entity; - // Add specific transfer verbs according to the container's size + var min = component.MinimumTransferAmount; + var max = component.MaximumTransferAmount; + var cur = component.TransferAmount; + var toggleAmount = cur == max ? min : max; + var priority = 0; - var user = args.User; + AlternativeVerb toggleVerb = new() + { + Text = Loc.GetString("comp-solution-transfer-verb-toggle", ("amount", toggleAmount)), + Category = VerbCategory.SetTransferAmount, + Act = () => + { + component.TransferAmount = toggleAmount; + Popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", toggleAmount)), user, user); + Dirty(entity); + }, + + Priority = priority + }; + args.Verbs.Add(toggleVerb); + + priority -= 1; + + // Add specific transfer verbs according to the container's size foreach (var amount in TransferAmounts) { if (amount < component.MinimumTransferAmount || amount > component.MaximumTransferAmount) diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index e5b35f6c0b..85d2e4675f 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -18,7 +18,7 @@ public sealed partial class MeleeWeaponComponent : Component /// /// Does this entity do a disarm on alt attack. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public bool AltDisarm = true; /// diff --git a/Content.Shared/Zombies/ZombieComponent.cs b/Content.Shared/Zombies/ZombieComponent.cs index 023bf751ff..85e1599e48 100644 --- a/Content.Shared/Zombies/ZombieComponent.cs +++ b/Content.Shared/Zombies/ZombieComponent.cs @@ -140,6 +140,12 @@ public sealed partial class ZombieComponent : Component, IAntagStatusIconCompone [DataField("greetSoundNotification")] public SoundSpecifier GreetSoundNotification = new SoundPathSpecifier("/Audio/Ambience/Antag/zombie_start.ogg"); + /// + /// Hit sound on zombie bite. + /// + [DataField] + public SoundSpecifier BiteSound = new SoundPathSpecifier("/Audio/Effects/bite.ogg"); + /// /// The blood reagent of the humanoid to restore in case of cloning /// diff --git a/Resources/Locale/en-US/accessories/human-hair.ftl b/Resources/Locale/en-US/accessories/human-hair.ftl index 9bd8c01fb0..a39e09d5d5 100644 --- a/Resources/Locale/en-US/accessories/human-hair.ftl +++ b/Resources/Locale/en-US/accessories/human-hair.ftl @@ -55,6 +55,7 @@ marking-HumanHairCornrowbun = Cornrow Bun marking-HumanHairCornrowbraid = Cornrow Braid marking-HumanHairCornrowtail = Cornrow Tail marking-HumanHairCrewcut = Crewcut +marking-HumanHairCrewcut2 = Crewcut 2 marking-HumanHairCurls = Curls marking-HumanHairC = Cut Hair marking-HumanHairDandypompadour = Dandy Pompadour diff --git a/Resources/Locale/en-US/chemistry/components/solution-transfer-component.ftl b/Resources/Locale/en-US/chemistry/components/solution-transfer-component.ftl index 14cec95129..74e38f00ab 100644 --- a/Resources/Locale/en-US/chemistry/components/solution-transfer-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/solution-transfer-component.ftl @@ -11,6 +11,7 @@ comp-solution-transfer-is-full = {THE($target)} is full! ## Displayed in change transfer amount verb's name comp-solution-transfer-verb-custom-amount = Custom comp-solution-transfer-verb-amount = {$amount}u +comp-solution-transfer-verb-toggle = Toggle to {$amount}u ## Displayed after you successfully change a solution's amount using the BUI comp-solution-transfer-set-amount = Transfer amount set to {$amount}u. diff --git a/Resources/Locale/en-US/clothing/boots.ftl b/Resources/Locale/en-US/clothing/boots.ftl index 05322d612a..c86bec8455 100644 --- a/Resources/Locale/en-US/clothing/boots.ftl +++ b/Resources/Locale/en-US/clothing/boots.ftl @@ -1 +1 @@ -clothing-military-boots-sidearm = Sidearm +clothing-boots-sidearm = Sidearm diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml index b84033a787..d3ccd335c1 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml @@ -41,6 +41,7 @@ - Geiger - TrayScanner - GasAnalyzer + - HandLabeler - type: ItemMapper mapLayers: drill: @@ -265,10 +266,12 @@ - PillCanister - Radio - DiscreteHealthAnalyzer + - SurgeryTool components: - Hypospray - Injector - Pill + - HandLabeler - type: ItemMapper mapLayers: bottle: @@ -341,6 +344,7 @@ components: - Seed - Smokable + - HandLabeler - type: ItemMapper mapLayers: hatchet: diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml index 8d7dde5928..1119d5cda7 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml @@ -45,7 +45,7 @@ - type: ItemSlots slots: item: - name: clothing-military-boots-sidearm + name: clothing-boots-sidearm whitelist: tags: - Knife diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml b/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml index 4a49c804cd..4b9cbeef42 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml @@ -9,8 +9,26 @@ - type: Clothing sprite: Clothing/Shoes/Specific/chef.rsi +# stuff common to all clown & jester shoes - type: entity - parent: ClothingShoesBaseButcherable + abstract: true + parent: [ClothingShoesBaseButcherable, ClothingSlotBase] + id: ClothingShoesClownBase + components: + - type: ItemSlots + slots: + item: + name: clothing-boots-sidearm + whitelist: + tags: + - Knife + - ToySidearm + blacklist: + components: + - Sharp + +- type: entity + parent: ClothingShoesClownBase id: ClothingShoesClown name: clown shoes description: "The prankster's standard-issue clowning shoes. Damn they're huge!" @@ -49,7 +67,7 @@ acceleration: 5 - type: entity - parent: ClothingShoesBaseButcherable + parent: ClothingShoesClownBase id: ClothingShoesBling name: bling clown shoes description: Made of refined bananium and shined with the pulp of a fresh banana peel. These make a flashy statement. diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml index af4114ce48..c3f3bd13a3 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml @@ -397,6 +397,13 @@ sprites: - sprite: Mobs/Customization/human_hair.rsi state: crewcut +- type: marking + id: HumanHairCrewcut2 + bodyPart: Hair + markingCategory: Hair + sprites: + - sprite: Mobs/Customization/human_hair.rsi + state: crewcut2 - type: marking id: HumanHairCurls bodyPart: Hair diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml index f8565a793e..85de407988 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meat.yml @@ -400,6 +400,9 @@ Quantity: 3 - ReagentId: Fat Quantity: 3 + - type: SliceableFood + count: 3 + slice: FoodMeatCutlet - type: entity name: raw lizard meat diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index ccb67b5ae1..e19cb23112 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -882,6 +882,7 @@ - type: Tag tags: - Sidearm + - ToySidearm - type: Gun selectedMode: SemiAuto availableModes: @@ -914,14 +915,14 @@ suffix: Fake description: Looks almost like the real thing! Ages 8 and up. components: - - type: RevolverAmmoProvider - whitelist: - tags: - - CartridgeCap - - SpeedLoaderCap - - CartridgeMagnum - - SpeedLoaderMagnum - proto: CartridgeMagnumAP + - type: RevolverAmmoProvider + whitelist: + tags: + - CartridgeCap + - SpeedLoaderCap + - CartridgeMagnum + - SpeedLoaderMagnum + proto: CartridgeMagnumAP - type: entity parent: BaseItem diff --git a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml index 4ac05e1e4b..4250669581 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml @@ -7,9 +7,6 @@ sprite: Objects/Misc/utensils.rsi - type: Item # TODO add inhand sprites for all utensils sprite: Objects/Misc/utensils.rsi - - type: Tag - tags: - - Metal - type: SpaceGarbage - type: entity @@ -23,8 +20,14 @@ price: 0 - type: Tag tags: - - Plastic - - Trash + - Plastic + - Trash + - type: MeleeWeapon + wideAnimationRotation: 180 + attackRate: 1.5 + damage: + types: + Blunt: 0 - type: entity parent: UtensilBase @@ -66,6 +69,9 @@ name: spoon description: There is no spoon. components: + - type: Tag + tags: + - Metal - type: Sprite state: spoon - type: Item @@ -99,7 +105,7 @@ speedModifier: 0.1 # you can try - type: entity - parent: UtensilBase + parent: UtensilBasePlastic id: KnifePlastic name: plastic knife description: That's not a knife. This is a knife. @@ -109,3 +115,8 @@ - type: Utensil types: - Knife + - type: Tag + tags: + - Plastic + - Trash + - Knife diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml index 6dc78455ea..aa0cf46187 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml @@ -8,6 +8,9 @@ - type: Sprite - type: StaticPrice price: 20 + - type: Tag + tags: + - SurgeryTool # Cautery diff --git a/Resources/Prototypes/Entities/Objects/Tools/lantern.yml b/Resources/Prototypes/Entities/Objects/Tools/lantern.yml index 71b27ed31e..89101e34ff 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lantern.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lantern.yml @@ -61,6 +61,9 @@ quickEquip: false slots: - Belt + - type: Tag + tags: + - Flashlight - type: entity parent: Lantern diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml index b7b98ba699..e26c4e9540 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/shotgun.yml @@ -130,22 +130,23 @@ maxTransferAmount: 7 - type: SpentAmmoVisuals state: "practice" - -#Not yet craftable due to balance concerns. Should take a good bit of setup to create like the /tg/station recipe. -#Either the improvised shotgun or its recipe (as of July 2023) will also probably have to be nerfed if you decide to make this craftable. + - type: entity id: ShellShotgunImprovised name: improvised shotgun shell - description: A homemade shotgun shell that shoots painful metal shrapnel. The spread is so wide that it couldn't hit the broad side of a barn. + description: A homemade shotgun shell that shoots painful glass shrapnel. The spread is so wide that it couldn't hit the broad side of a barn. parent: BaseShellShotgun components: - type: Sprite layers: - state: improvised map: [ "enum.AmmoVisualLayers.Base" ] + - type: Construction + graph: ImprovisedShotgunShellGraph + node: shell - type: CartridgeAmmo count: 10 - spread: 45 #deadly if you can get up close... otherwise, good luck doing any kind of real damage + spread: 45 proto: PelletShotgunImprovised - type: SpentAmmoVisuals state: "improvised" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml index e62fb9115e..757b8934d4 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml @@ -81,12 +81,13 @@ components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi - state: buckshot + state: shard - type: Projectile damage: types: Piercing: 3 - Slash: 3 #remember, it's metal shrapnel! + Slash: 3 + - type: entity id: PelletShotgunTranquilizer diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/improvised_shotgun_shell.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/improvised_shotgun_shell.yml new file mode 100644 index 0000000000..9f666dd61c --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/improvised_shotgun_shell.yml @@ -0,0 +1,76 @@ +- type: constructionGraph + id: ImprovisedShotgunShellGraph + start: start + graph: + - node: start + edges: + - to: shell + steps: + - material: Steel + amount: 1 + doAfter: 0.5 + - material: Plastic + amount: 1 + doAfter: 0.5 + - tag: GlassShard + name: glass shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard1 + doAfter: 0.5 + - tag: GlassShard + name: glass shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard2 + doAfter: 0.5 + - tag: GlassShard + name: glass shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard1 + doAfter: 0.5 + - tag: GlassShard + name: glass shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard3 + doAfter: 0.5 + - tag: Matchstick + name: match stick + icon: + sprite: Objects/Tools/matches.rsi + state: match_unlit + doAfter: 0.5 + - tag: Matchstick + name: match stick + icon: + sprite: Objects/Tools/matches.rsi + state: match_unlit + doAfter: 0.5 + - tag: Matchstick + name: match stick + icon: + sprite: Objects/Tools/matches.rsi + state: match_unlit + doAfter: 0.5 + - tag: Matchstick + name: match stick + icon: + sprite: Objects/Tools/matches.rsi + state: match_unlit + doAfter: 0.5 + - tag: Matchstick + name: match stick + icon: + sprite: Objects/Tools/matches.rsi + state: match_unlit + doAfter: 0.5 + - tag: Matchstick + name: match stick + icon: + sprite: Objects/Tools/matches.rsi + state: match_unlit + doAfter: 0.5 + - node: shell + entity: ShellShotgunImprovised diff --git a/Resources/Prototypes/Recipes/Crafting/improvised.yml b/Resources/Prototypes/Recipes/Crafting/improvised.yml index 12fbe97e28..23b9eb2c92 100644 --- a/Resources/Prototypes/Recipes/Crafting/improvised.yml +++ b/Resources/Prototypes/Recipes/Crafting/improvised.yml @@ -163,6 +163,19 @@ sprite: Objects/Weapons/Guns/Shotguns/improvised_shotgun.rsi state: icon +- type: construction + name: improvised shotgun shell + id: ShellShotgunImprovised + graph: ImprovisedShotgunShellGraph + startNode: start + targetNode: shell + category: construction-category-weapons + objectType: Item + description: A homemade shotgun shell that shoots painful glass shrapnel. The spread is so wide that it couldn't hit the broad side of a Barn + icon: + sprite: Objects/Weapons/Guns/Ammunition/Casings/shotgun_shell.rsi + state: improvised + - type: construction name: rifle stock id: riflestock diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 2b11b7991b..6d0120aed0 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -1142,6 +1142,9 @@ - type: Tag id: SuitEVA +- type: Tag + id: SurgeryTool + - type: Tag id: SurveillanceCameraMonitorCircuitboard @@ -1181,6 +1184,9 @@ - type: Tag id: Torch +- type: Tag + id: ToySidearm + - type: Tag id: Trash diff --git a/Resources/Textures/Mobs/Customization/human_hair.rsi/crewcut2.png b/Resources/Textures/Mobs/Customization/human_hair.rsi/crewcut2.png new file mode 100644 index 0000000000..2209a9ce83 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_hair.rsi/crewcut2.png differ diff --git a/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json index 5b682389ed..7fce060492 100644 --- a/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json @@ -235,6 +235,10 @@ "name": "crewcut", "directions": 4 }, + { + "name": "crewcut2", + "directions": 4 + }, { "name": "curls", "directions": 4