diff --git a/Content.IntegrationTests/Tests/Materials/ReclaimerLoopTest.cs b/Content.IntegrationTests/Tests/Materials/ReclaimerLoopTest.cs index 310401ed59..94ab23df03 100644 --- a/Content.IntegrationTests/Tests/Materials/ReclaimerLoopTest.cs +++ b/Content.IntegrationTests/Tests/Materials/ReclaimerLoopTest.cs @@ -37,6 +37,9 @@ public sealed class ReclaimerLoopTest : InteractionTest var reclaimComp = Comp(Target); + // Put a floor tile down + await InteractUsing(FloorTileId); + // Power the reclaimer await SpawnEntity(ApcId, SEntMan.GetCoordinates(TargetCoords)); await RunTicks(1); @@ -49,9 +52,6 @@ public sealed class ReclaimerLoopTest : InteractionTest // Check that reclaimer enabled Assume.That(reclaimComp.Enabled, "The reclaimer did not get or stay enabled"); - // Put a floor tile down - await InteractUsing(FloorTileId); - // Reclaimer can't reclaim materials? Job's done. if (!reclaimComp.ReclaimMaterials) Assert.Ignore("Cannot reclaim materials"); diff --git a/Content.Server/Materials/MaterialReclaimerSystem.cs b/Content.Server/Materials/MaterialReclaimerSystem.cs index 1a57f539cc..81e8f9de73 100644 --- a/Content.Server/Materials/MaterialReclaimerSystem.cs +++ b/Content.Server/Materials/MaterialReclaimerSystem.cs @@ -210,19 +210,7 @@ public sealed partial class MaterialReclaimerSystem : SharedMaterialReclaimerSys _materialStorage.TryChangeMaterialAmount(reclaimer, material, outputAmount, storage); } - foreach (var (storedMaterial, storedAmount) in storage.Storage) - { - var stacks = _materialStorage.SpawnMultipleFromMaterial(storedAmount, - storedMaterial, - xform.Coordinates, - out var materialOverflow); - var amountConsumed = storedAmount - materialOverflow; - _materialStorage.TryChangeMaterialAmount(reclaimer, storedMaterial, -amountConsumed, storage); - foreach (var stack in stacks) - { - _stack.TryMergeToContacts(stack); - } - } + _materialStorage.EjectAllMaterial(reclaimer, xform.Coordinates, storage, true); } private void SpawnChemicalsFromComposition(EntityUid reclaimer, diff --git a/Content.Server/Materials/MaterialStorageSystem.cs b/Content.Server/Materials/MaterialStorageSystem.cs index 86df5a6e28..1465784bbf 100644 --- a/Content.Server/Materials/MaterialStorageSystem.cs +++ b/Content.Server/Materials/MaterialStorageSystem.cs @@ -224,11 +224,13 @@ public sealed partial class MaterialStorageSystem : SharedMaterialStorageSystem /// The entity with storage to eject from. /// The position where to spawn the created sheets. If not given, they're spawned next to the entity. /// The storage component on . Resolved automatically if not given. + /// If true, spawned stacks will attempt to merge with existing stacks in the area. /// The stack entities that were spawned. public List EjectAllMaterial( EntityUid entity, EntityCoordinates? coordinates = null, - MaterialStorageComponent? component = null) + MaterialStorageComponent? component = null, + bool mergeContacts = false) { if (!Resolve(entity, ref component)) return new List(); @@ -242,6 +244,14 @@ public sealed partial class MaterialStorageSystem : SharedMaterialStorageSystem allSpawned.AddRange(spawned); } + if (mergeContacts) + { + foreach (var stack in allSpawned) + { + _stackSystem.TryMergeToContacts(stack); + } + } + return allSpawned; } } diff --git a/Content.Server/Materials/ServerTileReclaimerSystem.cs b/Content.Server/Materials/ServerTileReclaimerSystem.cs new file mode 100644 index 0000000000..0b975ece79 --- /dev/null +++ b/Content.Server/Materials/ServerTileReclaimerSystem.cs @@ -0,0 +1,26 @@ +using Content.Shared.Materials; +using Content.Shared.Maps; + +namespace Content.Server.Materials; + +/// +public sealed partial class ServerTileReclaimerSystem : TileReclaimerSystem +{ + [Dependency] private MaterialStorageSystem _materialStorage = default!; + + protected override void SpawnMaterialsFromComposition(Entity ent, + ContentTileDefinition tileDefinition, + float efficiency) + { + if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2)) + return; + + foreach (var (material, amount) in tileDefinition.MaterialComposition) + { + var outputAmount = (int) (amount * efficiency); + _materialStorage.TryChangeMaterialAmount(ent, material, outputAmount, ent.Comp1); + } + + _materialStorage.EjectAllMaterial(ent, ent.Comp2.Coordinates, ent.Comp1, true); + } +} diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index 72c2f33588..cdfc5cf5b4 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -1,4 +1,5 @@ using Content.Shared.Atmos; +using Content.Shared.Materials; using Content.Shared.Movement.Systems; using Content.Shared.Shuttles.Systems; using Content.Shared.Tools; @@ -132,6 +133,12 @@ public sealed partial class ContentTileDefinition : IPrototype, IInheritingProto /// [DataField] public bool EditorHidden { get; private set; } = false; + /// + /// If this tile is reclaimed, what materials would come out of it? + /// + [DataField] + public Dictionary, int> MaterialComposition = new(); + public void AssignTileId(ushort id) { TileId = id; diff --git a/Content.Shared/Materials/TileReclaimerComponent.cs b/Content.Shared/Materials/TileReclaimerComponent.cs new file mode 100644 index 0000000000..aee15adeba --- /dev/null +++ b/Content.Shared/Materials/TileReclaimerComponent.cs @@ -0,0 +1,77 @@ +using Content.Shared.Maps; +using Content.Shared.Whitelist; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Materials; + +/// +/// Makes an entity into a grid reclaimer, able to delete grids in front of it and produce materials. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause] +[Access(typeof(TileReclaimerSystem))] +public sealed partial class TileReclaimerComponent : Component +{ + /// + /// An "enable" toggle for things like interfacing with machine linking. + /// + [DataField, AutoNetworkedField] + public bool Enabled = true; + + /// + /// A master control for whether or not the reclaimer is broken and can function. + /// + [DataField, AutoNetworkedField] + public bool Broken; + + /// + /// A whitelist for what grid entities can be affected by this reclaimer. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? Whitelist; + + /// + /// A whitelist for what grid entities can be affected by this reclaimer. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? Blacklist; + + /// + /// The delay after a grid has been consumed that it can recycle again. + /// + [DataField, AutoNetworkedField] + public TimeSpan RecycleDelay = TimeSpan.FromSeconds(0.3f); + + /// + /// The bounding box in local coordinates for where it will check for grids to reclaim. + /// + [DataField, AutoNetworkedField] + public Box2 RecyclingBox = new(-0.5f, 0.5f, 0.5f, 1.5f); + + /// + /// Multiplier for the material being extracted from the tile, as defined in the tile's + /// + [DataField, AutoNetworkedField] + public float Efficiency = 1f; + + /// + /// How strong impulse the reclaimer should apply to a grid after it has destroyed one of it tiles. + /// This helps guide the grid further into the reclaimer. + /// + [DataField, AutoNetworkedField] + public float SlurpStrength = 1600f; + + /// + /// Next time a recycling attempt can be made. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadOnly)] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextRecycle; + + /// + /// The sound played when something is being processed. + /// + [DataField, AutoNetworkedField] + public SoundSpecifier? Sound; +} diff --git a/Content.Shared/Materials/TileReclaimerSystem.cs b/Content.Shared/Materials/TileReclaimerSystem.cs new file mode 100644 index 0000000000..556add2666 --- /dev/null +++ b/Content.Shared/Materials/TileReclaimerSystem.cs @@ -0,0 +1,141 @@ +using Content.Shared.Conveyor; +using Content.Shared.Maps; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Timing; + +namespace Content.Shared.Materials; + +/// +/// Handles interactions and logic related to . +/// +public abstract partial class TileReclaimerSystem : EntitySystem +{ + [Dependency] private SharedAudioSystem _audio = default!; + [Dependency] private SharedTransformSystem _transform = default!; + [Dependency] private IGameTiming _timing = default!; + [Dependency] private SharedMapSystem _mapSystem = default!; + [Dependency] private SharedPhysicsSystem _physics = default!; + [Dependency] private EntityLookupSystem _lookup = default!; + [Dependency] private TurfSystem _turf = default!; + [Dependency] private EntityWhitelistSystem _whitelist = default!; + + [Dependency] private EntityQuery _physicsComponentQuery = default!; + + [SubscribeLocalEvent] + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextRecycle = _timing.CurTime + ent.Comp.RecycleDelay; + DirtyField(ent.Owner, ent.Comp, nameof(TileReclaimerComponent.NextRecycle)); + } + + public override void Update(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var tileReclaimer, out var xform)) + { + if (tileReclaimer.NextRecycle > _timing.CurTime) + return; + + Update((uid, tileReclaimer, xform)); + } + } + + private void Update(Entity ent) + { + ent.Comp1.NextRecycle += ent.Comp1.RecycleDelay; + DirtyField(ent.Owner, ent.Comp1, nameof(TileReclaimerComponent.NextRecycle)); + + //TODO: The recycler is hardcoded to rely on the conveyor component for its powered state, and this system is based on the same functionality. That should be fixed into a more general solution for both systems, but for the sake of consistency I'm not doing that now. + if (!TryComp(ent, out var conveyor) || conveyor.State == ConveyorState.Off) + return; + + var reclaimerGrid = _transform.GetGrid((ent, ent)); + + if (reclaimerGrid == null) + return; + + var mapPos = _transform.GetMapCoordinates(ent); + + var grids = new List>(); + + var entMatrix = _transform.GetWorldMatrix(ent.Owner); + var box = entMatrix.TransformBox(ent.Comp1.RecyclingBox); + + _mapSystem.FindGridsIntersecting(mapPos.MapId, box, ref grids); + + var shredded = false; + + foreach (var grid in grids) + { + if (TerminatingOrDeleted(grid) || EntityManager.IsQueuedForDeletion(grid)) + continue; + + if (grid == reclaimerGrid) + continue; + + if (!_whitelist.CheckBoth(grid, ent.Comp1.Blacklist, ent.Comp1.Whitelist)) + continue; + + var intersectingEntities = new HashSet(); + + foreach (var tile in _mapSystem.GetTilesIntersecting(grid.Owner, grid.Comp, box)) + { + var tileDef = _turf.GetContentTileDefinition(tile); + if (tileDef.Indestructible) + continue; + + intersectingEntities.Clear(); + _lookup.GetLocalEntitiesIntersecting(tile.GridUid, tile.GridIndices, intersectingEntities); + + foreach (var entityOnTile in intersectingEntities) + { + if (!_physicsComponentQuery.TryComp(entityOnTile, out var physicsComp)) + { + // Marker/Spawn entities and similar don't have physics, so we just plain remove them. + QueueDel(entityOnTile); + continue; + } + + _physics.SetCanCollide(entityOnTile, true, body: physicsComp); + _physics.ApplyLinearImpulse(entityOnTile, _physics.GetLinearVelocity(grid.Owner, Transform(entityOnTile).LocalPosition), body: physicsComp); + } + + _mapSystem.SetTile(tile.GridUid, grid, tile.GridIndices, Tile.Empty); + // TODO: Ideally this should be using tilestacking to get materials out of every tile in the stack, as opposed to the top one. Not doing it right now as it may be reworked however. + SpawnMaterialsFromComposition((ent, null, ent.Comp2), tileDef, ent.Comp1.Efficiency); + shredded = true; + + // If it was the last tile, grid's probably gone + if (TerminatingOrDeleted(grid)) + continue; + + // We suck in the grid slurrrrp + // TODO: This can probably be refined, as it applies a stacking speed which could theoretically get out of hand if a grid is very long. + _physics.ApplyLinearImpulse(grid, ent.Comp1.SlurpStrength * _transform.GetWorldRotation(ent.Comp2).ToWorldVec(), tile.GridIndices); + } + } + + if (!shredded) + return; + + _audio.PlayPvs(ent.Comp1.Sound, ent); + } + + /// + /// Spawns materials from the of the given tile. + /// + /// Entity performing the spawning action. + /// Tile definition of the tile being reclaimed. + /// Multiplier of the material amount. + protected virtual void SpawnMaterialsFromComposition(Entity ent, + ContentTileDefinition tileDefinition, + float efficiency) + { + // Handled on the server because that's where MaterialStorageSystem is. + } +} diff --git a/Resources/Audio/Effects/attributions.yml b/Resources/Audio/Effects/attributions.yml index b842eb7b6c..d3a5cf94b7 100644 --- a/Resources/Audio/Effects/attributions.yml +++ b/Resources/Audio/Effects/attributions.yml @@ -276,3 +276,8 @@ copyright: "by petercornell (Freesound), sampled and sped up to 400% by whatston3 (GitHub)" license: "CC0-1.0" source: https://freesound.org/people/petercornell/sounds/837240/ + +- files: ["grind.ogg"] + copyright: 'modified by SlamBamActionman (Github) from "01-1 Angle Grinder.wav" by domiscz of Freesound.org' + license: "CC-BY-SA-3.0" + source: https://freesound.org/people/domiscz/sounds/461728/ diff --git a/Resources/Audio/Effects/grind.ogg b/Resources/Audio/Effects/grind.ogg new file mode 100644 index 0000000000..95b69bf6e5 Binary files /dev/null and b/Resources/Audio/Effects/grind.ogg differ diff --git a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml index 94cc143dcf..b0fc77fdae 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml @@ -81,6 +81,9 @@ interfaces: enum.DeimplantUiKey.Key: type: DeimplantBoundUserInterface + - type: Tag + tags: + - SmeltingImmune - type: entity id: Implanter @@ -153,7 +156,8 @@ True: {state: broken} False: {state: implanter1} - type: Tag - tags: [] + tags: + - SmeltingImmune #Fun implanters diff --git a/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml b/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml index ed16ce46a4..d5c69ede82 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml @@ -26,6 +26,8 @@ !type:PhysShapeAabb bounds: "-0.45,-0.45,0.45,0.45" density: 5 + mask: + - LowImpassable layer: - DoorPassable - type: Damageable diff --git a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml index 8fa681f9f3..5c296cc1ee 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml @@ -18,6 +18,7 @@ collection: GlassSmash - type: Transform anchored: true + - type: Pullable - type: Clickable - type: InteractionOutline - type: Sprite diff --git a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml index 6f22f46fa6..bcc31d0f3c 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml @@ -62,7 +62,6 @@ arrows: - offset: 0, -1.35 - offset: 0, 0 - - type: CollideMaterialReclaimer - type: MaterialReclaimer enabled: false @@ -132,3 +131,136 @@ - type: Speech speechVerb: Robotic speechSounds: SyndieBorg + +- type: entity + parent: [ BaseMachinePowered, StructureHealthMachineStrong ] + id: IndustrialSmelter + name: industrial smelter + suffix: Do Not Map + description: A massive stationary machine capable of chewing through flooring and walls. Must be powered to function. + components: + - type: Sprite + drawdepth: Doors + sprite: Structures/Machines/smelter.rsi + layers: + - state: smelter0 + map: ["enum.RecyclerVisualLayers.Main"] + offset: 0, 0.5 + - type: Appearance + - type: RecyclerVisuals + baseKey: smelter + - type: Conveyor + angle: 90 # Conveyor goes sideways + - type: DeviceLinkSink + ports: + - Reverse + - Forward + - Off + - type: MaterialStorage + insertOnInteract: false + - type: CollideMaterialReclaimer + - type: MaterialReclaimer + enabled: false + scaleProcessSpeed: false + minimumProcessDuration: 0 + efficiency: 0.1 + blacklist: # TODO: This will need to be iterated on to properly balance all items + components: + - Material + - Pda + - IdCard + - GrapplingProjectile + - Circuitboard + - Computer + tags: + - HighRiskItem + - SmeltingImmune + sound: + path: /Audio/Effects/saw.ogg + params: + volume: -3 + cutOffSound: false + - type: TileReclaimer + sound: + path: /Audio/Effects/grind.ogg # TODO: Needs more CRONCH, more SMELT + params: + volume: -3 + recyclingBox: "-0.35, 0.5, 0.35, 1" + blacklist: + components: + - StationMember + - CargoShuttle + - ArrivalsShuttle + - EmergencyShuttle + - type: Fixtures + fixtures: + brrt: + shape: + !type:PhysShapeAabb + bounds: "-0.5, -0.15, 0.5, 1.5" + hard: false + layer: + - FullTileLayer + - DoorPassable # Here to hit floor objects like carpets etc. + mask: + - FullTileMask # Necessary for grilles. + - TabletopMachineLayer # This is needed for lights. + collision: + shape: + !type:PhysShapeAabb + bounds: "-0.49,-0.49,0.49,0.49" + hard: true + mask: + - Impassable + layer: + - Opaque + - BulletImpassable + conveyor: + shape: !type:PolygonShape + vertices: + - -0.55,-0.55 + - 0.55,-0.55 + - 0.55,0.55 + - -0.55,0.55 + layer: + - Impassable + - MidImpassable + - LowImpassable + hard: False + - type: AmbientSound + enabled: false + volume: -8 + range: 5 + sound: + path: /Audio/Ambience/Objects/circular_saw.ogg + - type: Transform + anchored: true + noRot: false + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 200 + behaviors: + - !type:DoActsBehavior + acts: ["Breakage"] + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - type: Repairable + doAfterDelay: 5 + fuelCost: 25 + - type: Tag + tags: + - EmagImmune + - type: Speech + speechVerb: Robotic + speechSounds: SyndieBorg + +- type: entity + parent: IndustrialSmelter + id: IndustrialSmelterAdmeme + suffix: No Grid Whitelist, Admeme + components: + - type: TileReclaimer + blacklist: null diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml index eff831fa9e..34927e5427 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml @@ -8,6 +8,7 @@ components: - type: Transform anchored: true + - type: Pullable - type: Physics bodyType: Static - type: Sprite @@ -19,6 +20,8 @@ shape: !type:PhysShapeAabb bounds: "-0.5,-0.5,0.5,0.5" + mask: + - DoorPassable - type: Airtight noAirWhenFullyAirBlocked: false - type: Clickable @@ -35,6 +38,7 @@ components: - type: Transform anchored: true + - type: Pullable - type: Physics bodyType: Static - type: Sprite @@ -46,6 +50,8 @@ shape: !type:PhysShapeAabb bounds: "-0.48,-0.48,0.48,-0.40" + mask: + - DoorPassable - type: Airtight noAirWhenFullyAirBlocked: false airBlockedDirection: diff --git a/Resources/Prototypes/Entities/Structures/Power/apc.yml b/Resources/Prototypes/Entities/Structures/Power/apc.yml index 559b7972ae..ad4397deab 100644 --- a/Resources/Prototypes/Entities/Structures/Power/apc.yml +++ b/Resources/Prototypes/Entities/Structures/Power/apc.yml @@ -129,6 +129,15 @@ guides: - VoltageNetworks - Power + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.45,0.25,0.05" + density: 5 + mask: + - FullTileMask # APC under construction - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index eb5fe782f6..a768a85da2 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -132,13 +132,11 @@ # Compact Wall Substation Base - type: entity - parent: [ CoreSubstation, StructureHealthMachine ] + parent: [ CoreSubstation, BaseWallmount, StructureHealthMachine ] id: BaseSubstationWall categories: [ HideSpawnMenu ] name: wallmount substation description: A substation designed for compact shuttles and spaces. - placement: - mode: SnapgridCenter components: - type: AmbientSound range: 2 @@ -149,20 +147,12 @@ netsync: false castShadows: false offset: 0, -0.2 - - type: Clickable - type: ContainerFill containers: board: [ WallmountSubstationElectronics ] - type: ContainerContainer containers: board: !type:Container - - type: InteractionOutline - - type: Physics - bodyType: Static - canCollide: false - - type: Fixtures - - type: Transform - anchored: true - type: Sprite # TODO: add sprite for maintenance panel open drawdepth: WallMountedItems sprite: Structures/Power/substation.rsi @@ -196,7 +186,15 @@ maxIntensity: 50 intensitySlope: 2 totalIntensity: 100 - - type: WallMount + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.35,-0.45,0.35,0.20" + density: 5 + mask: + - FullTileMask # Substations in use diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml index 8f72b474d0..0c69b15454 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/base_structureclosets.yml @@ -171,6 +171,15 @@ - entity_storage - type: Paintable group: WallCloset + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.35,0.25,0.35" + density: 5 + mask: + - FullTileMask #Wall locker - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Switches/switch.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Switches/switch.yml index da1f99af48..3e4bfc9d3e 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Switches/switch.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Switches/switch.yml @@ -97,8 +97,6 @@ - type: DeviceLinkSource ports: - Pressed - - type: Transform - anchored: false - type: Destructible thresholds: - trigger: *DamageMachineFlimsy @@ -493,7 +491,18 @@ sprite: Structures/Wallmounts/switch-frame.rsi state: grey - type: Rotatable + - type: Transform + anchored: true + - type: Pullable - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.45" + density: 5 + mask: + - FullTileMask - type: entity id: ButtonFrameGrey diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml index 42ce1e5954..225cea40bb 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml @@ -12,7 +12,6 @@ - type: Rotatable - type: Physics canCollide: false - - type: Fixtures - type: Clickable - type: WallMount - type: InteractionOutline @@ -23,6 +22,16 @@ - Structure - type: Sprite drawdepth: WallMountedItems + - type: Pullable + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.45" + density: 5 + mask: + - FullTileMask - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Structures/Walls/grille.yml b/Resources/Prototypes/Entities/Structures/Walls/grille.yml index 9727b02430..ec33cedf83 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/grille.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/grille.yml @@ -160,7 +160,17 @@ graph: Grille node: grilleBroken deconstructionTarget: start - - type: Fixtures # overwrite BaseStructure parent. + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,-0.28125" + density: 5 + mask: + - DoorPassable + layer: + - DoorPassable - type: Physics bodyType: Static canCollide: false diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml index 08f8789397..84f245c293 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml @@ -321,6 +321,9 @@ density: 4000 - type: RadiationBlocker resistance: 5 + - type: Tag + tags: + - SmeltingImmune - type: entity parent: [ WallPlastitaniumIndestructible, StructureHealthWallStrong ] @@ -353,6 +356,10 @@ state: state0 - type: RadiationBlocker resistance: 5 + - type: Tag + tags: + - Diagonal + - SmeltingImmune - type: entity parent: [ WallPlastitaniumDiagonalIndestructible, StructureHealthWallStrong ] diff --git a/Resources/Prototypes/Entities/Structures/Windows/plastitanium.yml b/Resources/Prototypes/Entities/Structures/Windows/plastitanium.yml index 606b0a5ec1..452701a0d4 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/plastitanium.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/plastitanium.yml @@ -86,6 +86,11 @@ components: - type: ExaminableDamage messages: null + - type: Tag + tags: + - ForceFixRotations + - Window + - SmeltingImmune - type: entity parent: [ PlastitaniumWindowSquareBase, StructureHealthBarrierStrong ] @@ -171,6 +176,11 @@ components: - type: ExaminableDamage messages: null + - type: Tag + tags: + - ForceFixRotations + - Window + - SmeltingImmune - type: entity id: PlastitaniumWindowDiagonal diff --git a/Resources/Prototypes/Entities/Structures/catwalk.yml b/Resources/Prototypes/Entities/Structures/catwalk.yml index 88c53a8f6e..1ee851a6e0 100644 --- a/Resources/Prototypes/Entities/Structures/catwalk.yml +++ b/Resources/Prototypes/Entities/Structures/catwalk.yml @@ -1,6 +1,6 @@ # TODO move this to tiles once tile smoothing is supported - type: entity - parent: StructureHealthFurniture + parent: [ BaseStructure, StructureHealthFurniture ] id: Catwalk name: catwalk description: A catwalk for easier EVA maneuvering and cable placement. @@ -17,8 +17,6 @@ - type: Icon sprite: Structures/catwalk.rsi state: catwalk_preview - - type: Transform - anchored: true - type: IconSmooth key: catwalk base: catwalk_ @@ -51,3 +49,16 @@ cost: 2 delay: 2 fx: EffectRCDDeconstruct2 + - type: Physics + canCollide: false + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.45" + density: 5 + mask: + - LowImpassable + layer: + - DoorPassable diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index 2c1a82938b..1bb500cdaf 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -22,6 +22,8 @@ - FloorDirt - PlatingRCD - FloorHullReinforced + materialComposition: + Steel: 100 # 0.5 for lattice, 0.25 for plating, 0.25 for tile - type: tile id: FloorSteelCheckerLight diff --git a/Resources/Prototypes/Tiles/plating.yml b/Resources/Prototypes/Tiles/plating.yml index 81736d0b52..667ef36d9d 100644 --- a/Resources/Prototypes/Tiles/plating.yml +++ b/Resources/Prototypes/Tiles/plating.yml @@ -6,6 +6,8 @@ isSubfloor: true footstepSounds: collection: FootstepPlating + materialComposition: + Steel: 75 # 0.75 sheets; 0.5 for the lattice, 0.25 for the tile baseTurf: Lattice - type: tile @@ -77,3 +79,5 @@ heatCapacity: 10000 mass: 200 variants: 3 + materialComposition: + Steel: 50 # 0.5 sheets = 1 rod diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 7e689aa224..127ea543b7 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -1289,6 +1289,9 @@ - type: Tag id: Shiv # CargoBounty: BountyShiv +- type: Tag + id: SmeltingImmune # for entities that should not be deleted industrial smelter's MaterialReclaimer + - type: Tag id: Sidearm # Storage whitelist: ClothingBeltSecurity, ClothingShoesMilitaryBase diff --git a/Resources/Textures/Structures/Machines/smelter.rsi/meta.json b/Resources/Textures/Structures/Machines/smelter.rsi/meta.json new file mode 100644 index 0000000000..922a453a83 --- /dev/null +++ b/Resources/Textures/Structures/Machines/smelter.rsi/meta.json @@ -0,0 +1,39 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Smelter sprites by SlamBamActionman (Github)", + "size": { + "x": 32, + "y": 64 + }, + "states": [ + { + "name": "smelter0" + }, + { + "name": "smelter1", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "smelter1-0", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "smelter2" + } + ] +} diff --git a/Resources/Textures/Structures/Machines/smelter.rsi/smelter0.png b/Resources/Textures/Structures/Machines/smelter.rsi/smelter0.png new file mode 100644 index 0000000000..449061794b Binary files /dev/null and b/Resources/Textures/Structures/Machines/smelter.rsi/smelter0.png differ diff --git a/Resources/Textures/Structures/Machines/smelter.rsi/smelter1-0.png b/Resources/Textures/Structures/Machines/smelter.rsi/smelter1-0.png new file mode 100644 index 0000000000..a463a2be44 Binary files /dev/null and b/Resources/Textures/Structures/Machines/smelter.rsi/smelter1-0.png differ diff --git a/Resources/Textures/Structures/Machines/smelter.rsi/smelter1.png b/Resources/Textures/Structures/Machines/smelter.rsi/smelter1.png new file mode 100644 index 0000000000..735198a3ca Binary files /dev/null and b/Resources/Textures/Structures/Machines/smelter.rsi/smelter1.png differ diff --git a/Resources/Textures/Structures/Machines/smelter.rsi/smelter2.png b/Resources/Textures/Structures/Machines/smelter.rsi/smelter2.png new file mode 100644 index 0000000000..290f552717 Binary files /dev/null and b/Resources/Textures/Structures/Machines/smelter.rsi/smelter2.png differ