diff --git a/Content.Client/ADT/Geras/GerasSystem.cs b/Content.Client/ADT/Geras/GerasSystem.cs index 7db0352eaaf..c592700f73f 100644 --- a/Content.Client/ADT/Geras/GerasSystem.cs +++ b/Content.Client/ADT/Geras/GerasSystem.cs @@ -1,8 +1,6 @@ using Content.Client.ADT.Geras.Component; using Content.Shared.ADT.Geras; using Robust.Client.GameObjects; -using Content.Shared.Item; -using static Robust.Client.GameObjects.SpriteComponent; namespace Content.Client.ADT.Geras; diff --git a/Content.Server/ADT/Geras/GerasSystem.cs b/Content.Server/ADT/Geras/GerasSystem.cs index 5ef2fb7214a..4b2645bde9b 100644 --- a/Content.Server/ADT/Geras/GerasSystem.cs +++ b/Content.Server/ADT/Geras/GerasSystem.cs @@ -8,8 +8,17 @@ using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.ActionBlocker; -using Content.Shared.Item; -using Content.Shared.Hands; +using Robust.Shared.Utility; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Anomaly.Components; +using Content.Shared.Inventory; +using Content.Shared.Nuke; +using Content.Server.Ghost.Roles.Components; +using Content.Shared.Mind.Components; +using Content.Shared.Storage; +using Robust.Shared.Containers; +using System.Linq; namespace Content.Server.ADT.Geras; @@ -21,8 +30,14 @@ public sealed class GerasSystem : SharedGerasSystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + public override void Initialize() { + base.Initialize(); SubscribeLocalEvent(OnMorphIntoGeras); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnZombification); @@ -42,17 +57,84 @@ private void OnMapInit(EntityUid uid, GerasComponent component, MapInitEvent arg } } + private bool HasForbiddenComponent(EntityUid uid) + { + return HasComp(uid) || + HasComp(uid) || + HasComp(uid); + } + + private void EjectForbiddenRecursive(EntityUid item, EntityUid owner) + { + if (!TryComp(item, out var containerManager)) + return; + + foreach (var container in containerManager.Containers.Values) + { + var containedList = container.ContainedEntities.ToArray(); + foreach (var contained in containedList) + { + if (HasForbiddenComponent(contained)) + { + _container.Remove(contained, container, force: true); + _transform.DropNextTo(contained, owner); + } + else + { + EjectForbiddenRecursive(contained, owner); + } + } + } + } + private void OnMorphIntoGeras(EntityUid uid, GerasComponent component, MorphIntoGeras args) { if (HasComp(uid)) return; + if (HasComp(uid)) + { + _popupSystem.PopupEntity(Loc.GetString("geras-popup-cant-use-anomaly"), uid, uid); + return; + } + if (!_actionBlocker.CanInteract(uid, null) || _mobState.IsDead(uid) || _mobState.IsIncapacitated(uid)) { _popupSystem.PopupEntity(Loc.GetString("geras-popup-cant-use"), uid, uid); return; } + if (TryComp(uid, out var hands)) + { + foreach (var held in _hands.EnumerateHeld(uid)) + { + _hands.TryDrop(uid, held, Transform(uid).Coordinates); + } + } + + if (TryComp(uid, out var inventoryComp)) + { + _inventorySystem.TryUnequip(uid, "outerClothing", force: true); + + foreach (var slot in inventoryComp.Slots) + { + if (_inventorySystem.TryGetSlotEntity(uid, slot.Name, out var itemUid) && itemUid.HasValue) + { + var item = itemUid.Value; + if (HasForbiddenComponent(item)) + { + _inventorySystem.TryUnequip(uid, slot.Name, force: true); + } + else + { + EjectForbiddenRecursive(item, uid); + } + } + } + } + + EjectForbiddenRecursive(uid, uid); + var ent = _polymorphSystem.PolymorphEntity(uid, component.GerasPolymorphId); if (!ent.HasValue) diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs index 4d853bafef9..66d7f0f95be 100644 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs @@ -17,6 +17,10 @@ using Content.Shared.Speech.Muting; using Content.Shared.ADT.Traits; using Content.Shared.Storage.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Temperature.Systems; +using Content.Shared.Atmos.Components; +using Content.Shared.Temperature.Components; //ADT-Geras-Tweak-End using Content.Server.Inventory; using Content.Server.Polymorph.Components; @@ -69,6 +73,9 @@ public sealed partial class PolymorphSystem : EntitySystem [Dependency] private readonly SharedMindSystem _mindSystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly FollowerSystem _follow = default!; // goob edit + [Dependency] private readonly FlammableSystem _flammable = default!; //ADT-Geras-Tweak + [Dependency] private readonly SharedStaminaSystem _stamina = default!; //ADT-Geras-Tweak + [Dependency] private readonly TemperatureSystem _temperatureSystem = default!; //ADT-Geras-Tweak [Dependency] private readonly ISerializationManager _serialization = default!; // ADT-Changeling-Tweak private const string RevertPolymorphId = "ActionRevertPolymorph"; @@ -207,11 +214,16 @@ private void OnPolymorphedTerminating(Entity ent, re /// The new entity, or null if the polymorph failed. public EntityUid? PolymorphEntity(EntityUid uid, PolymorphConfiguration configuration) { - // If they're morphed, check their current config to see if they can be - // morphed again - if (!configuration.IgnoreAllowRepeatedMorphs - && TryComp(uid, out var currentPoly) - && !currentPoly.Configuration.AllowRepeatedMorphs) + //ADT-Geras-Tweak-Start + if (configuration.CanNotPolymorphInStorage && HasComp(uid)) + { + _popup.PopupEntity(Loc.GetString("polymorph-in-storage-forbidden"), uid, uid); + return null; + } + //ADT-Geras-Tweak-End + + // if it's already morphed, don't allow it again with this condition active. + if (!configuration.AllowRepeatedMorphs && HasComp(uid)) return null; // If this polymorph has a cooldown, check if that amount of time has passed since the @@ -393,6 +405,30 @@ private void OnPolymorphedTerminating(Entity ent, re } } } + + if (configuration.TransferFlame && TryComp(uid, out var parentFlame)) + { + var childFlame = EnsureComp(child); + _flammable.SetFireStacks(child, parentFlame.FireStacks, childFlame, parentFlame.OnFire); + } + + if (configuration.TransferStaminaDamage && TryComp(uid, out var parentStam)) + { + var childStam = EnsureComp(child); + var parentEffective = _stamina.GetStaminaDamage(uid, parentStam); + var fraction = parentEffective / parentStam.CritThreshold; + var childTarget = fraction * childStam.CritThreshold; + _stamina.TakeStaminaDamage(child, childTarget, childStam, visual: false, ignoreResist: true); + } + + if (configuration.TransferTemperature) + { + if (TryComp(uid, out var parentTemp)) + { + var childTemp = EnsureComp(child); + _temperatureSystem.ForceChangeTemperature(child, parentTemp.CurrentTemperature, childTemp); + } + } // ADT-Geras-Tweak-End if (configuration.TransferHumanoidAppearance) @@ -589,6 +625,34 @@ private void RetrievePausedEntity(EntityUid user, EntityUid target) if (TryComp(parent, out var polymorphableComponent)) polymorphableComponent.LastPolymorphEnd = _gameTiming.CurTime; + //ADT-Geras-Tweak-Start + if (component.Configuration.TransferFlame && TryComp(uid, out var childFlame)) + { + var parentFlame = EnsureComp(parent); + _flammable.SetFireStacks(parent, childFlame.FireStacks, parentFlame, childFlame.OnFire); + } + + if (component.Configuration.TransferStaminaDamage && TryComp(uid, out var childStam)) + { + var parentStam = EnsureComp(parent); + var childEffective = _stamina.GetStaminaDamage(uid, childStam); + var fraction = childEffective / childStam.CritThreshold; + var parentTarget = fraction * parentStam.CritThreshold; + var parentCurrent = _stamina.GetStaminaDamage(parent, parentStam); + var delta = parentTarget - parentCurrent; + _stamina.TakeStaminaDamage(parent, delta, parentStam, visual: false, ignoreResist: true); + } + + if (component.Configuration.TransferTemperature) + { + if (TryComp(uid, out var childTemp)) + { + var parentTemp = EnsureComp(parent); + _temperatureSystem.ForceChangeTemperature(parent, childTemp.CurrentTemperature, parentTemp); + } + } + //ADT-Geras-Tweak-End + // if an item polymorph was picked up, put it back down after reverting _transform.AttachToGridOrMap(parent, parentXform); diff --git a/Content.Shared/Polymorph/PolymorphPrototype.cs b/Content.Shared/Polymorph/PolymorphPrototype.cs index 0df0dff7f78..5b951b4d7c8 100644 --- a/Content.Shared/Polymorph/PolymorphPrototype.cs +++ b/Content.Shared/Polymorph/PolymorphPrototype.cs @@ -113,6 +113,24 @@ public sealed partial record PolymorphConfiguration [DataField(serverOnly: true)] public bool TransferQuirks; + /// + /// Whether or not the entity transfers its flame between forms. + /// + [DataField(serverOnly: true)] + public bool TransferFlame = true; + + /// + /// Whether or not the entity transfers its stamina damage between forms. + /// + [DataField(serverOnly: true)] + public bool TransferStaminaDamage = true; + + /// + /// Whether or not the entity transfers its temperature between forms. + /// + [DataField(serverOnly: true)] + public bool TransferTemperature = true; + /// /// Whether or not the entity can polymorph between forms in storage. /// diff --git a/Resources/Locale/ru-RU/ADT/geras/geras.ftl b/Resources/Locale/ru-RU/ADT/geras/geras.ftl index d5204a780d1..773a60efafd 100644 --- a/Resources/Locale/ru-RU/ADT/geras/geras.ftl +++ b/Resources/Locale/ru-RU/ADT/geras/geras.ftl @@ -1,3 +1,4 @@ -geras-popup-cant-use = Я не могу сконцентрироваться! -geras-popup-morph-message-user = Ты пытаешься изменить свою форму... +geras-popup-cant-use = Вы не можете сконцентрироваться! +geras-popup-cant-use-anomaly = Вы не можете сконцентрироваться из-за аномалии внутри вас! +geras-popup-morph-message-user = Вы пытаетесь изменить свою форму... geras-popup-morph-message-others = { $entity } начинает менять свою форму! diff --git a/Resources/Prototypes/ADT/Actions/types.yml b/Resources/Prototypes/ADT/Actions/types.yml index 0d7403fe652..e50a17f8fc1 100644 --- a/Resources/Prototypes/ADT/Actions/types.yml +++ b/Resources/Prototypes/ADT/Actions/types.yml @@ -46,7 +46,7 @@ components: - type: Action itemIconStyle: BigAction - useDelay: 60 # prevent spam + useDelay: 5 # prevent spam priority: -20 checkCanInteract: true icon: diff --git a/Resources/Prototypes/ADT/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/ADT/Entities/Mobs/NPCs/slimes.yml index ecb28e92c1c..b9649baf483 100644 --- a/Resources/Prototypes/ADT/Entities/Mobs/NPCs/slimes.yml +++ b/Resources/Prototypes/ADT/Entities/Mobs/NPCs/slimes.yml @@ -3,7 +3,8 @@ description: A slime. id: ADTMobSlimesGeras parent: - - BaseSimpleMob + - BaseMob + - MobDamageable - MobCombat - MobBloodstream - MobFlammable @@ -100,16 +101,12 @@ speedModifier: 1 useSound: path: /Audio/Items/crowbar.ogg - - type: Internals - type: Buckle - # - type: StandingState #зачем им ползать? хз они даже не готовы - type: ProjectileIgnoreCrawling - type: NpcFactionMember factions: - NanoTrasen - type: Climbing - - type: NameIdentifier - group: GenericNumber - type: SlowOnDamage speedModifierThresholds: 60: 0.7 @@ -174,3 +171,51 @@ - type: TimeDespawnDamage - type: Hands # They still don't have hands. - type: ComplexInteraction + - type: Temperature + heatDamageThreshold: 325 + coldDamageThreshold: 260 + currentTemperature: 310.15 + specificHeat: 42 + coldDamage: + types: + Cold: 0.1 + heatDamage: + types: + Heat: 1.5 + - type: TemperatureSpeed + thresholds: + 293: 0.9 + 260: 0.6 + 230: 0.4 + - type: ThermalRegulator + metabolismHeat: 800 + radiatedHeat: 100 + implicitHeatRegulation: 500 + sweatHeatRegulation: 2000 + shiveringHeatRegulation: 2000 + normalBodyTemperature: 310.15 + thermalRegulationTemperatureThreshold: 2 + - type: StunVisuals + - type: Reactive + groups: + Flammable: [ Touch ] + Extinguish: [ Touch ] + reactions: + - reagents: [ Water, SpaceCleaner ] + methods: [ Touch ] + effects: + - !type:WashCreamPie + - reagents: [ Water ] + methods: [ Touch ] + effects: + - !type:HealthChange + damage: + types: + Heat: 0.05 + - !type:PopupMessage + type: Local + visualType: Large + messages: [ "slime-hurt-by-water-popup" ] + probability: 0.25 + - type: PickupHumans + - type: Posing diff --git a/Resources/Prototypes/ADT/Polymorphs/polymorphs.yml b/Resources/Prototypes/ADT/Polymorphs/polymorphs.yml index b18b9dce768..008900479c4 100644 --- a/Resources/Prototypes/ADT/Polymorphs/polymorphs.yml +++ b/Resources/Prototypes/ADT/Polymorphs/polymorphs.yml @@ -554,3 +554,6 @@ transferDamage: true revertOnDeath: true revertOnCrit: true + transferFlame: true + transferStaminaDamage: true + transferTemperature: true diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index d9b0a76eb94..9dde59d1abe 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -146,6 +146,7 @@ tallscale: 1.05 short: true shortscale: 0.95 + - type: Geras #End ADT tweak - type: entity