diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index 561c5d7c6d..08dbfacbc2 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -2,15 +2,15 @@ using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Hands.Systems; +using Content.Server.Popups; using Content.Shared.Alert; using Content.Shared.Atmos; -using Content.Shared.Inventory; -using Robust.Shared.Containers; -using Robust.Shared.Prototypes; -using Content.Shared.Verbs; -using Content.Server.Popups; using Content.Shared.DoAfter; using Content.Shared.Internals; +using Content.Shared.Inventory; +using Content.Shared.Verbs; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Server.Body.Systems; @@ -64,7 +64,13 @@ public sealed class InternalsSystem : EntitySystem // Toggle off if they're on if (AreInternalsWorking(internals)) { - DisconnectTank(internals); + if (force || user == uid) + { + DisconnectTank(internals); + return; + } + + StartToggleInternalsDoAfter(user, uid, internals); return; } @@ -83,28 +89,31 @@ public sealed class InternalsSystem : EntitySystem return; } - var isUser = uid == user; - if (!force) { - // Is the target not you? If yes, use a do-after to give them time to respond. - //If no, do a short delay. There's no reason it should be beyond 1 second. - var delay = !isUser ? internals.Delay : 1.0f; - - _doAfter.TryStartDoAfter(new DoAfterArgs(user, delay, new InternalsDoAfterEvent(), uid, target: uid) - { - BreakOnUserMove = true, - BreakOnDamage = true, - BreakOnTargetMove = true, - MovementThreshold = 0.1f, - }); - + StartToggleInternalsDoAfter(user, uid, internals); return; } _gasTank.ConnectToInternals(tank); } + private void StartToggleInternalsDoAfter(EntityUid user, EntityUid target, InternalsComponent internals) + { + // Is the target not you? If yes, use a do-after to give them time to respond. + // If not, do a short delay. There's no reason it should be beyond 1 second. + var isUser = user == target; + var delay = !isUser ? internals.Delay : 1.0f; + + _doAfter.TryStartDoAfter(new DoAfterArgs(user, delay, new InternalsDoAfterEvent(), target, target: target) + { + BreakOnUserMove = true, + BreakOnDamage = true, + BreakOnTargetMove = true, + MovementThreshold = 0.1f, + }); + } + private void OnDoAfter(EntityUid uid, InternalsComponent component, InternalsDoAfterEvent args) { if (args.Cancelled || args.Handled) diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index d14a5bea00..d6a226ba95 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -773,9 +773,12 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id} await db.DbContext.SaveChangesAsync(); } - private static IQueryable GetAdminLogsQuery(ServerDbContext db, LogFilter? filter = null) + protected abstract IQueryable StartAdminLogsQuery(ServerDbContext db, LogFilter? filter = null); + + private IQueryable GetAdminLogsQuery(ServerDbContext db, LogFilter? filter = null) { - IQueryable query = db.AdminLog; + // Save me from SQLite + var query = StartAdminLogsQuery(db, filter); if (filter == null) { @@ -787,11 +790,6 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id} query = query.Where(log => log.RoundId == filter.Round); } - if (filter.Search != null) - { - query = query.Where(log => log.Message.Contains(filter.Search)); - } - if (filter.Types != null) { query = query.Where(log => filter.Types.Contains(log.Type)); diff --git a/Content.Server/Database/ServerDbPostgres.cs b/Content.Server/Database/ServerDbPostgres.cs index ffa810918f..40e9010cf7 100644 --- a/Content.Server/Database/ServerDbPostgres.cs +++ b/Content.Server/Database/ServerDbPostgres.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; +using Content.Server.Administration.Logs; using Content.Shared.CCVar; using Microsoft.EntityFrameworkCore; using Robust.Shared.Configuration; @@ -500,6 +501,21 @@ namespace Content.Server.Database return (admins.Select(p => (p.a, p.LastSeenUserName)).ToArray(), adminRanks)!; } + protected override IQueryable StartAdminLogsQuery(ServerDbContext db, LogFilter? filter = null) + { + // https://learn.microsoft.com/en-us/ef/core/querying/sql-queries#passing-parameters + // Read the link above for parameterization before changing this method or you get the bullet + if (!string.IsNullOrWhiteSpace(filter?.Search)) + { + return db.AdminLog.FromSql($""" +SELECT a.admin_log_id, a.round_id, a.date, a.impact, a.json, a.message, a.type FROM admin_log AS a +WHERE to_tsvector('english'::regconfig, a.message) @@ websearch_to_tsquery('english'::regconfig, {filter.Search}) +"""); + } + + return db.AdminLog; + } + private async Task GetDbImpl() { await _dbReadyTask; diff --git a/Content.Server/Database/ServerDbSqlite.cs b/Content.Server/Database/ServerDbSqlite.cs index e3a41f8416..35ee95f8d2 100644 --- a/Content.Server/Database/ServerDbSqlite.cs +++ b/Content.Server/Database/ServerDbSqlite.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; +using Content.Server.Administration.Logs; using Content.Server.IP; using Content.Server.Preferences.Managers; using Content.Shared.CCVar; @@ -478,6 +479,15 @@ namespace Content.Server.Database return round.Id; } + protected override IQueryable StartAdminLogsQuery(ServerDbContext db, LogFilter? filter = null) + { + IQueryable query = db.AdminLog; + if (filter?.Search != null) + query = query.Where(log => EF.Functions.Like(log.Message, $"%{filter.Search}%")); + + return query; + } + public override async Task AddAdminNote(AdminNote note) { await using (var db = await GetDb()) diff --git a/Content.Server/Gravity/GravityGeneratorComponent.cs b/Content.Server/Gravity/GravityGeneratorComponent.cs index 2ed325e52c..511fd49bdd 100644 --- a/Content.Server/Gravity/GravityGeneratorComponent.cs +++ b/Content.Server/Gravity/GravityGeneratorComponent.cs @@ -1,4 +1,6 @@ -using Content.Shared.Gravity; +using Content.Shared.Gravity; +using Content.Shared.Construction.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Gravity { @@ -29,9 +31,15 @@ namespace Content.Server.Gravity [DataField("intact")] public bool Intact { get; set; } = true; + [DataField("maxCharge")] + public float MaxCharge { get; set; } = 1; + // 0 -> 1 [ViewVariables(VVAccess.ReadWrite)] [DataField("charge")] public float Charge { get; set; } = 1; + [DataField("machinePartMaxChargeMultiplier", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartMaxChargeMultiplier = "Capacitor"; + /// /// Is the gravity generator currently "producing" gravity? /// diff --git a/Content.Server/Gravity/GravityGeneratorSystem.cs b/Content.Server/Gravity/GravityGeneratorSystem.cs index 930f2a8d4c..ad745ffa5d 100644 --- a/Content.Server/Gravity/GravityGeneratorSystem.cs +++ b/Content.Server/Gravity/GravityGeneratorSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Interaction; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Players; +using Content.Server.Construction; namespace Content.Server.Gravity { @@ -26,6 +27,7 @@ namespace Content.Server.Gravity SubscribeLocalEvent(OnComponentShutdown); SubscribeLocalEvent(OnParentChanged); // Or just anchor changed? SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnRefreshParts); SubscribeLocalEvent( OnSwitchGenerator); } @@ -84,11 +86,11 @@ namespace Content.Server.Gravity var active = gravGen.GravityActive; var lastCharge = gravGen.Charge; - gravGen.Charge = Math.Clamp(gravGen.Charge + frameTime * chargeRate, 0, 1); + gravGen.Charge = Math.Clamp(gravGen.Charge + frameTime * chargeRate, 0, gravGen.MaxCharge); if (chargeRate > 0) { // Charging. - if (MathHelper.CloseTo(gravGen.Charge, 1) && !gravGen.GravityActive) + if (MathHelper.CloseTo(gravGen.Charge, gravGen.MaxCharge) && !gravGen.GravityActive) { gravGen.GravityActive = true; } @@ -158,7 +160,7 @@ namespace Content.Server.Gravity if (!_uiSystem.IsUiOpen(component.Owner, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key)) return; - var chargeTarget = chargeRate < 0 ? 0 : 1; + var chargeTarget = chargeRate < 0 ? 0 : component.MaxCharge; short chargeEta; var atTarget = false; if (MathHelper.CloseTo(component.Charge, chargeTarget)) @@ -255,6 +257,12 @@ namespace Content.Server.Gravity } } + private void OnRefreshParts(EntityUid uid, GravityGeneratorComponent component, RefreshPartsEvent args) + { + var maxChargeMultipler = args.PartRatings[component.MachinePartMaxChargeMultiplier]; + component.MaxCharge = maxChargeMultipler * 1; + } + private void MakeBroken(EntityUid uid, GravityGeneratorComponent component, AppearanceComponent? appearance) { _ambientSoundSystem.SetAmbience(component.Owner, false); diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 930cc86668..f3416e7641 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,21 +1,4 @@ Entries: -- author: CrigCrag - changes: - - {message: 'Following a lawsuit, some unshielded asbestos was removed from the - atmos hardsuit helmet due to health concerns. They are now less heat resistant.', - type: Tweak} - - {message: 'Nanotrasen has released a new model of atmos firesuit. This model is - very resistant to heat, and has a bit more protection against high pressure. - However, it is not rated for low pressure environments and its helmet is notably - less sturdy.', type: Tweak} - id: 4095 - time: '2023-06-26T20:33:50.0000000+00:00' -- author: router - changes: - - {message: 'Added an alternative emotes prefix, *. Note that it doesn''t get treated - any differently than the normal @ prefix.', type: Add} - id: 4096 - time: '2023-06-26T21:20:09.0000000+00:00' - author: Chief-Engineer changes: - {message: Nanotrasen has invested in higher quality grilles., type: Tweak} @@ -3025,3 +3008,19 @@ Entries: acid, heat it up to 374k and receive your homemade plastic sheet.', type: Add} id: 4594 time: '2023-08-14T23:40:48.0000000+00:00' +- author: Just_Art + changes: + - {message: Now a mini gravity generator can be constructed using a machine board + and deconstructed., type: Add} + - {message: 'The mini gravity generator can be improved by replacing capacitors, + which will increase the maximum charge of the generator.', type: Add} + - {message: 'The amount of damage required to destroy the mini gravity generator + has been changed, and now it is completely destroyed, but it can still be restored + by welding.', type: Tweak} + id: 4595 + time: '2023-08-15T00:23:40.0000000+00:00' +- author: DrSmugleaf + changes: + - {message: There is now a delay when disconnecting someone else's internals., type: Tweak} + id: 4596 + time: '2023-08-15T00:25:58.0000000+00:00' diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index 5f4fced02f..defb13df04 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -941,3 +941,19 @@ Steel: 5 CableHV: 5 Cable: 2 + +- type: entity + parent: BaseMachineCircuitboard + id: MiniGravityGeneratorCircuitboard + name: mini gravity generator machine board + description: A machine printed circuit board for a mini gravity generator. + components: + - type: MachineBoard + prototype: GravityGeneratorMini + requirements: + Capacitor: 4 + MatterBin: 3 + materialRequirements: + Steel: 5 + CableHV: 5 + Uranium: 2 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index e263f63ad7..011db23bc8 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -476,7 +476,7 @@ clothingVisuals: head: - state: equipped-HELMET - offset: "0, 0.15" + offset: "0, 0.15625" - type: entity parent: BaseItem diff --git a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml index 9d1bf03efc..2658f68dfe 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml @@ -12,7 +12,6 @@ range: 7 sound: path: /Audio/Ambience/Objects/gravity_gen_hum.ogg - - type: Sprite sprite: Structures/Machines/gravity_generator.rsi layers: @@ -77,7 +76,7 @@ - type: entity id: GravityGeneratorMini - parent: GravityGenerator + parent: [ GravityGenerator, ConstructibleMachine ] name: mini gravity generator description: It's what keeps you to the floor, now in fun size. components: @@ -104,6 +103,28 @@ - LargeMobMask layer: - WallLayer + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 500 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + MachineFrameDestroyed: + min: 1 + max: 1 + - type: WiresPanel + - type: Wires + BoardName: "MiniGravityGenerator" + LayoutId: MiniGravityGenerator + - type: Machine + board: MiniGravityGeneratorCircuitboard - type: ApcPowerReceiver powerLoad: 500 - type: GravityGenerator diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 77e9c7edc4..0e73490cfa 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -347,6 +347,7 @@ - EmitterCircuitboard - ThrusterMachineCircuitboard - GyroscopeMachineCircuitboard + - MiniGravityGeneratorCircuitboard - GasRecyclerMachineCircuitboard - SeedExtractorMachineCircuitboard - AnalysisComputerCircuitboard diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index 8a5a5a2996..e9dcd8f181 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -661,3 +661,12 @@ materials: Steel: 100 Glass: 900 + +- type: latheRecipe + id: MiniGravityGeneratorCircuitboard + result: MiniGravityGeneratorCircuitboard + completetime: 6 + materials: + Steel: 100 + Glass: 900 + Gold: 100 diff --git a/Resources/Prototypes/Research/industrial.yml b/Resources/Prototypes/Research/industrial.yml index c262b067b6..5ea36788ec 100644 --- a/Resources/Prototypes/Research/industrial.yml +++ b/Resources/Prototypes/Research/industrial.yml @@ -129,6 +129,7 @@ - RadarConsoleCircuitboard - ThrusterMachineCircuitboard - GyroscopeMachineCircuitboard + - MiniGravityGeneratorCircuitboard - type: technology id: RipleyAPLU