diff --git a/Content.Client/Ghost/GhostSystem.cs b/Content.Client/Ghost/GhostSystem.cs index a5353921fa1..3ace889f278 100644 --- a/Content.Client/Ghost/GhostSystem.cs +++ b/Content.Client/Ghost/GhostSystem.cs @@ -15,7 +15,6 @@ public sealed class GhostSystem : SharedGhostSystem [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly ILightManager _lightManager = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly ContentEyeSystem _contentEye = default!; public int AvailableGhostRoleCount { get; private set; } @@ -83,7 +82,7 @@ private void OnToggleLighting(EntityUid uid, GhostComponent component, ToggleLig if (args.Handled) return; - _popup.PopupEntity(Loc.GetString("ghost-gui-toggle-lighting-manager-popup"), args.Performer); + Popup.PopupEntity(Loc.GetString("ghost-gui-toggle-lighting-manager-popup"), args.Performer); _lightManager.Enabled = !_lightManager.Enabled; args.Handled = true; } @@ -93,7 +92,7 @@ private void OnToggleFoV(EntityUid uid, GhostComponent component, ToggleFoVActio if (args.Handled) return; - _popup.PopupEntity(Loc.GetString("ghost-gui-toggle-fov-popup"), args.Performer); + Popup.PopupEntity(Loc.GetString("ghost-gui-toggle-fov-popup"), args.Performer); _contentEye.RequestToggleFov(uid); args.Handled = true; } @@ -103,7 +102,7 @@ private void OnToggleGhosts(EntityUid uid, GhostComponent component, ToggleGhost if (args.Handled) return; - _popup.PopupEntity(Loc.GetString("ghost-gui-toggle-ghost-visibility-popup"), args.Performer); + Popup.PopupEntity(Loc.GetString("ghost-gui-toggle-ghost-visibility-popup"), args.Performer); ToggleGhostVisibility(); args.Handled = true; } @@ -113,6 +112,7 @@ private void OnGhostRemove(EntityUid uid, GhostComponent component, ComponentRem _actions.RemoveAction(uid, component.ToggleLightingActionEntity); _actions.RemoveAction(uid, component.ToggleFoVActionEntity); _actions.RemoveAction(uid, component.ToggleGhostsActionEntity); + _actions.RemoveAction(uid, component.ToggleGhostHearingActionEntity); if (uid != _playerManager.LocalPlayer?.ControlledEntity) return; diff --git a/Content.Client/MouseRotator/MouseRotatorSystem.cs b/Content.Client/MouseRotator/MouseRotatorSystem.cs index 4b7f9373479..9615862dc5e 100644 --- a/Content.Client/MouseRotator/MouseRotatorSystem.cs +++ b/Content.Client/MouseRotator/MouseRotatorSystem.cs @@ -41,6 +41,22 @@ public override void Update(float frameTime) var curRot = _transform.GetWorldRotation(xform); + // 4-dir handling is separate -- + // only raise event if the cardinal direction has changed + if (rotator.Simple4DirMode) + { + var angleDir = angle.GetCardinalDir(); + if (angleDir == curRot.GetCardinalDir()) + return; + + RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent() + { + Direction = angleDir, + }); + + return; + } + // Don't raise event if mouse ~hasn't moved (or if too close to goal rotation already) var diff = Angle.ShortestDistance(angle, curRot); if (Math.Abs(diff.Theta) < rotator.AngleTolerance.Theta) diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 5770af23aa5..36fe75fad7f 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -152,6 +152,10 @@ public override void Update(float frameTime) target = screen.GetClickedEntity(mousePos); } + // Don't light-attack if interaction will be handling this instead + if (Interaction.CombatModeCanHandInteract(entity, target)) + return; + RaisePredictiveEvent(new LightAttackEvent(GetNetEntity(target), GetNetEntity(weaponUid), GetNetCoordinates(coordinates))); } } diff --git a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs index 00e6c010648..7b9ea7146ef 100644 --- a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs +++ b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs @@ -68,17 +68,28 @@ private void UpdateController(EntityUid uid, TimeSpan curTime, AmeControllerComp if (TryComp(controller.JarSlot.ContainedEntity, out var fuelJar)) { - var availableInject = Math.Min(controller.InjectionAmount, fuelJar.FuelAmount); - var powerOutput = group.InjectFuel(availableInject, out var overloading); - if (TryComp(uid, out var powerOutlet)) - powerOutlet.MaxSupply = powerOutput; - fuelJar.FuelAmount -= availableInject; - _audioSystem.PlayPvs(controller.InjectSound, uid, AudioParams.Default.WithVolume(overloading ? 10f : 0f)); - UpdateUi(uid, controller); + // if the jar is empty shut down the AME + if (fuelJar.FuelAmount <= 0) + { + SetInjecting(uid, false, null, controller); + } + else + { + var availableInject = Math.Min(controller.InjectionAmount, fuelJar.FuelAmount); + var powerOutput = group.InjectFuel(availableInject, out var overloading); + if (TryComp(uid, out var powerOutlet)) + powerOutlet.MaxSupply = powerOutput; + fuelJar.FuelAmount -= availableInject; + // only play audio if we actually had an injection + if (availableInject > 0) + _audioSystem.PlayPvs(controller.InjectSound, uid, AudioParams.Default.WithVolume(overloading ? 10f : 0f)); + UpdateUi(uid, controller); + } } controller.Stability = group.GetTotalStability(); + group.UpdateCoreVisuals(); UpdateDisplay(uid, controller.Stability, controller); if (controller.Stability <= 0) @@ -155,7 +166,7 @@ public void SetInjecting(EntityUid uid, bool value, EntityUid? user = null, AmeC return; controller.Injecting = value; - _appearanceSystem.SetData(uid, AmeControllerVisuals.DisplayState, value ? AmeControllerState.On : AmeControllerState.Off); + UpdateDisplay(uid, controller.Stability, controller); if (!value && TryComp(uid, out var powerOut)) powerOut.MaxSupply = 0; @@ -215,15 +226,20 @@ private void UpdateDisplay(EntityUid uid, int stability, AmeControllerComponent? if (!Resolve(uid, ref controller, ref appearance)) return; + var ameControllerState = stability switch + { + < 10 => AmeControllerState.Fuck, + < 50 => AmeControllerState.Critical, + _ => AmeControllerState.On, + }; + + if (!controller.Injecting) + ameControllerState = AmeControllerState.Off; + _appearanceSystem.SetData( uid, AmeControllerVisuals.DisplayState, - stability switch - { - < 10 => AmeControllerState.Fuck, - < 50 => AmeControllerState.Critical, - _ => AmeControllerState.On, - }, + ameControllerState, appearance ); } diff --git a/Content.Server/Atmos/Components/GasTankComponent.cs b/Content.Server/Atmos/Components/GasTankComponent.cs index 8b411e38db5..a649e57b45d 100644 --- a/Content.Server/Atmos/Components/GasTankComponent.cs +++ b/Content.Server/Atmos/Components/GasTankComponent.cs @@ -8,7 +8,7 @@ namespace Content.Server.Atmos.Components [RegisterComponent] public sealed partial class GasTankComponent : Component, IGasMixtureHolder { - public const float MaxExplosionRange = 80f; + public const float MaxExplosionRange = 26f; private const float DefaultLowPressure = 0f; private const float DefaultOutputPressure = Atmospherics.OneAtmosphere; diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index e6943b3c2ad..e1d9805e6a0 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -750,7 +750,7 @@ private Dictionary GetRecipients(EntityUid // TODO proper speech occlusion var recipients = new Dictionary(); - var ghosts = GetEntityQuery(); + var ghostHearing = GetEntityQuery(); var xforms = GetEntityQuery(); var transformSource = xforms.GetComponent(source); @@ -767,9 +767,9 @@ private Dictionary GetRecipients(EntityUid if (transformEntity.MapID != sourceMapId) continue; - var observer = ghosts.HasComponent(playerEntity); + var observer = ghostHearing.HasComponent(playerEntity); - // even if they are an observer, in some situations we still need the range + // even if they are a ghost hearer, in some situations we still need the range if (sourceCoords.TryDistance(EntityManager, transformEntity.Coordinates, out var distance) && distance < voiceGetRange) { recipients.Add(player, new ICChatRecipientData(distance, observer)); diff --git a/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs b/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs index 529aa8adf17..1208e74367b 100644 --- a/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs +++ b/Content.Server/Chemistry/ReagentEffects/SatiateThirst.cs @@ -1,6 +1,6 @@ -using Content.Server.Nutrition.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Nutrition.Components; +using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.ReagentEffects @@ -21,8 +21,9 @@ public sealed partial class SatiateThirst : ReagentEffect /// Satiate thirst if a ThirstComponent can be found public override void Effect(ReagentEffectArgs args) { - if (args.EntityManager.TryGetComponent(args.SolutionEntity, out ThirstComponent? thirst)) - EntitySystem.Get().UpdateThirst(thirst, HydrationFactor); + var uid = args.SolutionEntity; + if (args.EntityManager.TryGetComponent(uid, out ThirstComponent? thirst)) + EntitySystem.Get().ModifyThirst(uid, thirst, HydrationFactor); } protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) diff --git a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs index 760b684e1ad..8ddfd9c14bb 100644 --- a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs @@ -1,4 +1,5 @@ using Content.Server.NPC.Components; +using Content.Server.RoundEnd; using Content.Server.StationEvents.Events; using Content.Shared.Dataset; using Content.Shared.Roles; @@ -31,10 +32,34 @@ public sealed partial class NukeopsRuleComponent : Component public int MaxOperatives = 5; /// - /// Whether or not all of the nuclear operatives dying will end the round. Used by LoneOpsSpawn event. + /// What will happen if all of the nuclear operatives will die. Used by LoneOpsSpawn event. /// - [DataField("endsRound")] - public bool EndsRound = true; + [DataField("roundEndBehavior")] + public RoundEndBehavior RoundEndBehavior = RoundEndBehavior.ShuttleCall; + + /// + /// Text for shuttle call if RoundEndBehavior is ShuttleCall. + /// + [DataField("roundEndTextSender")] + public string RoundEndTextSender = "comms-console-announcement-title-centcom"; + + /// + /// Text for shuttle call if RoundEndBehavior is ShuttleCall. + /// + [DataField("roundEndTextShuttleCall")] + public string RoundEndTextShuttleCall = "nuke-ops-no-more-threat-announcement-shuttle-call"; + + /// + /// Text for announcement if RoundEndBehavior is ShuttleCall. Used if shuttle is already called + /// + [DataField("roundEndTextAnnouncement")] + public string RoundEndTextAnnouncement = "nuke-ops-no-more-threat-announcement"; + + /// + /// Time to emergency shuttle to arrive if RoundEndBehavior is ShuttleCall. + /// + [DataField("evacShuttleTime")] + public TimeSpan EvacShuttleTime = TimeSpan.FromMinutes(10); /// /// Whether or not to spawn the nuclear operative outpost. Used by LoneOpsSpawn event. diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 4533ed88960..1af413e9656 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -489,14 +489,14 @@ private void OnRoundEndText(RoundEndTextAppendEvent ev) } } - private void SetWinType(EntityUid uid, WinType type, NukeopsRuleComponent? component = null) + private void SetWinType(EntityUid uid, WinType type, NukeopsRuleComponent? component = null, bool endRound = true) { if (!Resolve(uid, ref component)) return; component.WinType = type; - if (type == WinType.CrewMajor || type == WinType.OpsMajor) + if (endRound && (type == WinType.CrewMajor || type == WinType.OpsMajor)) _roundEndSystem.EndRound(); } @@ -508,7 +508,7 @@ private void CheckRoundShouldEnd() if (!GameTicker.IsGameRuleAdded(uid, gameRule)) continue; - if (!nukeops.EndsRound || nukeops.WinType == WinType.CrewMajor || nukeops.WinType == WinType.OpsMajor) + if (nukeops.RoundEndBehavior == RoundEndBehavior.Nothing || nukeops.WinType == WinType.CrewMajor || nukeops.WinType == WinType.OpsMajor) continue; // If there are any nuclear bombs that are active, immediately return. We're not over yet. @@ -561,7 +561,12 @@ private void CheckRoundShouldEnd() ? WinCondition.NukiesAbandoned : WinCondition.AllNukiesDead); - SetWinType(uid, WinType.CrewMajor, nukeops); + SetWinType(uid, WinType.CrewMajor, nukeops, false); + _roundEndSystem.DoRoundEndBehavior( + nukeops.RoundEndBehavior, nukeops.EvacShuttleTime, nukeops.RoundEndTextSender, nukeops.RoundEndTextShuttleCall, nukeops.RoundEndTextAnnouncement); + + // prevent it called multiple times + nukeops.RoundEndBehavior = RoundEndBehavior.Nothing; } } @@ -765,7 +770,7 @@ private void OnMindAdded(EntityUid uid, NukeOperativeComponent component, MindAd foreach (var (nukeops, gameRule) in EntityQuery()) { - if (nukeops.OperativeMindPendingData.TryGetValue(uid, out var role) || !nukeops.SpawnOutpost || !nukeops.EndsRound) + if (nukeops.OperativeMindPendingData.TryGetValue(uid, out var role) || !nukeops.SpawnOutpost || nukeops.RoundEndBehavior == RoundEndBehavior.Nothing) { role ??= nukeops.OperativeRoleProto; _roles.MindAddRole(mindId, new NukeopsRoleComponent { PrototypeId = role }); diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index c8a410b91fc..78818039017 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -16,6 +16,7 @@ using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; +using Content.Shared.Popups; using Content.Shared.Storage.Components; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -64,11 +65,35 @@ public override void Initialize() SubscribeNetworkEvent(OnGhostWarpToTargetRequest); SubscribeLocalEvent(OnActionPerform); + SubscribeLocalEvent(OnGhostHearingAction); SubscribeLocalEvent(OnEntityStorageInsertAttempt); SubscribeLocalEvent(_ => MakeVisible(true)); } + private void OnGhostHearingAction(EntityUid uid, GhostComponent component, ToggleGhostHearingActionEvent args) + { + args.Handled = true; + + if (HasComp(uid)) + { + RemComp(uid); + _actions.SetToggled(component.ToggleGhostHearingActionEntity, true); + } + else + { + AddComp(uid); + _actions.SetToggled(component.ToggleGhostHearingActionEntity, false); + } + + var str = HasComp(uid) + ? Loc.GetString("ghost-gui-toggle-hearing-popup-on") + : Loc.GetString("ghost-gui-toggle-hearing-popup-off"); + + Popup.PopupEntity(str, uid, uid); + Dirty(uid, component); + } + private void OnActionPerform(EntityUid uid, GhostComponent component, BooActionEvent args) { if (args.Handled) @@ -164,6 +189,7 @@ private void OnMapInit(EntityUid uid, GhostComponent component, MapInitEvent arg _actions.SetCooldown(component.BooActionEntity.Value, start, end); } + _actions.AddAction(uid, ref component.ToggleGhostHearingActionEntity, component.ToggleGhostHearingAction); _actions.AddAction(uid, ref component.ToggleLightingActionEntity, component.ToggleLightingAction); _actions.AddAction(uid, ref component.ToggleFoVActionEntity, component.ToggleFoVAction); _actions.AddAction(uid, ref component.ToggleGhostsActionEntity, component.ToggleGhostsAction); diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index a764cd2b19c..37ad658825b 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -44,7 +44,7 @@ public void Vomit(EntityUid uid, float thirstAdded = -40f, float hungerAdded = - _hunger.ModifyHunger(uid, hungerAdded, hunger); if (TryComp(uid, out var thirst)) - _thirst.UpdateThirst(thirst, thirstAdded); + _thirst.ModifyThirst(uid, thirst, thirstAdded); // It fully empties the stomach, this amount from the chem stream is relatively small var solutionSize = (MathF.Abs(thirstAdded) + MathF.Abs(hungerAdded)) / 6; diff --git a/Content.Server/Nutrition/Components/FoodComponent.cs b/Content.Server/Nutrition/Components/FoodComponent.cs index 9e37af2a108..0f696d36946 100644 --- a/Content.Server/Nutrition/Components/FoodComponent.cs +++ b/Content.Server/Nutrition/Components/FoodComponent.cs @@ -17,7 +17,7 @@ public sealed partial class FoodComponent : Component [DataField] public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/eatfood.ogg"); - [DataField] + [DataField("trash")] public EntProtoId? TrashPrototype; [DataField] diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index f1a4a6d5f43..af037187408 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; +using Content.Server.Inventory; using Content.Server.Nutrition.Components; using Content.Server.Popups; using Content.Server.Stack; @@ -61,7 +62,7 @@ public override void Initialize() // TODO add InteractNoHandEvent for entities like mice. // run after openable for wrapped/peelable foods - SubscribeLocalEvent(OnUseFoodInHand, after: new[] { typeof(OpenableSystem) }); + SubscribeLocalEvent(OnUseFoodInHand, after: new[] { typeof(OpenableSystem), typeof(ServerInventorySystem) }); SubscribeLocalEvent(OnFeedFood); SubscribeLocalEvent>(AddEatVerb); SubscribeLocalEvent(OnDoAfter); diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index c36ff2d76b6..1bb127106cf 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -90,7 +90,12 @@ public bool CanCallOrRecall() return _cooldownTokenSource == null; } - public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, bool autoCall = false) + public bool IsRoundEndRequested() + { + return _countdownTokenSource != null; + } + + public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") { var duration = DefaultCountdownDuration; @@ -105,10 +110,10 @@ public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = tr } } - RequestRoundEnd(duration, requester, checkCooldown, autoCall); + RequestRoundEnd(duration, requester, checkCooldown, text, name); } - public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, bool autoCall = false) + public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") { if (_gameTicker.RunLevel != GameRunLevel.InRound) return; @@ -141,29 +146,16 @@ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, units = "eta-units-minutes"; } - if (autoCall) - { - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-auto-called-announcement", - ("time", time), - ("units", Loc.GetString(units))), - Loc.GetString("Station"), - false, - null, - Color.Gold); - SoundSystem.Play("/Audio/Corvax/Announcements/crew_s_called.ogg", Filter.Broadcast(), AudioParams.Default.AddVolume(-4)); // Corvax-Announcements - } - else - { - _chatSystem.DispatchGlobalAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement", - ("time", time), - ("units", Loc.GetString(units))), - Loc.GetString("Station"), - false, - null, - Color.Gold); - } + _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(text, + ("time", time), + ("units", Loc.GetString(units))), + name, + false, + null, + Color.Gold); - if (!autoCall) SoundSystem.Play("/Audio/Announcements/shuttlecalled.ogg", Filter.Broadcast(), AudioParams.Default.AddVolume(-4)); // Corvax-Announcements: Custom sound for auto-called + if (!AutoCalledBefore) SoundSystem.Play("/Audio/Announcements/shuttlecalled.ogg", Filter.Broadcast(), AudioParams.Default.AddVolume(-4)); // Corvax-Announcements: Custom sound for auto-called + else SoundSystem.Play("/Audio/Corvax/Announcements/crew_s_called.ogg", Filter.Broadcast(), AudioParams.Default.AddVolume(-4)); // Corvax-Announcements LastCountdownStart = _gameTiming.CurTime; ExpectedCountdownEnd = _gameTiming.CurTime + countdownTime; @@ -233,6 +225,30 @@ public void EndRound(TimeSpan? countdownTime = null) Timer.Spawn(countdownTime.Value, AfterEndRoundRestart, _countdownTokenSource.Token); } + public void DoRoundEndBehavior(RoundEndBehavior behavior, TimeSpan time, string sender, string textCall, string textAnnounce) + { + switch (behavior) + { + case RoundEndBehavior.InstantEnd: + EndRound(); + break; + case RoundEndBehavior.ShuttleCall: + // Check is shuttle called or not. We should only dispatch announcement if it's already called + if (IsRoundEndRequested()) + { + _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(textAnnounce), + Loc.GetString(sender), + colorOverride: Color.Gold); + } + else + { + RequestRoundEnd(time, null, false, textCall, + Loc.GetString(sender)); + } + break; + } + } + private void AfterEndRoundRestart() { if (_gameTicker.RunLevel != GameRunLevel.PostRound) return; @@ -261,8 +277,8 @@ public override void Update(float frameTime) { if (!_shuttle.EmergencyShuttleArrived && ExpectedCountdownEnd is null) { - RequestRoundEnd(null, false, true); - AutoCalledBefore = true; + AutoCalledBefore = true; // Corvax-Announcements: Move before call RequestRoundEnd to play correct announcement sound type + RequestRoundEnd(null, false, "round-end-system-shuttle-auto-called-announcement"); } // Always reset auto-call in case of a recall. @@ -275,4 +291,22 @@ public sealed class RoundEndSystemChangedEvent : EntityEventArgs { public static RoundEndSystemChangedEvent Default { get; } = new(); } + + public enum RoundEndBehavior : byte +{ + /// + /// Instantly end round + /// + InstantEnd, + + /// + /// Call shuttle with custom announcement + /// + ShuttleCall, + + /// + /// Do nothing + /// + Nothing +} } diff --git a/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs b/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs index bc77a9ce471..36d30f50eee 100644 --- a/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs +++ b/Content.Server/StationEvents/BasicStationEventSchedulerSystem.cs @@ -1,8 +1,13 @@ +using System.Linq; +using Content.Server.Administration; using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Shared.Administration; using JetBrains.Annotations; using Robust.Shared.Random; +using Robust.Shared.Toolshed; +using Robust.Shared.Utility; namespace Content.Server.StationEvents { @@ -56,4 +61,54 @@ private void ResetTimer(BasicStationEventSchedulerComponent component) component.TimeUntilNextEvent = _random.Next(300, 1500); } } + + [ToolshedCommand, AdminCommand(AdminFlags.Debug)] + public sealed class StationEventCommand : ToolshedCommand + { + private EventManagerSystem? _stationEvent; + + [CommandImplementation("lsprob")] + public IEnumerable<(string, float)> LsProb() + { + _stationEvent ??= GetSys(); + var events = _stationEvent.AllEvents(); + + var totalWeight = events.Sum(x => x.Value.Weight); + + foreach (var (proto, comp) in events) + { + yield return (proto.ID, comp.Weight / totalWeight); + } + } + + [CommandImplementation("lsprobtime")] + public IEnumerable<(string, float)> LsProbTime([CommandArgument] float time) + { + _stationEvent ??= GetSys(); + var events = _stationEvent.AllEvents().Where(pair => pair.Value.EarliestStart <= time).ToList(); + + var totalWeight = events.Sum(x => x.Value.Weight); + + foreach (var (proto, comp) in events) + { + yield return (proto.ID, comp.Weight / totalWeight); + } + } + + [CommandImplementation("prob")] + public float Prob([CommandArgument] string eventId) + { + _stationEvent ??= GetSys(); + var events = _stationEvent.AllEvents(); + + var totalWeight = events.Sum(x => x.Value.Weight); + var weight = 0f; + if (events.TryFirstOrNull(p => p.Key.ID == eventId, out var pair)) + { + weight = pair.Value.Value.Weight; + } + + return weight / totalWeight; + } + } } diff --git a/Content.Server/StationEvents/Events/LoneOpsSpawnRule.cs b/Content.Server/StationEvents/Events/LoneOpsSpawnRule.cs index 8e1a2f3b3b0..ce5f826d0cd 100644 --- a/Content.Server/StationEvents/Events/LoneOpsSpawnRule.cs +++ b/Content.Server/StationEvents/Events/LoneOpsSpawnRule.cs @@ -5,6 +5,7 @@ using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; +using Content.Server.RoundEnd; namespace Content.Server.StationEvents.Events; @@ -37,7 +38,7 @@ protected override void Started(EntityUid uid, LoneOpsSpawnRuleComponent compone component.AdditionalRule = nukeopsEntity; var nukeopsComp = EntityManager.GetComponent(nukeopsEntity); nukeopsComp.SpawnOutpost = false; - nukeopsComp.EndsRound = false; + nukeopsComp.RoundEndBehavior = RoundEndBehavior.Nothing; _gameTicker.StartGameRule(nukeopsEntity); } diff --git a/Content.Shared/CombatMode/CombatModeComponent.cs b/Content.Shared/CombatMode/CombatModeComponent.cs index ace8105b999..6696f8af806 100644 --- a/Content.Shared/CombatMode/CombatModeComponent.cs +++ b/Content.Shared/CombatMode/CombatModeComponent.cs @@ -1,3 +1,5 @@ +using Content.Shared.MouseRotator; +using Content.Shared.Movement.Components; using Content.Shared.Targeting; using Robust.Shared.Audio; using Robust.Shared.GameStates; @@ -41,6 +43,13 @@ public sealed partial class CombatModeComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("isInCombatMode"), AutoNetworkedField] public bool IsInCombatMode; + /// + /// Will add and + /// to entities with this flag enabled that enter combat mode, and vice versa for removal. + /// + [DataField, AutoNetworkedField] + public bool ToggleMouseRotator = true; + [ViewVariables(VVAccess.ReadWrite), DataField("activeZone"), AutoNetworkedField] public TargetingZone ActiveZone; } diff --git a/Content.Shared/CombatMode/SharedCombatModeSystem.cs b/Content.Shared/CombatMode/SharedCombatModeSystem.cs index 263f3e8311a..66b31d01ffb 100644 --- a/Content.Shared/CombatMode/SharedCombatModeSystem.cs +++ b/Content.Shared/CombatMode/SharedCombatModeSystem.cs @@ -1,4 +1,6 @@ using Content.Shared.Actions; +using Content.Shared.MouseRotator; +using Content.Shared.Movement.Components; using Content.Shared.Popups; using Content.Shared.Targeting; using Robust.Shared.Network; @@ -30,6 +32,8 @@ private void OnMapInit(EntityUid uid, CombatModeComponent component, MapInitEven private void OnShutdown(EntityUid uid, CombatModeComponent component, ComponentShutdown args) { _actionsSystem.RemoveAction(uid, component.CombatToggleActionEntity); + + SetMouseRotatorComponents(uid, false); } private void OnActionPerform(EntityUid uid, CombatModeComponent component, ToggleCombatActionEvent args) @@ -76,6 +80,12 @@ public virtual void SetInCombatMode(EntityUid entity, bool value, CombatModeComp if (component.CombatToggleActionEntity != null) _actionsSystem.SetToggled(component.CombatToggleActionEntity, component.IsInCombatMode); + + // Change mouse rotator comps if flag is set + if (!component.ToggleMouseRotator) + return; + + SetMouseRotatorComponents(entity, value); } public virtual void SetActiveZone(EntityUid entity, TargetingZone zone, @@ -86,6 +96,20 @@ public virtual void SetActiveZone(EntityUid entity, TargetingZone zone, component.ActiveZone = zone; } + + private void SetMouseRotatorComponents(EntityUid uid, bool value) + { + if (value) + { + EnsureComp(uid); + EnsureComp(uid); + } + else + { + RemComp(uid); + RemComp(uid); + } + } } public sealed partial class ToggleCombatActionEvent : InstantActionEvent { } diff --git a/Content.Shared/Ghost/GhostComponent.cs b/Content.Shared/Ghost/GhostComponent.cs index e58cb3a16f3..9090af4dbaa 100644 --- a/Content.Shared/Ghost/GhostComponent.cs +++ b/Content.Shared/Ghost/GhostComponent.cs @@ -1,8 +1,6 @@ using Content.Shared.Actions; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Ghost; @@ -14,32 +12,30 @@ public sealed partial class GhostComponent : Component [ViewVariables] public bool IsAttached; - [DataField("toggleLightingAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ToggleLightingAction = "ActionToggleLighting"; + // Actions + [DataField] + public EntProtoId ToggleLightingAction = "ActionToggleLighting"; [DataField, AutoNetworkedField] public EntityUid? ToggleLightingActionEntity; - [DataField("toggleFovAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ToggleFoVAction = "ActionToggleFov"; + [DataField] + public EntProtoId ToggleFoVAction = "ActionToggleFov"; [DataField, AutoNetworkedField] public EntityUid? ToggleFoVActionEntity; - [DataField("toggleGhostsAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ToggleGhostsAction = "ActionToggleGhosts"; + [DataField] + public EntProtoId ToggleGhostsAction = "ActionToggleGhosts"; [DataField, AutoNetworkedField] public EntityUid? ToggleGhostsActionEntity; - [ViewVariables(VVAccess.ReadWrite), DataField("timeOfDeath", customTypeSerializer:typeof(TimeOffsetSerializer))] - public TimeSpan TimeOfDeath = TimeSpan.Zero; - - [DataField("booRadius")] - public float BooRadius = 3; + [DataField] + public EntProtoId ToggleGhostHearingAction = "ActionToggleGhostHearing"; - [DataField("booMaxTargets")] - public int BooMaxTargets = 3; + [DataField] + public EntityUid? ToggleGhostHearingActionEntity; [DataField] public EntProtoId BooAction = "ActionGhostBoo"; @@ -47,6 +43,17 @@ public sealed partial class GhostComponent : Component [DataField, AutoNetworkedField] public EntityUid? BooActionEntity; + // End actions + + [ViewVariables(VVAccess.ReadWrite), DataField] + public TimeSpan TimeOfDeath = TimeSpan.Zero; + + [DataField("booRadius")] + public float BooRadius = 3; + + [DataField("booMaxTargets")] + public int BooMaxTargets = 3; + // TODO: instead of this funny stuff just give it access and update in system dirtying when needed [ViewVariables(VVAccess.ReadWrite)] public bool CanGhostInteract @@ -90,10 +97,12 @@ public bool CanReturnToBody private bool _canReturnToBody; } -public sealed partial class BooActionEvent : InstantActionEvent { } +public sealed partial class ToggleFoVActionEvent : InstantActionEvent { } -public sealed partial class ToggleFoVActionEvent : InstantActionEvent { }; +public sealed partial class ToggleGhostsActionEvent : InstantActionEvent { } -public sealed partial class ToggleGhostsActionEvent : InstantActionEvent { }; +public sealed partial class ToggleLightingActionEvent : InstantActionEvent { } -public sealed partial class ToggleLightingActionEvent : InstantActionEvent { }; +public sealed partial class ToggleGhostHearingActionEvent : InstantActionEvent { } + +public sealed partial class BooActionEvent : InstantActionEvent { } diff --git a/Content.Shared/Ghost/GhostHearingComponent.cs b/Content.Shared/Ghost/GhostHearingComponent.cs new file mode 100644 index 00000000000..c50a1f6c74a --- /dev/null +++ b/Content.Shared/Ghost/GhostHearingComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Shared.Ghost; + +/// +/// This is used for marking entities which should receive all local chat message, even when out of range +/// +[RegisterComponent] +public sealed partial class GhostHearingComponent : Component +{ +} diff --git a/Content.Shared/Ghost/SharedGhostSystem.cs b/Content.Shared/Ghost/SharedGhostSystem.cs index 1bd0bbacb9e..c1c2c3c71e8 100644 --- a/Content.Shared/Ghost/SharedGhostSystem.cs +++ b/Content.Shared/Ghost/SharedGhostSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Hands; using Content.Shared.Interaction.Events; using Content.Shared.Item; +using Content.Shared.Popups; using Robust.Shared.Serialization; namespace Content.Shared.Ghost @@ -12,6 +13,8 @@ namespace Content.Shared.Ghost /// public abstract class SharedGhostSystem : EntitySystem { + [Dependency] protected readonly SharedPopupSystem Popup = default!; + public override void Initialize() { base.Initialize(); diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 7d55035d5c1..00c357814d7 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -262,6 +262,35 @@ private bool ShouldCheckAccess(EntityUid user) return !_tagSystem.HasTag(user, "BypassInteractionRangeChecks"); } + /// + /// Returns true if the specified entity should hand interact with the target instead of attacking + /// + /// The user interacting in combat mode + /// The target of the interaction + /// + public bool CombatModeCanHandInteract(EntityUid user, EntityUid? target) + { + // Always allow attack in these cases + if (target == null || !TryComp(user, out var hands) || hands.ActiveHand?.HeldEntity is not null) + return false; + + // Only eat input if: + // - Target isn't an item + // - Target doesn't cancel should-interact event + // This is intended to allow items to be picked up in combat mode, + // but to also allow items to force attacks anyway (like mobs which are items, e.g. mice) + if (!HasComp(target)) + return false; + + var combatEv = new CombatModeShouldHandInteractEvent(); + RaiseLocalEvent(target.Value, ref combatEv); + + if (combatEv.Cancelled) + return false; + + return true; + } + /// /// Resolves user interactions with objects. /// @@ -285,7 +314,8 @@ public void UserInteraction( // TODO this needs to be handled better. This probably bypasses many complex can-interact checks in weird roundabout ways. if (_actionBlockerSystem.CanInteract(user, target)) { - UserInteraction(relay.RelayEntity.Value, coordinates, target, altInteract, checkCanInteract, checkAccess, checkCanUse); + UserInteraction(relay.RelayEntity.Value, coordinates, target, altInteract, checkCanInteract, + checkAccess, checkCanUse); return; } } @@ -293,10 +323,10 @@ public void UserInteraction( if (target != null && Deleted(target.Value)) return; - if (!altInteract && TryComp(user, out CombatModeComponent? combatMode) && combatMode.IsInCombatMode) + if (!altInteract && TryComp(user, out var combatMode) && combatMode.IsInCombatMode) { - // Eat the input - return; + if (!CombatModeCanHandInteract(user, target)) + return; } if (!ValidateInteractAndFace(user, coordinates)) @@ -326,7 +356,7 @@ public void UserInteraction( : !checkAccess || InRangeUnobstructed(user, target.Value); // permits interactions with wall mounted entities // Does the user have hands? - if (!TryComp(user, out HandsComponent? hands) || hands.ActiveHand == null) + if (!TryComp(user, out var hands) || hands.ActiveHand == null) { var ev = new InteractNoHandEvent(user, target, coordinates); RaiseLocalEvent(user, ev); @@ -341,6 +371,8 @@ public void UserInteraction( } // empty-hand interactions + // combat mode hand interactions will always be true here -- since + // they check this earlier before returning in if (hands.ActiveHandEntity is not { } held) { if (inRangeUnobstructed && target != null) @@ -1164,4 +1196,12 @@ public InteractInventorySlotEvent(NetEntity itemUid, bool altInteract = false) AltInteract = altInteract; } } + + /// + /// Raised directed by-ref on an item to determine if hand interactions should go through. + /// Defaults to allowing hand interactions to go through. Cancel to force the item to be attacked instead. + /// + /// Whether the hand interaction should be cancelled. + [ByRefEvent] + public record struct CombatModeShouldHandInteractEvent(bool Cancelled = false); } diff --git a/Content.Shared/Item/SharedItemSystem.cs b/Content.Shared/Item/SharedItemSystem.cs index bda92c500a1..5f890af99fd 100644 --- a/Content.Shared/Item/SharedItemSystem.cs +++ b/Content.Shared/Item/SharedItemSystem.cs @@ -75,7 +75,7 @@ public void CopyVisuals(EntityUid uid, ItemComponent otherItem, ItemComponent? i private void OnHandInteract(EntityUid uid, ItemComponent component, InteractHandEvent args) { - if (args.Handled || _combatMode.IsInCombatMode(args.User)) + if (args.Handled) return; args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false); diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs index f4537deede4..340a1627d6d 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs @@ -1,6 +1,7 @@ using Content.Shared.Bed.Sleep; using Content.Shared.Emoting; using Content.Shared.Hands; +using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Inventory.Events; using Content.Shared.Item; @@ -36,6 +37,7 @@ private void SubscribeEvents() SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(CheckAct); SubscribeLocalEvent(OnSleepAttempt); + SubscribeLocalEvent(OnCombatModeShouldHandInteract); } private void OnStateExitSubscribers(EntityUid target, MobStateComponent component, MobState state) @@ -139,5 +141,13 @@ private void OnUnequipAttempt(EntityUid target, MobStateComponent component, IsU CheckAct(target, component, args); } + private void OnCombatModeShouldHandInteract(EntityUid uid, MobStateComponent component, ref CombatModeShouldHandInteractEvent args) + { + // Disallow empty-hand-interacting in combat mode + // for non-dead mobs + if (!IsDead(uid, component)) + args.Cancelled = true; + } + #endregion } diff --git a/Content.Shared/MouseRotator/MouseRotatorComponent.cs b/Content.Shared/MouseRotator/MouseRotatorComponent.cs index 9b4dac54ba7..a35dfe0a288 100644 --- a/Content.Shared/MouseRotator/MouseRotatorComponent.cs +++ b/Content.Shared/MouseRotator/MouseRotatorComponent.cs @@ -14,22 +14,31 @@ public sealed partial class MouseRotatorComponent : Component /// /// How much the desired angle needs to change before a predictive event is sent /// - [DataField] - [ViewVariables(VVAccess.ReadWrite)] - public Angle AngleTolerance = Angle.FromDegrees(5.0); + [DataField, AutoNetworkedField] + public Angle AngleTolerance = Angle.FromDegrees(20.0); /// /// The angle that will be lerped to /// - [AutoNetworkedField, DataField] + [DataField, AutoNetworkedField] public Angle? GoalRotation; /// /// Max degrees the entity can rotate per second /// - [DataField] - [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public double RotationSpeed = float.MaxValue; + + /// + /// This one is important. If this is true, does not apply, and the system will + /// use instead. In this mode, the client will only send + /// events when an entity should snap to a different cardinal direction, rather than for every angle change. + /// + /// This is useful for cases like humans, where what really matters is the visual sprite direction, as opposed to something + /// like turrets or ship guns, which have finer range of movement. + /// + [DataField, AutoNetworkedField] + public bool Simple4DirMode = true; } /// @@ -41,3 +50,13 @@ public sealed class RequestMouseRotatorRotationEvent : EntityEventArgs { public Angle Rotation; } + +/// +/// Simpler version of for implementations +/// that only require snapping to 4-dir and not full angle rotation. +/// +[Serializable, NetSerializable] +public sealed class RequestMouseRotatorRotationSimpleEvent : EntityEventArgs +{ + public Direction Direction; +} diff --git a/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs b/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs index 4ff309682a4..c57d477bd2f 100644 --- a/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs +++ b/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs @@ -16,6 +16,7 @@ public override void Initialize() base.Initialize(); SubscribeAllEvent(OnRequestRotation); + SubscribeAllEvent(OnRequestSimpleRotation); } public override void Update(float frameTime) @@ -48,13 +49,27 @@ public override void Update(float frameTime) private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessionEventArgs args) { - if (args.SenderSession.AttachedEntity is not { } ent || !TryComp(ent, out var rotator)) + if (args.SenderSession.AttachedEntity is not { } ent + || !TryComp(ent, out var rotator) || rotator.Simple4DirMode) { - Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting local rotation without a mouse rotator component attached!"); + Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting local rotation directly without a valid mouse rotator component attached!"); return; } rotator.GoalRotation = msg.Rotation; Dirty(ent, rotator); } + + private void OnRequestSimpleRotation(RequestMouseRotatorRotationSimpleEvent ev, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not { } ent + || !TryComp(ent, out var rotator) || !rotator.Simple4DirMode) + { + Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting 4-dir rotation directly without a valid mouse rotator component attached!"); + return; + } + + rotator.GoalRotation = ev.Direction.ToAngle(); + Dirty(ent, rotator); + } } diff --git a/Content.Shared/Nutrition/Components/ThirstComponent.cs b/Content.Shared/Nutrition/Components/ThirstComponent.cs index da75a8e5dea..e5604de57b3 100644 --- a/Content.Shared/Nutrition/Components/ThirstComponent.cs +++ b/Content.Shared/Nutrition/Components/ThirstComponent.cs @@ -1,5 +1,5 @@ -using Content.Server.Nutrition.EntitySystems; using Content.Shared.Alert; +using Content.Shared.Nutrition.EntitySystems; using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; diff --git a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs index 4fa7c417aa4..b75a6d1a0a5 100644 --- a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs @@ -7,7 +7,7 @@ using Robust.Shared.Random; using Robust.Shared.Timing; -namespace Content.Server.Nutrition.EntitySystems; +namespace Content.Shared.Nutrition.EntitySystems; [UsedImplicitly] public sealed class ThirstSystem : EntitySystem @@ -27,12 +27,12 @@ public override void Initialize() _sawmill = Logger.GetSawmill("thirst"); SubscribeLocalEvent(OnRefreshMovespeed); - SubscribeLocalEvent(OnComponentStartup); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnUnpaused); } - private void OnComponentStartup(EntityUid uid, ThirstComponent component, ComponentStartup args) + private void OnMapInit(EntityUid uid, ThirstComponent component, MapInitEvent args) { // Do not change behavior unless starting value is explicitly defined if (component.CurrentThirst < 0) @@ -41,6 +41,7 @@ private void OnComponentStartup(EntityUid uid, ThirstComponent component, Compon (int) component.ThirstThresholds[ThirstThreshold.Thirsty] + 10, (int) component.ThirstThresholds[ThirstThreshold.Okay] - 1); } + component.NextUpdateTime = _timing.CurTime; component.CurrentThirstThreshold = GetThirstThreshold(component, component.CurrentThirst); component.LastThirstThreshold = ThirstThreshold.Okay; // TODO: Potentially change this -> Used Okay because no effects. // TODO: Check all thresholds make sense and throw if they don't. @@ -59,7 +60,7 @@ private void OnRefreshMovespeed(EntityUid uid, ThirstComponent component, Refres private void OnRejuvenate(EntityUid uid, ThirstComponent component, RejuvenateEvent args) { - ResetThirst(component); + SetThirst(uid, component, component.ThirstThresholds[ThirstThreshold.Okay]); } private ThirstThreshold GetThirstThreshold(ThirstComponent component, float amount) @@ -78,14 +79,18 @@ private ThirstThreshold GetThirstThreshold(ThirstComponent component, float amou return result; } - public void UpdateThirst(ThirstComponent component, float amount) + public void ModifyThirst(EntityUid uid, ThirstComponent component, float amount) { - component.CurrentThirst = Math.Clamp(component.CurrentThirst + amount, component.ThirstThresholds[ThirstThreshold.Dead], component.ThirstThresholds[ThirstThreshold.OverHydrated]); + SetThirst(uid, component, component.CurrentThirst + amount); } - public void ResetThirst(ThirstComponent component) + public void SetThirst(EntityUid uid, ThirstComponent component, float amount) { - component.CurrentThirst = component.ThirstThresholds[ThirstThreshold.Okay]; + component.CurrentThirst = Math.Clamp(amount, + component.ThirstThresholds[ThirstThreshold.Dead], + component.ThirstThresholds[ThirstThreshold.OverHydrated] + ); + Dirty(uid, component); } private bool IsMovementThreshold(ThirstThreshold threshold) @@ -166,7 +171,7 @@ public override void Update(float frameTime) thirst.NextUpdateTime += thirst.UpdateRate; - UpdateThirst(thirst, -thirst.ActualDecayRate); + ModifyThirst(uid, thirst, -thirst.ActualDecayRate); var calculatedThirstThreshold = GetThirstThreshold(thirst, thirst.CurrentThirst); if (calculatedThirstThreshold == thirst.CurrentThirstThreshold) diff --git a/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs b/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs index cde7e637d4a..008b7c2ced4 100644 --- a/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs +++ b/Content.Shared/Projectiles/EmbeddableProjectileComponent.cs @@ -13,37 +13,37 @@ public sealed partial class EmbeddableProjectileComponent : Component /// /// Minimum speed of the projectile to embed. /// - [ViewVariables(VVAccess.ReadWrite), DataField("minimumSpeed"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float MinimumSpeed = 5f; /// /// Delete the entity on embedded removal? /// Does nothing if there's no RemovalTime. /// - [ViewVariables(VVAccess.ReadWrite), DataField("deleteOnRemove"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public bool DeleteOnRemove; /// /// How long it takes to remove the embedded object. /// - [ViewVariables(VVAccess.ReadWrite), DataField("removalTime"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public float? RemovalTime = 3f; /// /// Whether this entity will embed when thrown, or only when shot as a projectile. /// - [ViewVariables(VVAccess.ReadWrite), DataField("embedOnThrow"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public bool EmbedOnThrow = true; /// /// How far into the entity should we offset (0 is wherever we collided). /// - [ViewVariables(VVAccess.ReadWrite), DataField("offset"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public Vector2 Offset = Vector2.Zero; /// /// Sound to play after embedding into a hit target. /// - [ViewVariables(VVAccess.ReadWrite), DataField("sound"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] public SoundSpecifier? Sound; } diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index 6c5d7897c23..1df743bc0b1 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Shared.Damage; using Content.Shared.DoAfter; +using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Projectiles; using Content.Shared.Sound.Components; @@ -24,6 +25,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem [Dependency] private readonly INetManager _netManager = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; @@ -85,6 +87,9 @@ private void OnEmbedRemove(EntityUid uid, EmbeddableProjectileComponent componen var landEv = new LandEvent(args.User, true); RaiseLocalEvent(uid, ref landEv); _physics.WakeBody(uid, body: physics); + + // try place it in the user's hand + _hands.TryPickupAnyHand(args.User, uid); } private void OnEmbedThrowDoHit(EntityUid uid, EmbeddableProjectileComponent component, ThrowDoHitEvent args) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ab94b9a30a4..66a1ebe9d0d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,79 +1,4 @@ Entries: -- author: graevy - changes: - - {message: Added reflection to the reflective vest and shuttle walls, type: Add} - id: 4381 - time: '2023-07-31T01:07:46.0000000+00:00' -- author: Bhijn and Myr - changes: - - {message: 'The flash overlay is no longer offset towards the actual physical center - of your screen when playing with the separated UI layout. Additionally, ultrawide - monitors no longer experience an exceptionally stretched flash overlay.', type: Fix} - id: 4382 - time: '2023-07-31T04:41:24.0000000+00:00' -- author: Misha_Unity - changes: - - {message: Command access allows to delete any articles, type: Tweak} - - {message: Updated mass-media console interface, type: Tweak} - id: 4383 - time: '2023-07-31T05:34:22.0000000+00:00' -- author: Ilya246 - changes: - - {message: Passive vents now equalize pressure both ways between the pipe and environment., - type: Tweak} - id: 4384 - time: '2023-07-31T05:40:31.0000000+00:00' -- author: Raitononai - changes: - - {message: Added missing job specific items to Senior Researcher and Senior Engineer - traitors., type: Fix} - id: 4385 - time: '2023-07-31T06:03:41.0000000+00:00' -- author: Alekshhh - changes: - - {message: 'The chemical page of the wiki has been heavily reworded, and a few - chemicals had their recipes tweaked and effects changed a little', type: Tweak} - id: 4386 - time: '2023-07-31T06:03:49.0000000+00:00' -- author: Raitononai - changes: - - {message: Adjusted the contents of command staff's lockers to reduce bloat., type: Tweak} - id: 4387 - time: '2023-07-31T20:29:01.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: Fixed the guidebook incorrectly showing oculine as damaging eyes., type: Fix} - id: 4388 - time: '2023-07-31T20:29:52.0000000+00:00' -- author: notafet - changes: - - {message: 'Bullets, lasers, and disabler bolts now hit vehicles and their occupants.', - type: Fix} - id: 4389 - time: '2023-07-31T20:30:24.0000000+00:00' -- author: crazybrain - changes: - - {message: Updated the HAMTR mech's description to avoid trademark issues., type: Fix} - id: 4390 - time: '2023-07-31T20:30:52.0000000+00:00' -- author: Raitononai - changes: - - {message: 'Gave the toy sword slight stamina damage, like the boxing gloves and - toy hammer.', type: Tweak} - id: 4391 - time: '2023-07-31T20:32:17.0000000+00:00' -- author: HerCoyote23 - changes: - - {message: 'Following a recent increase in Behonker activity, Nanotrasen has equipped - its security teams with a more harmful alternative to the stun baton.', type: Add} - id: 4392 - time: '2023-07-31T20:37:13.0000000+00:00' -- author: tom-leys - changes: - - {message: 'The roundend summary now shows a picture of your original body, even - after you ghosted', type: Fix} - id: 4393 - time: '2023-07-31T22:46:06.0000000+00:00' - author: Vasilis changes: - {message: Spilling a liquid will no longer expose the true identity of someone, @@ -2981,3 +2906,78 @@ Entries: - {message: Nukies can declare war again., type: Fix} id: 4880 time: '2023-09-23T20:00:13.0000000+00:00' +- author: Doru991 + changes: + - {message: Trash spawns correctly after food is eaten., type: Fix} + id: 4881 + time: '2023-09-24T17:20:03.0000000+00:00' +- author: DrTeaSpoon + changes: + - {message: Arrows can now be doped with chemicals., type: Tweak} + - {message: Spears now correctly transfares chemicals when thrown., type: Fix} + id: 4882 + time: '2023-09-24T19:46:16.0000000+00:00' +- author: mirrorcult + changes: + - {message: You can now pick up items (and dead pickupable mobs) in combat mode, + type: Add} + id: 4883 + time: '2023-09-24T19:47:42.0000000+00:00' +- author: Slava0135 + changes: + - {message: Fixed people getting too thirsty., type: Fix} + id: 4884 + time: '2023-09-24T19:50:41.0000000+00:00' +- author: PixelTK + changes: + - {message: Arachnids have one new back marking., type: Add} + id: 4885 + time: '2023-09-24T19:54:39.0000000+00:00' +- author: Slava0135 + changes: + - {message: Syndicate agents can no longer buy hot potatoes because of food safety + regulations, type: Remove} + id: 4886 + time: '2023-09-24T19:56:07.0000000+00:00' +- author: Tunguso4ka + changes: + - {message: Added gladiator`s helmet and uniform for both the station and planet + gladiators., type: Add} + - {message: Added bone armor and spear to please our lava planet habitats., type: Add} + id: 4887 + time: '2023-09-24T19:57:10.0000000+00:00' +- author: liltenhead + changes: + - {message: Lowered the maximum explosion range of canister bombs., type: Tweak} + id: 4888 + time: '2023-09-24T19:59:05.0000000+00:00' +- author: CaptainSqrBeard + changes: + - {message: 'Now after killing all nuclear operatives, the emergency shuttle will + be called instead of instant round end. Shuttle arrives in 10 minutes and you + can recall it.', type: Tweak} + id: 4889 + time: '2023-09-24T20:16:33.0000000+00:00' +- author: mirrorcult + changes: + - {message: Ghosts can now toggle whether they hear out-of-range local messages + using an action, type: Add} + id: 4890 + time: '2023-09-24T20:34:09.0000000+00:00' +- author: daerSeebaer + changes: + - {message: The AME now shuts down when the inserted fuel jar is empty, type: Add} + - {message: The AME no longer makes sounds if no fuel was injected, type: Tweak} + id: 4891 + time: '2023-09-24T20:39:49.0000000+00:00' +- author: gusxyz + changes: + - {message: Empty ore boxes are now orderable from cargo., type: Add} + id: 4892 + time: '2023-09-24T20:52:07.0000000+00:00' +- author: mirrorcult + changes: + - {message: Your character will now rotate in the direction of your mouse cursor + while in combat mode, type: Add} + id: 4893 + time: '2023-09-24T21:22:45.0000000+00:00' diff --git a/Resources/Locale/en-US/commands/toolshed-commands.ftl b/Resources/Locale/en-US/commands/toolshed-commands.ftl index 9320dac917d..29c8190d6e2 100644 --- a/Resources/Locale/en-US/commands/toolshed-commands.ftl +++ b/Resources/Locale/en-US/commands/toolshed-commands.ftl @@ -40,6 +40,12 @@ command-description-stations-rename = Renames the given station. command-description-stations-largestgrid = Returns the largest grid the given station has, if any. +command-description-stationevent-lsprob = + Lists the probability of different station events occuring out of the entire pool. +command-description-stationevent-lsprobtime = + Lists the probability of different station events occuring based on the specified length of a round. +command-description-stationevent-prob = + Returns the probability of a single station event occuring out of the entire pool. command-description-admins-active = Returns a list of active admins. command-description-admins-all = diff --git a/Resources/Locale/en-US/ghost/ghost-gui.ftl b/Resources/Locale/en-US/ghost/ghost-gui.ftl index 8275d7e5d61..909513e96ca 100644 --- a/Resources/Locale/en-US/ghost/ghost-gui.ftl +++ b/Resources/Locale/en-US/ghost/ghost-gui.ftl @@ -5,6 +5,9 @@ ghost-gui-toggle-ghost-visibility-popup = Toggled visibility of ghosts. ghost-gui-toggle-lighting-manager-popup = Toggled all lighting. ghost-gui-toggle-fov-popup = Toggled field-of-view. +ghost-gui-toggle-hearing-popup-on = You can now hear all messages. +ghost-gui-toggle-hearing-popup-off = You can now only hear radio and nearby messages. + ghost-target-window-title = Ghost Warp ghost-target-window-current-button = Warp: {$name} diff --git a/Resources/Locale/en-US/markings/arachnid.ftl b/Resources/Locale/en-US/markings/arachnid.ftl index 7fb78fb74c2..e383cca649a 100644 --- a/Resources/Locale/en-US/markings/arachnid.ftl +++ b/Resources/Locale/en-US/markings/arachnid.ftl @@ -36,6 +36,10 @@ marking-ArachnidAppendagesShort = Appendages (Short) marking-ArachnidAppendagesShort-short_primary = Appendage marking-ArachnidAppendagesShort-short_secondary = Stripes +marking-ArachnidAppendagesFreaky = Appendages (Freaky long) +marking-ArachnidAppendagesFreaky-freaky_primary = Appendage +marking-ArachnidAppendagesFreaky-freaky_secondary = Stripes + marking-ArachnidTorsoStripes = Stripes marking-ArachnidTorsoStripes-stripes = Design diff --git a/Resources/Locale/en-US/materials/materials.ftl b/Resources/Locale/en-US/materials/materials.ftl index 12bfcf5e12e..abd61d1065f 100644 --- a/Resources/Locale/en-US/materials/materials.ftl +++ b/Resources/Locale/en-US/materials/materials.ftl @@ -22,6 +22,7 @@ materials-uranium = uranium materials-bananium = bananium materials-meat = meat materials-web = silk +materials-bones = bone # Material Reclaimer material-reclaimer-upgrade-process-rate = process rate diff --git a/Resources/Locale/en-US/nukeops/nuke-ops.ftl b/Resources/Locale/en-US/nukeops/nuke-ops.ftl new file mode 100644 index 00000000000..b4f2238e072 --- /dev/null +++ b/Resources/Locale/en-US/nukeops/nuke-ops.ftl @@ -0,0 +1,2 @@ +nuke-ops-no-more-threat-announcement-shuttle-call = Based on our scans from our long-range sensors, the nuclear threat is now eliminated. We will call emergency shuttle that will arrive shortly. ETA: {$time} {$units}. You can recall the shuttle to extend the shift. +nuke-ops-no-more-threat-announcement = Based on our scans from our long-range sensors, the nuclear threat is now eliminated. Shuttle is already called. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/commands/toolshed-commands.ftl b/Resources/Locale/ru-RU/commands/toolshed-commands.ftl index 59d206e98e9..5fd005b6c99 100644 --- a/Resources/Locale/ru-RU/commands/toolshed-commands.ftl +++ b/Resources/Locale/ru-RU/commands/toolshed-commands.ftl @@ -19,6 +19,9 @@ command-description-stations-addgrid = Adds a grid to the given station. command-description-stations-rmgrid = Removes a grid from the given station. command-description-stations-rename = Renames the given station. command-description-stations-largestgrid = Returns the largest grid the given station has, if any. +command-description-stationevent-lsprob = Lists the probability of different station events occuring out of the entire pool. +command-description-stationevent-lsprobtime = Lists the probability of different station events occuring based on the specified length of a round. +command-description-stationevent-prob = Returns the probability of a single station event occuring out of the entire pool. command-description-admins-active = Returns a list of active admins. command-description-admins-all = Returns a list of ALL admins, including deadmined ones. command-description-marked = Returns the value of $marked as a List. diff --git a/Resources/Locale/ru-RU/ghost/ghost-gui.ftl b/Resources/Locale/ru-RU/ghost/ghost-gui.ftl index 5ae77bfdb62..fbe325d2dfd 100644 --- a/Resources/Locale/ru-RU/ghost/ghost-gui.ftl +++ b/Resources/Locale/ru-RU/ghost/ghost-gui.ftl @@ -4,6 +4,8 @@ ghost-gui-ghost-roles-button = Роли призраков ({ $count }) ghost-gui-toggle-ghost-visibility-popup = Видимость других призраков была изменена. ghost-gui-toggle-lighting-manager-popup = Рендеринг света был переключён. ghost-gui-toggle-fov-popup = Поле зрения было переключено. +ghost-gui-toggle-hearing-popup-on = You can now hear all messages. +ghost-gui-toggle-hearing-popup-off = You can now only hear radio and nearby messages. ghost-target-window-title = Телепорт призрака ghost-target-window-current-button = Телепорт в: { $name } ghost-roles-window-title = Роли призраков diff --git a/Resources/Locale/ru-RU/markings/arachnid.ftl b/Resources/Locale/ru-RU/markings/arachnid.ftl index de9d0078bb7..4709b376582 100644 --- a/Resources/Locale/ru-RU/markings/arachnid.ftl +++ b/Resources/Locale/ru-RU/markings/arachnid.ftl @@ -26,6 +26,9 @@ marking-ArachnidAppendagesHarvest-harvest_secondary = Полосы marking-ArachnidAppendagesShort = Придатки (Короткие) marking-ArachnidAppendagesShort-short_primary = Придаток marking-ArachnidAppendagesShort-short_secondary = Полосы +marking-ArachnidAppendagesFreaky = Appendages (Freaky long) +marking-ArachnidAppendagesFreaky-freaky_primary = Appendage +marking-ArachnidAppendagesFreaky-freaky_secondary = Stripes marking-ArachnidTorsoStripes = Полосы marking-ArachnidTorsoStripes-stripes = Дизайн marking-ArachnidTorsoSlashes = Косые срезы diff --git a/Resources/Locale/ru-RU/materials/materials.ftl b/Resources/Locale/ru-RU/materials/materials.ftl index 1c0fec93a7a..86198555754 100644 --- a/Resources/Locale/ru-RU/materials/materials.ftl +++ b/Resources/Locale/ru-RU/materials/materials.ftl @@ -20,5 +20,6 @@ materials-uranium = уран materials-bananium = бананиум materials-meat = мясо materials-web = шёлк +materials-bones = bone # Material Reclaimer material-reclaimer-upgrade-process-rate = скорость переработки diff --git a/Resources/Locale/ru-RU/nukeops/nuke-ops.ftl b/Resources/Locale/ru-RU/nukeops/nuke-ops.ftl new file mode 100644 index 00000000000..ebb47861075 --- /dev/null +++ b/Resources/Locale/ru-RU/nukeops/nuke-ops.ftl @@ -0,0 +1,2 @@ +nuke-ops-no-more-threat-announcement-shuttle-call = Based on our scans from our long-range sensors, the nuclear threat is now eliminated. We will call emergency shuttle that will arrive shortly. ETA: { $time } { $units }. You can recall the shuttle to extend the shift. +nuke-ops-no-more-threat-announcement = Based on our scans from our long-range sensors, the nuclear threat is now eliminated. Shuttle is already called. diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/thrusters.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/thrusters.ftl index 1fe90b231e7..93de50b5f89 100644 --- a/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/thrusters.ftl +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/entities/structures/shuttles/thrusters.ftl @@ -2,15 +2,11 @@ ent-BaseThruster = ракетный двигатель .desc = Он делает ньооооооом. ent-Thruster = ракетный двигатель .desc = Он делает ньооооооом. -ent-ThrusterUnanchored = { ent-Thruster } - .desc = { ent-Thruster.desc } ent-DebugThruster = ракетный двигатель .desc = Он делает ньооооооом. Не требует ни питания, ни свободного места. .suffix = DEBUG ent-Gyroscope = гироскоп .desc = Увеличивает потенциальное угловое вращение шаттла. -ent-GyroscopeUnanchored = { ent-Gyroscope } - .desc = { ent-Gyroscope.desc } ent-DebugGyroscope = гироскоп .desc = Увеличивает потенциальное угловое вращение шаттла. .suffix = DEBUG diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_cargo.yml b/Resources/Prototypes/Catalog/Cargo/cargo_cargo.yml index f36aee12e46..c4cd57c85f7 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_cargo.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_cargo.yml @@ -8,6 +8,16 @@ category: Cargo group: market +- type: cargoProduct + id: CargoOreBox + icon: + sprite: /Textures/Structures/Storage/orebox.rsi + state: orebox + product: OreBox + cost: 500 + category: Cargo + group: market + - type: cargoProduct id: CargoLuxuryHardsuit icon: diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml index 8476fff464a..d4dd657027c 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml @@ -41,6 +41,8 @@ ClothingUniformJumpsuitKimono: 1 ClothingHeadHatCasa: 1 ClothingHeadHatHairflower: 1 + ClothingHeadHatGladiator: 1 + ClothingUniformJumpsuitGladiator: 1 emaggedInventory: ClothingShoesBling: 1 ClothingOuterDogi: 1 diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index 922c2cc790d..c2ecf0f9466 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -777,3 +777,14 @@ - ClothMade - WhitelistChameleon - HamsterWearable + +- type: entity + parent: ClothingHeadBase + id: ClothingHeadHatGladiator + name: Gladiator helmet + description: Protects the head from harsh ash winds and toy spears. + components: + - type: Sprite + sprite: Clothing/Head/Hats/gladiator.rsi + - type: Clothing + sprite: Clothing/Head/Hats/gladiator.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index 576e88a2858..c7622e60be6 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -336,3 +336,18 @@ sprite: Clothing/Head/Helmets/ert_janitor.rsi - type: Clothing sprite: Clothing/Head/Helmets/ert_janitor.rsi + +#Bone Helmet +- type: entity + parent: ClothingHeadHelmetBasic + id: ClothingHeadHelmetBone + name: bone helmet + description: Cool-looking helmet made of skull of your enemies. + components: + - type: Sprite + sprite: Clothing/Head/Helmets/bone_helmet.rsi + - type: Clothing + sprite: Clothing/Head/Helmets/bone_helmet.rsi + - type: Construction + graph: BoneHelmet + node: helmet diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml index 666cbc2d203..b66ddc1dff7 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml @@ -255,3 +255,28 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: GroupExamine + +- type: entity + parent: ClothingOuterBaseLarge + id: ClothingOuterArmorBone + name: bone armor + description: Sits on you like a second skin. + components: + - type: Sprite + sprite: Clothing/OuterClothing/Armor/bone_armor.rsi + - type: Clothing + sprite: Clothing/OuterClothing/Armor/bone_armor.rsi + - type: Armor + modifiers: + coefficients: + Blunt: 0.6 + Slash: 0.8 + Piercing: 0.4 + - type: ClothingSpeedModifier + walkModifier: 0.8 + - type: ExplosionResistance + damageCoefficient: 0.4 + - type: GroupExamine + - type: Construction + graph: BoneArmor + node: armor diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 992abaa4629..ff70343c573 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -1312,3 +1312,14 @@ sprite: Clothing/Uniforms/Jumpsuit/loungewear.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/loungewear.rsi + +- type: entity + parent: ClothingUniformBase + id: ClothingUniformJumpsuitGladiator + name: gladiator uniform + description: Made for true gladiators (or Ash Walkers). + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/gladiator.rsi + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/gladiator.rsi diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/arachnid.yml index cf3e1ab2d56..f4c446df5b7 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/arachnid.yml @@ -106,6 +106,17 @@ - sprite: Mobs/Customization/Arachnid/appendages.rsi state: short_secondary +- type: marking + id: ArachnidAppendagesFreaky + bodyPart: Tail + markingCategory: Tail + speciesRestriction: [Arachnid] + sprites: + - sprite: Mobs/Customization/Arachnid/appendages.rsi + state: freaky_primary + - sprite: Mobs/Customization/Arachnid/appendages.rsi + state: freaky_secondary + # Chest - type: marking id: ArachnidTorsoStripes diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index bd339291f0b..807c0f92364 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -980,7 +980,6 @@ - Trash - VimPilot - Mouse - - DoorBumpOpener - type: Respirator damage: types: diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index de618dda8fa..2d40a069584 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -15,6 +15,7 @@ context: "aghost" - type: Ghost canInteract: true + - type: GhostHearing - type: Hands - type: Puller - type: CombatMode diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml index 66e0e42978f..c7cac426a41 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml @@ -32,6 +32,7 @@ - type: Examiner skipChecks: true - type: Ghost + - type: GhostHearing - type: MovementSpeedModifier baseSprintSpeed: 12 baseWalkSpeed: 8 @@ -106,3 +107,17 @@ clientExclusive: true checkCanInteract: false event: !type:ToggleGhostsActionEvent + +- type: entity + id: ActionToggleGhostHearing + name: Toggle Ghost Hearing + description: Toggle between hearing all messages and hearing only radio & nearby messages. + noSpawn: true + components: + - type: InstantAction + checkCanInteract: false + icon: + sprite: Clothing/Ears/Headsets/base.rsi + state: icon + iconOn: Interface/Actions/ghostHearingToggled.png + event: !type:ToggleGhostHearingActionEvent diff --git a/Resources/Prototypes/Entities/Objects/Materials/materials.yml b/Resources/Prototypes/Entities/Objects/Materials/materials.yml index dd47d3c1919..7386eaee4d3 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/materials.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/materials.yml @@ -534,3 +534,44 @@ count: 1 - type: Item size: 1 + +- type: entity + parent: MaterialBase + id: MaterialBones + name: bones + suffix: Full + components: + - type: Stack + stackType: Bones + baseLayer: base + layerStates: + - bones + - bones_2 + - bones_3 + - type: Sprite + state: cotton_3 + layers: + - state: cotton_3 + map: ["base"] + - type: Appearance + - type: Item + size: 30 + - type: Food + - type: BadFood + - type: SolutionContainerManager + solutions: + food: + maxVol: 5 + reagents: + - ReagentId: Vitamin + Quantity: 3 + +- type: entity + parent: MaterialBones + id: MaterialBones1 + suffix: 1 + components: + - type: Stack + count: 1 + - type: Item + size: 1 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml index 7112d07f2f0..201e328c75b 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml @@ -41,6 +41,24 @@ damage: types: Piercing: 25 + - type: SolutionContainerManager + solutions: + ammo: + maxVol: 5 + - type: RefillableSolution + solution: ammo + - type: InjectableSolution + solution: ammo + - type: SolutionInjectOnCollide + transferAmount: 5 + blockSlots: NONE + - type: SolutionTransfer + maxTransferAmount: 5 + - type: Appearance + - type: SolutionContainerVisuals + maxFillLevels: 1 + fillBaseName: solution + - type: entity parent: BaseArrow @@ -55,6 +73,9 @@ - state: rod color: brown - state: tip + - state: solution1 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false - type: Projectile damage: types: @@ -75,6 +96,9 @@ color: darkgray - state: tip color: lightblue + - state: solution1 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false - type: Projectile damage: types: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/turrets.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/turrets.yml index 3c7d0dd5d08..632e86e4fcc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/turrets.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/turrets.yml @@ -66,6 +66,7 @@ interactSuccessSound: path: /Audio/Effects/double_beep.ogg - type: CombatMode + toggleMouseRotator: false - type: Damageable damageContainer: Inorganic - type: Destructible @@ -110,7 +111,9 @@ SoundTargetInLOS: !type:SoundPathSpecifier path: /Audio/Effects/double_beep.ogg - type: MouseRotator + angleTolerance: 5 rotationSpeed: 180 + simple4DirMode: false - type: NoRotateOnInteract - type: NoRotateOnMove - type: Input diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml index c893829beaf..bbd4d2389d3 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml @@ -28,7 +28,11 @@ - type: Sharp - type: Sprite sprite: Objects/Weapons/Melee/spear.rsi - state: spear + layers: + - state: spear + - state: spear1 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false - type: MeleeWeapon damage: types: @@ -61,6 +65,9 @@ solution: melee - type: InjectableSolution solution: melee + - type: SolutionInjectOnCollide + transferAmount: 5 + blockSlots: NONE - type: SolutionTransfer maxTransferAmount: 5 - type: Wieldable @@ -96,6 +103,10 @@ damage: types: Blunt: 5 + - type: Appearance + - type: SolutionContainerVisuals + maxFillLevels: 1 + fillBaseName: spear - type: entity name: reinforced spear @@ -155,3 +166,14 @@ Radiation: 9 - type: Construction graph: SpearUranium + +- type: entity + name: bone spear + parent: Spear + id: SpearBone + description: A spear made of bones. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/bone_spear.rsi + - type: Construction + graph: SpearBone diff --git a/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml b/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml index 4c5b41e8e12..7099e1b45d3 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml @@ -4,6 +4,8 @@ description: A large storage container for holding unprocessed ores. parent: BaseStructureDynamic components: + - type: StaticPrice + price: 500 - type: Anchorable - type: InteractionOutline - type: Damageable diff --git a/Resources/Prototypes/Hydroponics/seeds.yml b/Resources/Prototypes/Hydroponics/seeds.yml index e990ffdb370..8e1c6c93285 100644 --- a/Resources/Prototypes/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Hydroponics/seeds.yml @@ -1272,7 +1272,7 @@ Vitamin: Min: 1 Max: 4 - PotencyDivisor: 40 + PotencyDivisor: 40 - type: seed id: bungo @@ -1301,4 +1301,4 @@ Enzyme: Min: 5 Max: 10 - PotencyDivisor: 20 \ No newline at end of file + PotencyDivisor: 20 diff --git a/Resources/Prototypes/Reagents/Materials/materials.yml b/Resources/Prototypes/Reagents/Materials/materials.yml index 66033508062..4c94798dbf3 100644 --- a/Resources/Prototypes/Reagents/Materials/materials.yml +++ b/Resources/Prototypes/Reagents/Materials/materials.yml @@ -91,3 +91,11 @@ icon: { sprite: Objects/Materials/silk.rsi, state: icon } color: "#eeeeee" #eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee price: 0 # Maybe better for it to be priceless, knowing how greedy cargo is. + +- type: material + id: Bones + name: materials-bones + unit: materials-unit-piece + icon: { sprite: Objects/Materials/materials.rsi, state: bones } + color: "#896f5e" + price: 0 diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/clothing/armor.yml b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/armor.yml new file mode 100644 index 00000000000..e597d7cdc45 --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/armor.yml @@ -0,0 +1,27 @@ +- type: constructionGraph + id: BoneArmor + start: start + graph: + - node: start + edges: + - to: armor + steps: + - material: Bones + amount: 6 + doAfter: 2 + - node: armor + entity: ClothingOuterArmorBone + +- type: constructionGraph + id: BoneHelmet + start: start + graph: + - node: start + edges: + - to: helmet + steps: + - material: Bones + amount: 4 + doAfter: 1 + - node: helmet + entity: ClothingHeadHelmetBone diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/spear.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/spear.yml index c680662ccb9..6e1c682f475 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/spear.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/spear.yml @@ -89,3 +89,20 @@ doAfter: 1 - node: spear entity: SpearUranium + +- type: constructionGraph + id: SpearBone + start: start + graph: + - node: start + edges: + - to: spear + steps: + - material: Bones + amount: 4 + doAfter: 2 + - material: WebSilk + amount: 1 + doAfter: 1 + - node: spear + entity: SpearBone diff --git a/Resources/Prototypes/Recipes/Construction/clothing.yml b/Resources/Prototypes/Recipes/Construction/clothing.yml index 796ab786420..e8bd1b69385 100644 --- a/Resources/Prototypes/Recipes/Construction/clothing.yml +++ b/Resources/Prototypes/Recipes/Construction/clothing.yml @@ -8,3 +8,25 @@ description: A modified hardsuit fit for a clown. icon: { sprite: Clothing/OuterClothing/Hardsuits/clown.rsi, state: icon } objectType: Item + +- type: construction + name: bone armor + id: BoneArmor + graph: BoneArmor + startNode: start + targetNode: armor + category: construction-category-clothing + description: Armor made of bones. + icon: { sprite: Clothing/OuterClothing/Armor/bone_armor.rsi, state: icon } + objectType: Item + +- type: construction + name: bone helmet + id: BoneHelmet + graph: BoneHelmet + startNode: start + targetNode: helmet + category: construction-category-clothing + description: Helmet made of bones. + icon: { sprite: Clothing/Head/Helmets/bone_helmet.rsi, state: icon } + objectType: Item diff --git a/Resources/Prototypes/Recipes/Construction/weapons.yml b/Resources/Prototypes/Recipes/Construction/weapons.yml index 25da0d10733..24e46f3856f 100644 --- a/Resources/Prototypes/Recipes/Construction/weapons.yml +++ b/Resources/Prototypes/Recipes/Construction/weapons.yml @@ -140,3 +140,14 @@ description: A shoddily constructed bow made out of wood and cloth. It's not much, but it's gotten the job done for millennia. icon: { sprite: Objects/Weapons/Guns/Bow/bow.rsi, state: unwielded } objectType: Item + +- type: construction + name: bone spear + id: SpearBone + graph: SpearBone + startNode: start + targetNode: spear + category: construction-category-weapons + description: Bones and silk combined together. + icon: { sprite: Objects/Weapons/Melee/bone_spear.rsi, state: spear } + objectType: Item diff --git a/Resources/Prototypes/Stacks/Materials/materials.yml b/Resources/Prototypes/Stacks/Materials/materials.yml index 283c64a10ba..00153ef23c0 100644 --- a/Resources/Prototypes/Stacks/Materials/materials.yml +++ b/Resources/Prototypes/Stacks/Materials/materials.yml @@ -77,3 +77,11 @@ spawn: MaterialWebSilk1 maxCount: 50 itemSize: 1 + +- type: stack + id: Bones + name: bones + icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bones} + spawn: MaterialBones1 + maxCount: 30 + itemSize: 1 diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/equipped-HELMET.png new file mode 100644 index 00000000000..12eb5037a20 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/icon.png b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/icon.png new file mode 100644 index 00000000000..d772d55d24f Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/inhand-left.png new file mode 100644 index 00000000000..1f77ba61d0a Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/inhand-right.png new file mode 100644 index 00000000000..f5aa1af07da Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json new file mode 100644 index 00000000000..bbb0aac6648 --- /dev/null +++ b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "direction": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/equipped-HELMET.png new file mode 100644 index 00000000000..243a83e036c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/icon.png b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/icon.png new file mode 100644 index 00000000000..2bd0eb748fa Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/inhand-left.png new file mode 100644 index 00000000000..484dd6a5a3c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/inhand-right.png new file mode 100644 index 00000000000..9a33a3051e9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/meta.json new file mode 100644 index 00000000000..bbb0aac6648 --- /dev/null +++ b/Resources/Textures/Clothing/Head/Helmets/bone_helmet.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "direction": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 00000000000..6788174f5a3 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/equipped-OUTERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/icon.png new file mode 100644 index 00000000000..29f3288aaa8 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/inhand-left.png new file mode 100644 index 00000000000..f4b22946740 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/inhand-right.png new file mode 100644 index 00000000000..2594f917b89 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/meta.json new file mode 100644 index 00000000000..e482264df5f --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/Armor/bone_armor.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 00000000000..7a802db3e31 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/icon.png new file mode 100644 index 00000000000..224c170d586 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/meta.json new file mode 100644 index 00000000000..8ee0b256cec --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/gladiator.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/pull/46166/commits/b4b1dde442978f9d85d534437a32e5f2fbc3e89e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-INNERCLOTHING", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Interface/Actions/ghostHearingToggled.png b/Resources/Textures/Interface/Actions/ghostHearingToggled.png new file mode 100644 index 00000000000..2c619ee496c Binary files /dev/null and b/Resources/Textures/Interface/Actions/ghostHearingToggled.png differ diff --git a/Resources/Textures/Interface/Actions/meta.json b/Resources/Textures/Interface/Actions/meta.json index 2ac85458561..9998f662341 100644 --- a/Resources/Textures/Interface/Actions/meta.json +++ b/Resources/Textures/Interface/Actions/meta.json @@ -48,6 +48,9 @@ }, { "name": "web" + }, + { + "name": "ghostHearingToggled" } ] } diff --git a/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/freaky_primary.png b/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/freaky_primary.png new file mode 100644 index 00000000000..b852964156c Binary files /dev/null and b/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/freaky_primary.png differ diff --git a/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/freaky_secondary.png b/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/freaky_secondary.png new file mode 100644 index 00000000000..7b17e94e5b6 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/freaky_secondary.png differ diff --git a/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/meta.json b/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/meta.json index a85abf1ddb8..b1cb1eb1ab5 100644 --- a/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/Arachnid/appendages.rsi/meta.json @@ -70,6 +70,14 @@ { "name": "short_secondary", "directions": 4 + }, + { + "name": "freaky_primary", + "directions": 4 + }, + { + "name": "freaky_secondary", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Materials/materials.rsi/bones.png b/Resources/Textures/Objects/Materials/materials.rsi/bones.png new file mode 100644 index 00000000000..50b0439588a Binary files /dev/null and b/Resources/Textures/Objects/Materials/materials.rsi/bones.png differ diff --git a/Resources/Textures/Objects/Materials/materials.rsi/bones_2.png b/Resources/Textures/Objects/Materials/materials.rsi/bones_2.png new file mode 100644 index 00000000000..4d900ad5a43 Binary files /dev/null and b/Resources/Textures/Objects/Materials/materials.rsi/bones_2.png differ diff --git a/Resources/Textures/Objects/Materials/materials.rsi/bones_3.png b/Resources/Textures/Objects/Materials/materials.rsi/bones_3.png new file mode 100644 index 00000000000..713710671f5 Binary files /dev/null and b/Resources/Textures/Objects/Materials/materials.rsi/bones_3.png differ diff --git a/Resources/Textures/Objects/Materials/materials.rsi/meta.json b/Resources/Textures/Objects/Materials/materials.rsi/meta.json index a1db317d4bc..f0307208e92 100644 --- a/Resources/Textures/Objects/Materials/materials.rsi/meta.json +++ b/Resources/Textures/Objects/Materials/materials.rsi/meta.json @@ -141,6 +141,15 @@ { "name": "wood-inhand-right", "directions": 4 + }, + { + "name": "bones" + }, + { + "name": "bones_2" + }, + { + "name": "bones_3" } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json index b8313f78101..f5f474b9606 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/meta.json @@ -17,7 +17,7 @@ "name": "tip" }, { - "name": "solution" + "name": "solution1" }, { "name": "inhand-left", diff --git a/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution.png b/Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution1.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution.png rename to Resources/Textures/Objects/Weapons/Guns/Projectiles/arrows.rsi/solution1.png diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/equipped-BACKPACK.png new file mode 100644 index 00000000000..585f2279403 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/inhand-left.png new file mode 100644 index 00000000000..48b74e934a5 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/inhand-right.png new file mode 100644 index 00000000000..b739e105cfa Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/meta.json new file mode 100644 index 00000000000..49209bf2dcd --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/meta.json @@ -0,0 +1,37 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "spear" + }, + { + "name": "spear1" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/spear.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/spear.png new file mode 100644 index 00000000000..e46cb9bea85 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/spear.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/spear1.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/spear1.png new file mode 100644 index 00000000000..ed04f597774 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/spear1.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..5f2a9d893b3 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..a10d676762a Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/bone_spear.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/meta.json index 0800614b814..383ea777d27 100644 --- a/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/meta.json @@ -10,6 +10,9 @@ { "name": "spear" }, + { + "name": "spear1" + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/spear1.png b/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/spear1.png new file mode 100644 index 00000000000..fec362ac728 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/plasma_spear.rsi/spear1.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/meta.json index 0800614b814..383ea777d27 100644 --- a/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/meta.json @@ -10,6 +10,9 @@ { "name": "spear" }, + { + "name": "spear1" + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/spear1.png b/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/spear1.png new file mode 100644 index 00000000000..fec362ac728 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/reinforced_spear.rsi/spear1.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/spear.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/spear.rsi/meta.json index 6c80fc8cc11..95f2736de14 100644 --- a/Resources/Textures/Objects/Weapons/Melee/spear.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Melee/spear.rsi/meta.json @@ -10,6 +10,9 @@ { "name": "spear" }, + { + "name": "spear1" + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Objects/Weapons/Melee/spear.rsi/spear1.png b/Resources/Textures/Objects/Weapons/Melee/spear.rsi/spear1.png new file mode 100644 index 00000000000..fec362ac728 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/spear.rsi/spear1.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/meta.json index 0800614b814..383ea777d27 100644 --- a/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/meta.json @@ -10,6 +10,9 @@ { "name": "spear" }, + { + "name": "spear1" + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/spear1.png b/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/spear1.png new file mode 100644 index 00000000000..fec362ac728 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/uranium_spear.rsi/spear1.png differ diff --git a/Tools/actions_changelog_rss.py b/Tools/actions_changelog_rss.py index 01d9234ca8d..7be6e3dc26c 100755 --- a/Tools/actions_changelog_rss.py +++ b/Tools/actions_changelog_rss.py @@ -43,6 +43,7 @@ FEED_DESCRIPTION = "Changelog for the official Wizard's Den branch of Space Station 14." FEED_LANGUAGE = "en-US" FEED_GUID_PREFIX = "ss14-changelog-wizards-" +FEED_URL = "https://central.spacestation14.io/changelog.xml" CHANGELOG_FILE = "Resources/Changelog/Changelog.yml" @@ -56,7 +57,11 @@ XML_NS = "https://spacestation14.com/changelog_rss" XML_NS_B = f"{{{XML_NS}}}" +XML_NS_ATOM = "http://www.w3.org/2005/Atom" +XML_NS_ATOM_B = f"{{{XML_NS_ATOM}}}" + ET.register_namespace("ss14", XML_NS) +ET.register_namespace("atom", XML_NS_ATOM) # From https://stackoverflow.com/a/37958106/4678631 class NoDatesSafeLoader(yaml.SafeLoader): @@ -113,6 +118,7 @@ def create_feed(changelog: Any, previous_items: List[ET.Element]) -> Tuple[ET.El ET.SubElement(channel, "language").text = FEED_LANGUAGE ET.SubElement(channel, "lastBuildDate").text = email.utils.format_datetime(time_now) + ET.SubElement(channel, XML_NS_ATOM_B + "link", {"type": "application/rss+xml", "rel": "self", "href": FEED_URL}) # Find the last item ID mentioned in the previous changelog last_changelog_id = find_last_changelog_id(previous_items) @@ -132,7 +138,7 @@ def create_new_item_since(changelog: Any, channel: ET.Element, since: int, now: attrs = {XML_NS_B + "from-id": str(since), XML_NS_B + "to-id": str(top_entry_id)} new_item = ET.SubElement(channel, "item", attrs) ET.SubElement(new_item, "pubDate").text = email.utils.format_datetime(now) - ET.SubElement(new_item, "guid").text = f"{FEED_GUID_PREFIX}{since}-{top_entry_id}" + ET.SubElement(new_item, "guid", {"isPermaLink": "false"}).text = f"{FEED_GUID_PREFIX}{since}-{top_entry_id}" ET.SubElement(new_item, "description").text = generate_description_for_entries(entries_for_item)