diff --git a/Content.Server/Interaction/InteractionPopupSystem.cs b/Content.Server/Interaction/InteractionPopupSystem.cs index 1115f2c0d8..0d21d92a2d 100644 --- a/Content.Server/Interaction/InteractionPopupSystem.cs +++ b/Content.Server/Interaction/InteractionPopupSystem.cs @@ -91,6 +91,7 @@ public sealed class InteractionPopupSystem : EntitySystem { var ev = new MoodEffectEvent("PetAnimal"); RaiseLocalEvent(user, ev); + RaiseLocalEvent(uid, new MoodEffectEvent("BeingPet")); } //WD end } diff --git a/Content.Server/_White/Construction/DoorUnlocked.cs b/Content.Server/_White/Construction/DoorUnlocked.cs new file mode 100644 index 0000000000..6016a82959 --- /dev/null +++ b/Content.Server/_White/Construction/DoorUnlocked.cs @@ -0,0 +1,33 @@ +using Content.Shared._White.Keyhole.Components; +using Content.Shared.Construction; +using Content.Shared.Examine; +using JetBrains.Annotations; + +namespace Content.Server._White.Construction; + +[UsedImplicitly, DataDefinition] +public sealed partial class DoorUnlocked : IGraphCondition +{ + public bool Condition(EntityUid uid, IEntityManager entityManager) + { + return !entityManager.TryGetComponent(uid, out KeyholeComponent? keyhole) || !keyhole.Locked; + } + + public bool DoExamine(ExaminedEvent args) + { + if (Condition(args.Examined, IoCManager.Resolve())) + return false; + + args.PushMarkup(Loc.GetString("construction-examine-condition-door-locked")); + return true; + + } + + public IEnumerable GenerateGuideEntry() + { + yield return new ConstructionGuideEntry + { + Localization = "construction-examine-condition-door-locked" + }; + } +} diff --git a/Content.Server/_White/Keyhole/KeyholeSystem.cs b/Content.Server/_White/Keyhole/KeyholeSystem.cs index 8a6c92f0cb..1a5d09ad1c 100644 --- a/Content.Server/_White/Keyhole/KeyholeSystem.cs +++ b/Content.Server/_White/Keyhole/KeyholeSystem.cs @@ -1,4 +1,6 @@ -using Content.Shared._White.Keyhole.Components; +using System.Diagnostics; +using Content.Server._White.Cult.Structures; +using Content.Shared._White.Keyhole.Components; using Content.Shared._White.Keyhole; using Content.Shared.DoAfter; using Content.Shared.Doors.Components; @@ -10,10 +12,7 @@ using Robust.Shared.Random; namespace Content.Server._White.Keyhole; -// TODO: Исправить, что дверь на замке можно разобрать через ее id: DoorGraph -// TODO: Исправить, что при прерывании закрытия девственной двери форма замка принимает форму ключа, хотя закрытия не произошло - -public sealed partial class KeyholeSystem : EntitySystem +public sealed class KeyholeSystem : EntitySystem { [Dependency] private readonly IRobustRandom _random = default!; @@ -37,52 +36,55 @@ public sealed partial class KeyholeSystem : EntitySystem private void OnKeyInsert(EntityUid uid, KeyComponent component, AfterInteractEvent ev) { + Debug.Assert(component.FormId != null); + if (TryComp(ev.Target, out var keyformComponent)) - OnKeyInsertForm(uid, component, keyformComponent, ev); + { + OnKeyInsertForm(uid, component, keyformComponent, ev.Target.Value, ev.User); + return; + } - if (!TryComp(ev.Target, out var keyholeComponent)) + if (!TryComp(ev.Target, out var keyholeComponent) || !CanLock(ev.Target.Value)) return; - keyholeComponent.FormId ??= component.FormId; - - if (!CanLock(keyholeComponent.Owner, keyholeComponent, component)) + if (keyholeComponent.FormId != null && keyholeComponent.FormId != component.FormId) + { + _popupSystem.PopupEntity(Loc.GetString("door-keyhole-different-form"), ev.Target.Value); return; + } var doAfterEventArgs = - new DoAfterArgs(EntityManager, ev.User, keyholeComponent.Delay, new KeyInsertDoAfterEvent(), ev.Target, ev.Used) - { - BreakOnTargetMove = true, - BreakOnUserMove = true, - BreakOnDamage = true - }; + new DoAfterArgs(EntityManager, ev.User, keyholeComponent.Delay, + new KeyInsertDoAfterEvent(component.FormId.Value), ev.Target, ev.Used) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnDamage = true + }; + _doAfter.TryStartDoAfter(doAfterEventArgs); } - private bool CanLock(EntityUid uid, KeyholeComponent keyholeComponent, KeyComponent keyComponent) + private bool CanLock(EntityUid uid) { - var can = TryComp(uid, out var doorComponent) && - keyholeComponent.FormId == keyComponent.FormId && - doorComponent.State == DoorState.Closed; - - return can; + return !HasComp(uid) && TryComp(uid, out var doorComponent) && + doorComponent.State == DoorState.Closed; } private void OnDoAfter(EntityUid uid, KeyholeComponent component, KeyInsertDoAfterEvent args) { - if (args.Handled || args.Cancelled || IsStateChanging(uid)) + if (args.Handled || args.Cancelled || !CanLock(uid)) return; + Debug.Assert(component.FormId == null || component.FormId == args.FormId); + + component.FormId = args.FormId; + Lock(uid, component, args.User); args.Handled = true; } - private bool IsStateChanging(EntityUid uid) - { - return TryComp(uid, out var doorComponent) && - (doorComponent.State == DoorState.Closing || doorComponent.State == DoorState.Opening); - } - private void Lock(EntityUid uid, KeyholeComponent component, EntityUid user) { var sound = component.Locked ? component.UnlockSound : component.LockSound; @@ -96,22 +98,22 @@ public sealed partial class KeyholeSystem : EntitySystem component.Locked = !component.Locked; } - private void OnKeyInsertForm(EntityUid uid, KeyComponent keyComponent, KeyformComponent keyformComponent, AfterInteractEvent args) + private void OnKeyInsertForm(EntityUid uid, KeyComponent keyComponent, KeyformComponent keyformComponent, EntityUid keyform, EntityUid user) { if (!keyformComponent.IsUsed) { keyformComponent.FormId ??= keyComponent.FormId; - _appearance.SetData(keyformComponent.Owner, KeyformVisuals.IsUsed, true); + _appearance.SetData(keyform, KeyformVisuals.IsUsed, true); _audio.PlayPvs(keyformComponent.PressSound, uid); - _popupSystem.PopupEntity(Loc.GetString("key-pressed-in-keyform-message-first", ("user", args.User), ("key", uid)), uid); + _popupSystem.PopupEntity(Loc.GetString("key-pressed-in-keyform-message-first", ("user", user), ("key", uid)), uid); keyformComponent.IsUsed = true; } else { keyComponent.FormId = keyformComponent.FormId; - _popupSystem.PopupEntity(Loc.GetString("key-pressed-in-keyform-message", ("user", args.User), ("key", uid)), uid); + _popupSystem.PopupEntity(Loc.GetString("key-pressed-in-keyform-message", ("user", user), ("key", uid)), uid); } } diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs index 5199133253..576fea8943 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs @@ -15,7 +15,6 @@ using Content.Shared.Speech; using Content.Shared.Standing; using Content.Shared.Strip.Components; using Content.Shared.Throwing; -using Robust.Shared.Physics.Components; namespace Content.Shared.Mobs.Systems; @@ -56,12 +55,7 @@ public partial class MobStateSystem _standing.Stand(target); break; case MobState.Dead: - RemComp(target); _standing.Stand(target); - if (!_standing.IsDown(target) && TryComp(target, out var physics)) - { - _physics.SetCanCollide(target, true, body: physics); - } break; case MobState.Invalid: @@ -91,14 +85,8 @@ public partial class MobStateSystem _appearance.SetData(target, MobStateVisuals.State, MobState.Critical); break; case MobState.Dead: - EnsureComp(target); _standing.Down(target); - if (_standing.IsDown(target) && TryComp(target, out var physics)) - { - _physics.SetCanCollide(target, false, body: physics); - } - _appearance.SetData(target, MobStateVisuals.State, MobState.Dead); break; case MobState.Invalid: diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index d331f00e78..bd93142433 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -190,6 +190,10 @@ public abstract partial class SharedProjectileSystem : EntitySystem private void PreventCollision(EntityUid uid, ProjectileComponent component, ref PreventCollideEvent args) { + // Shoot yourself! + if (args.OtherEntity == component.Target) // WD + return; + if (component.IgnoreShooter && (args.OtherEntity == component.Shooter || args.OtherEntity == component.Weapon)) { args.Cancelled = true; @@ -356,4 +360,4 @@ public record struct ProjectileHitEvent(DamageSpecifier Damage, EntityUid Target /// Raised after a projectile has dealt it's damage. /// [ByRefEvent] -public record struct AfterProjectileHitEvent(DamageSpecifier Damage, EntityUid Target, Fixture Fixture); \ No newline at end of file +public record struct AfterProjectileHitEvent(DamageSpecifier Damage, EntityUid Target, Fixture Fixture); diff --git a/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs b/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs index 308be30e70..35be109b81 100644 --- a/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs +++ b/Content.Shared/_White/Cult/Systems/BloodSpearSystem.cs @@ -1,5 +1,6 @@ using Content.Shared._White.Cult.Components; using Content.Shared.Actions; +using Content.Shared.Examine; using Content.Shared.Hands; using Content.Shared.StatusEffect; using Content.Shared.Stunnable; @@ -23,6 +24,12 @@ public sealed class BloodSpearSystem : EntitySystem SubscribeLocalEvent(OnRemove); SubscribeLocalEvent(OnEquip); SubscribeLocalEvent(OnThrowDoHit); + SubscribeLocalEvent(OnExamine); + } + + private void OnExamine(Entity ent, ref ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("blood-spear-component-extra-desc")); } private void OnThrowDoHit(Entity ent, ref ThrowDoHitEvent args) diff --git a/Content.Shared/_White/Cult/Systems/BoltBarrageSystem.cs b/Content.Shared/_White/Cult/Systems/BoltBarrageSystem.cs index e2fb4947a3..696605f99a 100644 --- a/Content.Shared/_White/Cult/Systems/BoltBarrageSystem.cs +++ b/Content.Shared/_White/Cult/Systems/BoltBarrageSystem.cs @@ -1,5 +1,6 @@ using System.Linq; using Content.Shared._White.Cult.Components; +using Content.Shared.Examine; using Content.Shared.Ghost; using Content.Shared.Hands; using Content.Shared.Hands.Components; @@ -29,6 +30,12 @@ public sealed class BoltBarrageSystem : EntitySystem SubscribeLocalEvent(OnUnequipHand); SubscribeLocalEvent(OnRemoveAttempt); SubscribeLocalEvent(OnEmptyShot); + SubscribeLocalEvent(OnExamine); + } + + private void OnExamine(Entity ent, ref ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("bolt-barrage-component-extra-desc")); } private void OnUnequipHand(Entity ent, ref UnequippedHandEvent args) @@ -51,7 +58,7 @@ public sealed class BoltBarrageSystem : EntitySystem private void OnDrop(Entity ent, ref DroppedEvent args) { - if (_net.IsServer) + if (_net.IsServer && ent.Comp.Unremoveable) QueueDel(ent); } diff --git a/Content.Shared/_White/Keyhole/Components/KeyBaseComponent.cs b/Content.Shared/_White/Keyhole/Components/KeyBaseComponent.cs index 8a6b818cab..861e1315cf 100644 --- a/Content.Shared/_White/Keyhole/Components/KeyBaseComponent.cs +++ b/Content.Shared/_White/Keyhole/Components/KeyBaseComponent.cs @@ -1,6 +1,6 @@ namespace Content.Shared._White.Keyhole.Components; -[RegisterComponent] +[RegisterComponent, Virtual] public partial class KeyBaseComponent : Component { [ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Shared/_White/Keyhole/KeyInsertEvent.cs b/Content.Shared/_White/Keyhole/KeyInsertEvent.cs index 48a6f2c049..cb7bb684fb 100644 --- a/Content.Shared/_White/Keyhole/KeyInsertEvent.cs +++ b/Content.Shared/_White/Keyhole/KeyInsertEvent.cs @@ -4,5 +4,13 @@ using Robust.Shared.Serialization; namespace Content.Shared._White.Keyhole; [Serializable, NetSerializable] -public sealed partial class KeyInsertDoAfterEvent : SimpleDoAfterEvent {} +public sealed partial class KeyInsertDoAfterEvent : SimpleDoAfterEvent +{ + public int FormId; + + public KeyInsertDoAfterEvent(int formId) + { + FormId = formId; + } +} diff --git a/Resources/Locale/ru-RU/cult/blood-spear.ftl b/Resources/Locale/ru-RU/cult/blood-spear.ftl new file mode 100644 index 0000000000..85e9bee270 --- /dev/null +++ b/Resources/Locale/ru-RU/cult/blood-spear.ftl @@ -0,0 +1 @@ +blood-spear-component-extra-desc = [color=darkgray]Кровавое копьё можно бросить, что заставит его разбиться и оглушить любого, кого оно поразит.[/color] diff --git a/Resources/Locale/ru-RU/cult/bolt-barrage.ftl b/Resources/Locale/ru-RU/cult/bolt-barrage.ftl index b6e870093d..0aa68a47a8 100644 --- a/Resources/Locale/ru-RU/cult/bolt-barrage.ftl +++ b/Resources/Locale/ru-RU/cult/bolt-barrage.ftl @@ -1,2 +1,3 @@ bolt-barrage-component-no-empty-hand = Вам нужно иметь свободную руку, чтобы стрелять. bolt-barrage-component-not-cultist = Вы не умеете пользоваться магией. +bolt-barrage-component-extra-desc = [color=darkgray]Для стрельбы залпом необходимо иметь свободную руку. Вобросите залп, чтобы навсегда избавиться от него.[/color] diff --git a/Resources/Locale/ru-RU/mind/components/mind-component.ftl b/Resources/Locale/ru-RU/mind/components/mind-component.ftl index fda48cb119..41a5de8e61 100644 --- a/Resources/Locale/ru-RU/mind/components/mind-component.ftl +++ b/Resources/Locale/ru-RU/mind/components/mind-component.ftl @@ -7,7 +7,10 @@ comp-mind-ghosting-prevented = Вы не можете стать призрак comp-mind-examined-catatonic = { CAPITALIZE(SUBJECT($ent)) } в кататоническом ступоре. Стрессы жизни в глубоком космосе, должно быть, оказались слишком тяжелы для { OBJECT($ent) }. Восстановление маловероятно. comp-mind-examined-dead = { CAPITALIZE(POSS-PRONOUN($ent)) } душа покинула тело. comp-mind-examined-ssd = { CAPITALIZE(SUBJECT($ent)) } рассеяно смотрит в пустоту и ни на что не реагирует. { CAPITALIZE(SUBJECT($ent)) } может скоро придти в себя. -comp-mind-examined-dead-and-ssd = Душа { CAPITALIZE(POSS-ADJ($ent)) } ушла и улетела. Любое восстановление маловероятно. +comp-mind-examined-dead-and-ssd = { CAPITALIZE(POSS-ADJ($ent)) } душа дремлет и может скоро вернуться. +comp-mind-examined-dead-and-irrecoverable = { CAPITALIZE(POSS-ADJ($ent)) } душа покинула тело и пропала. Восстановление маловероятно. + mind-component-no-mind-and-alive-text = { CAPITALIZE(SUBJECT($ent)) } в кататоническом ступоре. Стрессы жизни в глубоком космосе, должно быть, оказались слишком тяжелы для него. Восстановление маловероятно. mind-component-no-mind-and-dead-text = { CAPITALIZE(POSS-PRONOUN($ent)) } душа покинула тело и пропала. Восстановление маловероятно. mind-component-mind-and-no-session-text = { CAPITALIZE(SUBJECT($ent)) } рассеяно смотрит в пустоту и ни на что не реагирует. { CAPITALIZE(SUBJECT($ent)) } может скоро придти в себя. + diff --git a/Resources/Locale/ru-RU/white/object/tools/keyhole.ftl b/Resources/Locale/ru-RU/white/object/tools/keyhole.ftl index 788328b305..3966ca0bcc 100644 --- a/Resources/Locale/ru-RU/white/object/tools/keyhole.ftl +++ b/Resources/Locale/ru-RU/white/object/tools/keyhole.ftl @@ -1 +1,3 @@ -door-locked-via-key = {$door} закрыта +door-locked-via-key = {$door} закрыта +door-keyhole-different-form = Форма замка этой двери не совпадает с формой ключа. +construction-examine-condition-door-locked = Дверь не должна быть закрыта на ключ. diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 4f45453c3c..fcadccdc1a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -61,6 +61,11 @@ - type: Tag tags: - VimPilot + - type: MobThresholds + thresholds: + 0: Alive + 20: Critical + 30: Dead - type: entity name: bee @@ -466,8 +471,8 @@ - type: MobThresholds thresholds: 0: Alive - 40: Critical - 60: Dead + 20: Critical + 30: Dead - type: MovementSpeedModifier baseWalkSpeed : 2.5 baseSprintSpeed : 4 @@ -2965,8 +2970,8 @@ - type: MobThresholds thresholds: 0: Alive - 40: Critical - 60: Dead + 20: Critical + 30: Dead - type: MovementSpeedModifier baseWalkSpeed : 4 baseSprintSpeed : 4 diff --git a/Resources/Prototypes/Entities/Objects/Materials/materials.yml b/Resources/Prototypes/Entities/Objects/Materials/materials.yml index 2de5716f4f..2e476346ab 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/materials.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/materials.yml @@ -8,7 +8,7 @@ sprite: Objects/Materials/materials.rsi - type: Item sprite: Objects/Materials/materials.rsi - size: Normal + size: Small - type: Tag tags: - DroneUsable diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml index 29ee0d6fe1..2656e80943 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml @@ -77,6 +77,12 @@ acts: [ "Destruction" ] - type: Label originalName: jug + - type: MeleeWeapon + soundNoDamage: + path: "/Audio/Effects/Fluids/splat.ogg" + damage: + types: + Blunt: 0 - type: entity parent: Jug diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/doors.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/doors.yml index e15f4a644a..6c58f840da 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/doors.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/doors.yml @@ -11,35 +11,35 @@ - !type:SnapToGrid { } steps: - material: Steel - amount: 20 + amount: 5 doAfter: 15 - to: woodDoor completed: - !type:SnapToGrid { } steps: - material: WoodPlank - amount: 20 + amount: 5 doAfter: 15 - to: plasmaDoor completed: - !type:SnapToGrid { } steps: - material: Plasma - amount: 20 + amount: 5 doAfter: 15 - to: goldDoor completed: - !type:SnapToGrid { } steps: - material: Gold - amount: 20 + amount: 5 doAfter: 15 - to: silverDoor completed: - !type:SnapToGrid { } steps: - material: Silver - amount: 20 + amount: 5 doAfter: 15 - to: bananiumDoor completed: @@ -53,7 +53,7 @@ - !type:SnapToGrid { } steps: - material: Paper - amount: 20 + amount: 5 doAfter: 15 - node: metalDoor entity: MetalDoor @@ -62,7 +62,9 @@ completed: - !type:SpawnPrototype prototype: SheetSteel1 - amount: 20 + amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 @@ -73,7 +75,9 @@ completed: - !type:SpawnPrototype prototype: MaterialWoodPlank1 - amount: 20 + amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 @@ -84,7 +88,9 @@ completed: - !type:SpawnPrototype prototype: SheetPlasma - amount: 20 + amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 @@ -95,7 +101,9 @@ completed: - !type:SpawnPrototype prototype: IngotGold1 - amount: 20 + amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 @@ -106,7 +114,9 @@ completed: - !type:SpawnPrototype prototype: IngotSilver1 - amount: 20 + amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 @@ -117,7 +127,9 @@ completed: - !type:SpawnPrototype prototype: SheetPaper1 - amount: 20 + amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 @@ -129,6 +141,8 @@ - !type:SpawnPrototype prototype: MaterialBananium1 amount: 5 + conditions: + - !type:DoorUnlocked steps: - tool: Anchoring doAfter: 15 diff --git a/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml b/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml index 3816ff0208..3397ed86dc 100644 --- a/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml +++ b/Resources/Prototypes/_White/Entities/Cult/Items/tome_craft.yml @@ -172,7 +172,7 @@ - key: enum.CultStructureCraftUiKey.Key type: StructureCraftBoundUserInterface - type: Item - size: Normal + size: Small - type: CultItem - type: entity diff --git a/Resources/Prototypes/_White/Mood/generic_positveEffects.yml b/Resources/Prototypes/_White/Mood/generic_positveEffects.yml index 539b9a2a68..856879bdc2 100644 --- a/Resources/Prototypes/_White/Mood/generic_positveEffects.yml +++ b/Resources/Prototypes/_White/Mood/generic_positveEffects.yml @@ -1,10 +1,17 @@ -- type: moodEffect +- type: moodEffect id: BeingHugged desc: "Обнимашки - круто." moodChange: enum.MoodChangeLevel.Small positiveEffect: true timeout: 2 +- type: moodEffect + id: BeingPet + desc: "Меня погладили!" + moodChange: enum.MoodChangeLevel.Small + positiveEffect: true + timeout: 2 + - type: moodEffect id: ArcadePlay desc: "Я весело поиграл в интересную аркаду."