// Deconstruct the steel tile.
await Interact(null, pEast);
await RunSeconds(settingDeconstructTile.Delay + 1); // wait for the deconstruction to finish
- await AssertTile(Lattice, FromServer(pEast));
+ await AssertTile(Plating, FromServer(pEast));
// Check that the cost of the deconstruction was subtracted from the current charges.
newCharges = sCharges.GetCurrentCharges(ToServer(rcd));
protected const string FloorItem = "FloorTileItemSteel";
protected const string Plating = "Plating";
protected const string Lattice = "Lattice";
+ protected const string PlatingBrass = "PlatingBrass";
// Structures
protected const string Airlock = "Airlock";
await AssertEntityLookup((FloorItem, 1));
}
+
+ /// <summary>
+ /// Test brassPlating -> floor -> brassPlating using tilestacking
+ /// </summary>
+ [Test]
+ public async Task BrassPlatingPlace()
+ {
+ await SetTile(PlatingBrass);
+
+ // Brass Plating -> Tile
+ await InteractUsing(FloorItem);
+ Assert.That(HandSys.GetActiveItem((SEntMan.GetEntity(Player), Hands)), Is.Null);
+ await AssertTile(Floor);
+ AssertGridCount(1);
+
+ // Tile -> Brass Plating
+ await InteractUsing(Pry);
+ await AssertTile(PlatingBrass);
+ AssertGridCount(1);
+ await AssertEntityLookup((FloorItem, 1));
+ }
}
--- /dev/null
+using System.Collections.Generic;
+using System.Linq;
+using Content.Shared.CCVar;
+using Content.Shared.Maps;
+using Robust.Shared.Configuration;
+using Robust.Shared.Prototypes;
+
+namespace Content.IntegrationTests.Tests.Tiles;
+
+public sealed class TileStackRecursionTest
+{
+ [Test]
+ public async Task TestBaseTurfRecursion()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+ var protoMan = pair.Server.ResolveDependency<IPrototypeManager>();
+ var cfg = pair.Server.ResolveDependency<IConfigurationManager>();
+ var maxTileHistoryLength = cfg.GetCVar(CCVars.TileStackLimit);
+ Assert.That(protoMan.TryGetInstances<ContentTileDefinition>(out var tiles));
+ Assert.That(tiles, Is.Not.EqualTo(null));
+ //store the distance from the root node to the given tile node
+ var nodes = new List<(ProtoId<ContentTileDefinition>, int)>();
+ //each element of list is a connection from BaseTurf tile to tile that goes on it
+ var edges = new List<(ProtoId<ContentTileDefinition>, ProtoId<ContentTileDefinition>)>();
+ foreach (var ctdef in tiles!.Values)
+ {
+ //at first, each node is unexplored and has infinite distance to root.
+ //we use space node as root - everything is supposed to start at space, and it's hardcoded into the game anyway.
+ if (ctdef.ID == ContentTileDefinition.SpaceID)
+ {
+ nodes.Insert(0, (ctdef.ID, 0)); //space is the first element
+ continue;
+ }
+ Assert.That(ctdef.BaseTurf != ctdef.ID);
+ nodes.Add((ctdef.ID, int.MaxValue));
+ if (ctdef.BaseTurf != null)
+ edges.Add((ctdef.BaseTurf.Value, ctdef.ID));
+ Assert.That(ctdef.BaseWhitelist, Does.Not.Contain(ctdef.ID));
+ edges.AddRange(ctdef.BaseWhitelist.Select(possibleTurf =>
+ (possibleTurf, new ProtoId<ContentTileDefinition>(ctdef.ID))));
+ }
+ Bfs(nodes, edges, maxTileHistoryLength);
+ await pair.CleanReturnAsync();
+ }
+
+ private void Bfs(List<(ProtoId<ContentTileDefinition>, int)> nodes, List<(ProtoId<ContentTileDefinition>, ProtoId<ContentTileDefinition>)> edges, int depthLimit)
+ {
+ var root = nodes[0];
+ var queue = new Queue<(ProtoId<ContentTileDefinition>, int)>();
+ queue.Enqueue(root);
+ while (queue.Count != 0)
+ {
+ var u = queue.Dequeue();
+ //get a list of tiles that can be put on this tile
+ var adj = edges.Where(n => n.Item1 == u.Item1).Select(n => n.Item2);
+ var adjNodes = nodes.Where(n => adj.Contains(n.Item1)).ToList();
+ foreach (var node in adjNodes)
+ {
+ var adjNode = node;
+ adjNode.Item2 = u.Item2 + 1;
+ Assert.That(adjNode.Item2, Is.LessThanOrEqualTo(depthLimit)); //we can doomstack tiles on top of each other. Bad!
+ queue.Enqueue(adjNode);
+ }
+ }
+ }
+}
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using System.Numerics;
+using Content.Shared.Damage.Systems;
+using Robust.Shared.Prototypes;
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
namespace Content.Server.Explosion.EntitySystems;
int maxTileBreak,
bool canCreateVacuum,
List<(Vector2i GridIndices, Tile Tile)> damagedTiles,
- ExplosionPrototype type)
+ ExplosionPrototype type,
+ TileHistoryComponent? history,
+ ref (TileHistoryChunk? Chunk, Vector2i Indices)? chunk)
{
- if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef
- || tileDef.Indestructible)
+ if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef || tileDef.Indestructible)
return;
if (!CanCreateVacuum)
else if (tileDef.MapAtmosphere)
canCreateVacuum = true; // is already a vacuum.
+ // break the tile into its underlying parts
int tileBreakages = 0;
while (maxTileBreak > tileBreakages && _robustRandom.Prob(type.TileBreakChance(effectiveIntensity)))
{
tileBreakages++;
effectiveIntensity -= type.TileBreakRerollReduction;
- // does this have a base-turf that we can break it down to?
- if (string.IsNullOrEmpty(tileDef.BaseTurf))
+ if (GetNextTile((tileDef, tileRef.GridIndices), history, ref chunk) is not { } newId)
break;
- if (_tileDefinitionManager[tileDef.BaseTurf] is not ContentTileDefinition newDef)
- break;
+ var newDef = (ContentTileDefinition) _tileDefinitionManager[newId];
if (newDef.MapAtmosphere && !canCreateVacuum)
break;
damagedTiles.Add((tileRef.GridIndices, new Tile(tileDef.TileId)));
}
+
+ private ProtoId<ContentTileDefinition>? GetNextTile((ContentTileDefinition tileDef, Vector2i gridIndices) tile,
+ TileHistoryComponent? history,
+ ref (TileHistoryChunk? Chunk, Vector2i Indices)? chunk)
+ {
+ if (chunk?.Chunk == null || !chunk.Value.Chunk.History.TryGetValue(tile.gridIndices, out var stack))
+ return tile.tileDef.BaseTurf; // No tile stack means we return BaseTurf if it exists!
+
+ // last entry in the stack
+ if (stack.Count > 1)
+ {
+ var newId = stack[^1];
+ stack.RemoveAt(stack.Count - 1);
+ chunk.Value.Chunk.LastModified = _timing.CurTick;
+ return newId;
+ }
+
+ chunk.Value.Chunk.History.Remove(tile.gridIndices);
+ if (chunk.Value.Chunk.History.Count == 0)
+ {
+ history?.ChunkHistory.Remove(chunk.Value.Indices);
+ chunk = null;
+ }
+ else
+ {
+ chunk.Value.Chunk.LastModified = _timing.CurTick;
+ }
+
+ return stack[0]; // If the stack is somehow empty, this will throw, but we will have at least removed it from dict first!
+ }
+
+ public void DirtyHistory(EntityUid grid)
+ {
+ if (!_tileHistoryQuery.TryComp(grid, out var history))
+ return;
+
+ Dirty(grid, history);
+ }
}
/// <summary>
/// <summary>
/// The actual grid that this corresponds to. If null, this implies space.
/// </summary>
- public Entity<MapGridComponent>? MapGrid;
+ public Entity<MapGridComponent, TileHistoryComponent?>? MapGrid;
}
private readonly List<ExplosionData> _explosionData = new();
+ private Entity<MapGridComponent, TileHistoryComponent?>? _currentGrid;
+ private (TileHistoryChunk? Chunk, Vector2i Indices)? _currentChunk;
+
/// <summary>
/// The explosion intensity associated with each tile iteration.
/// </summary>
private DamageSpecifier? _expectedDamage;
#endif
private Entity<BroadphaseComponent> _currentLookup = default!;
- private Entity<MapGridComponent>? _currentGrid;
private float _currentIntensity;
private float _currentThrowForce;
private List<Vector2i>.Enumerator _currentEnumerator;
EntityUid visualEnt,
EntityUid? cause,
SharedMapSystem mapSystem,
- Shared.Damage.Systems.DamageableSystem damageable)
+ DamageableSystem damageable,
+ EntityQuery<TileHistoryComponent> historyQuery)
{
VisualEnt = visualEnt;
Cause = cause;
{
TileLists = spaceData.TileLists,
Lookup = (mapUid, entMan.GetComponent<BroadphaseComponent>(mapUid)),
- MapGrid = null
+ MapGrid = null,
});
_spaceMatrix = spaceMatrix;
foreach (var grid in gridData)
{
+ var history = historyQuery.CompOrNull(grid.Grid);
_explosionData.Add(new ExplosionData
{
TileLists = grid.TileLists,
Lookup = (grid.Grid, entMan.GetComponent<BroadphaseComponent>(grid.Grid)),
- MapGrid = grid.Grid,
+ MapGrid = (grid.Grid, entMan.GetComponent<MapGridComponent>(grid.Grid), history),
});
}
_currentEnumerator = tileList.GetEnumerator();
_currentLookup = _explosionData[_currentDataIndex].Lookup;
_currentGrid = _explosionData[_currentDataIndex].MapGrid;
+ _currentChunk = null;
_currentDataIndex++;
// sanity checks, in case something changed while the explosion was being processed over several ticks.
- if (_currentLookup.Comp.Deleted || _currentGrid != null && !_entMan.EntityExists(_currentGrid.Value))
+ if (_currentLookup.Comp.Deleted || (_currentGrid is { } grid && !_entMan.EntityExists(grid.Owner)))
continue;
return true;
// Is the current tile on a grid (instead of in space)?
if (_currentGrid is { } currentGrid &&
- _mapSystem.TryGetTileRef(currentGrid, currentGrid.Comp, _currentEnumerator.Current, out var tileRef) &&
+ _mapSystem.TryGetTileRef(currentGrid.Owner, currentGrid.Comp1, _currentEnumerator.Current, out var tileRef) &&
!tileRef.Tile.IsEmpty)
{
- if (!_tileUpdateDict.TryGetValue(currentGrid, out var tileUpdateList))
+ if (!_tileUpdateDict.TryGetValue((currentGrid.Owner, currentGrid.Comp1), out var tileUpdateList))
{
tileUpdateList = new();
- _tileUpdateDict[currentGrid] = tileUpdateList;
+ _tileUpdateDict[(currentGrid.Owner, currentGrid.Comp1)] = tileUpdateList;
}
// damage entities on the tile. Also figures out whether there are any solid entities blocking the floor
// from being destroyed.
var canDamageFloor = _system.ExplodeTile(_currentLookup,
- currentGrid,
+ (currentGrid.Owner, currentGrid.Comp1),
_currentEnumerator.Current,
_currentThrowForce,
_currentDamage,
// If the floor is not blocked by some dense object, damage the floor tiles.
if (canDamageFloor)
- _system.DamageFloorTile(tileRef, _currentIntensity * _tileBreakScale, _maxTileBreak, _canCreateVacuum, tileUpdateList, ExplosionType);
+ {
+ var tileIndices = _currentEnumerator.Current;
+ var chunkIndices = SharedMapSystem.GetChunkIndices(tileIndices, TileSystem.ChunkSize);
+ if (_currentChunk?.Indices != chunkIndices)
+ {
+ var chunk = currentGrid.Comp2?.ChunkHistory.GetValueOrDefault(chunkIndices);
+ _currentChunk = (chunk, chunkIndices);
+ }
+
+ _system.DamageFloorTile(tileRef,
+ _currentIntensity * _tileBreakScale,
+ _maxTileBreak,
+ _canCreateVacuum,
+ tileUpdateList,
+ ExplosionType,
+ currentGrid.Comp2,
+ ref _currentChunk);
+ }
}
else
{
if (list.Count > 0 && _entMan.EntityExists(grid.Owner))
{
_mapSystem.SetTiles(grid.Owner, grid, list);
+
+ _system.DirtyHistory(grid.Owner);
}
}
_tileUpdateDict.Clear();
using Content.Shared.Explosion.EntitySystems;
using Content.Shared.GameTicking;
using Content.Shared.Inventory;
+using Content.Shared.Maps;
using Content.Shared.Projectiles;
using Content.Shared.Throwing;
using Robust.Server.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Explosion.EntitySystems;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
private EntityQuery<DestructibleComponent> _destructibleQuery;
private EntityQuery<DamageableComponent> _damageableQuery;
private EntityQuery<AirtightComponent> _airtightQuery;
+ private EntityQuery<TileHistoryComponent> _tileHistoryQuery;
/// <summary>
/// "Tile-size" for space when there are no nearby grids to use as a reference.
_destructibleQuery = GetEntityQuery<DestructibleComponent>();
_damageableQuery = GetEntityQuery<DamageableComponent>();
_airtightQuery = GetEntityQuery<AirtightComponent>();
+ _tileHistoryQuery = GetEntityQuery<TileHistoryComponent>();
_prototypeManager.PrototypesReloaded += ReloadExplosionPrototypes;
}
visualEnt,
queued.Cause,
_map,
- _damageableSystem);
+ _damageableSystem,
+ _tileHistoryQuery);
}
private void CameraShake(float range, MapCoordinates epicenter, float totalIntensity)
--- /dev/null
+using System.Numerics;
+using Content.Shared.Maps;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Maps;
+
+/// <summary>
+/// This system handles transferring <see cref="TileHistoryComponent"/> data when a grid is split.
+/// </summary>
+public sealed class TileGridSplitSystem : EntitySystem
+{
+ [Dependency] private readonly SharedMapSystem _maps = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<GridSplitEvent>(OnGridSplit);
+ }
+
+ /// <summary>
+ /// Transfer tile history from the old grid to the new grids.
+ /// </summary>
+ private void OnGridSplit(ref GridSplitEvent ev)
+ {
+ if (!TryComp<TileHistoryComponent>(ev.Grid, out var oldHistory))
+ return;
+
+ var oldGrid = Comp<MapGridComponent>(ev.Grid);
+
+ foreach (var gridUid in ev.NewGrids)
+ {
+ // ensure the new grid has a history component and get its grid component
+ var newHistory = EnsureComp<TileHistoryComponent>(gridUid);
+ var newGrid = Comp<MapGridComponent>(gridUid);
+
+ foreach (var tile in _maps.GetAllTiles(gridUid, newGrid))
+ {
+ // calculate where this tile was on the old grid
+ var oldIndices = _maps.LocalToTile(ev.Grid, oldGrid, new EntityCoordinates(gridUid, new Vector2(tile.GridIndices.X + 0.5f, tile.GridIndices.Y + 0.5f)));
+
+ var chunkIndices = SharedMapSystem.GetChunkIndices(oldIndices, TileSystem.ChunkSize);
+ if (oldHistory.ChunkHistory.TryGetValue(chunkIndices, out var oldChunk) &&
+ oldChunk.History.TryGetValue(oldIndices, out var history))
+ {
+ // now we move the history from the old grid to the new grid
+ var newChunkIndices = SharedMapSystem.GetChunkIndices(tile.GridIndices, TileSystem.ChunkSize);
+ if (!newHistory.ChunkHistory.TryGetValue(newChunkIndices, out var newChunk))
+ {
+ newChunk = new TileHistoryChunk();
+ newHistory.ChunkHistory[newChunkIndices] = newChunk;
+ }
+
+ newChunk.History[tile.GridIndices] = new List<ProtoId<ContentTileDefinition>>(history);
+ newChunk.LastModified = _timing.CurTick;
+
+ // clean up the old history
+ oldChunk.History.Remove(oldIndices);
+ if (oldChunk.History.Count == 0)
+ oldHistory.ChunkHistory.Remove(chunkIndices);
+ else
+ oldChunk.LastModified = _timing.CurTick;
+ }
+ }
+
+ Dirty(gridUid, newHistory);
+ }
+
+ Dirty(ev.Grid, oldHistory);
+ }
+}
/// </summary>
public static readonly CVarDef<bool> GameHostnameInTitlebar =
CVarDef.Create("game.hostname_in_titlebar", true, CVar.SERVER | CVar.REPLICATED);
+
+ /// <summary>
+ /// The maximum amount of tiles you can stack on top of each other. 0 is unlimited.
+ /// </summary>
+ /// <remarks>
+ /// Having it too high can result in "doomstacking" tiles - this messes with efficiency of explosions, deconstruction of tiles, and might result in memory problems.
+ /// </remarks>
+ public static readonly CVarDef<int> TileStackLimit =
+ CVarDef.Create("game.tile_stack_limit", 5, CVar.SERVER | CVar.REPLICATED);
}
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
using Robust.Shared.Utility;
namespace Content.Shared.Maps
[DataField("isSubfloor")] public bool IsSubFloor { get; private set; }
[DataField("baseTurf")]
- public string BaseTurf { get; private set; } = string.Empty;
+ public ProtoId<ContentTileDefinition>? BaseTurf { get; private set; }
+
+ /// <summary>
+ /// On what tiles this tile can be placed on. BaseTurf is already included.
+ /// </summary>
+ [DataField]
+ public List<ProtoId<ContentTileDefinition>> BaseWhitelist { get; private set; } = new();
[DataField]
public PrototypeFlags<ToolQualityPrototype> DeconstructTools { get; set; } = new();
--- /dev/null
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Maps;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class TileHistoryComponent : Component
+{
+ // History of tiles for each grid chunk.
+ [DataField]
+ public Dictionary<Vector2i, TileHistoryChunk> ChunkHistory = new();
+
+ /// <summary>
+ /// Tick at which PVS was last toggled. Ensures that all players receive a full update when toggling PVS.
+ /// </summary>
+ public GameTick ForceTick { get; set; }
+}
+
+[Serializable, NetSerializable]
+public sealed class TileHistoryState : ComponentState
+{
+ public Dictionary<Vector2i, TileHistoryChunk> ChunkHistory;
+
+ public TileHistoryState(Dictionary<Vector2i, TileHistoryChunk> chunkHistory)
+ {
+ ChunkHistory = chunkHistory;
+ }
+}
+
+[Serializable, NetSerializable]
+public sealed class TileHistoryDeltaState : ComponentState, IComponentDeltaState<TileHistoryState>
+{
+ public Dictionary<Vector2i, TileHistoryChunk> ChunkHistory;
+ public HashSet<Vector2i> AllHistoryChunks;
+
+ public TileHistoryDeltaState(Dictionary<Vector2i, TileHistoryChunk> chunkHistory, HashSet<Vector2i> allHistoryChunks)
+ {
+ ChunkHistory = chunkHistory;
+ AllHistoryChunks = allHistoryChunks;
+ }
+
+ public void ApplyToFullState(TileHistoryState state)
+ {
+ var toRemove = new List<Vector2i>();
+ foreach (var key in state.ChunkHistory.Keys)
+ {
+ if (!AllHistoryChunks.Contains(key))
+ toRemove.Add(key);
+ }
+
+ foreach (var key in toRemove)
+ {
+ state.ChunkHistory.Remove(key);
+ }
+
+ foreach (var (indices, chunk) in ChunkHistory)
+ {
+ state.ChunkHistory[indices] = new TileHistoryChunk(chunk);
+ }
+ }
+
+ public void ApplyToComponent(TileHistoryComponent component)
+ {
+ var toRemove = new List<Vector2i>();
+ foreach (var key in component.ChunkHistory.Keys)
+ {
+ if (!AllHistoryChunks.Contains(key))
+ toRemove.Add(key);
+ }
+
+ foreach (var key in toRemove)
+ {
+ component.ChunkHistory.Remove(key);
+ }
+
+ foreach (var (indices, chunk) in ChunkHistory)
+ {
+ component.ChunkHistory[indices] = new TileHistoryChunk(chunk);
+ }
+ }
+
+ public TileHistoryState CreateNewFullState(TileHistoryState state)
+ {
+ var chunks = new Dictionary<Vector2i, TileHistoryChunk>(state.ChunkHistory.Count);
+
+ foreach (var (indices, chunk) in ChunkHistory)
+ {
+ chunks[indices] = new TileHistoryChunk(chunk);
+ }
+
+ foreach (var (indices, chunk) in state.ChunkHistory)
+ {
+ if (AllHistoryChunks.Contains(indices))
+ chunks.TryAdd(indices, new TileHistoryChunk(chunk));
+ }
+
+ return new TileHistoryState(chunks);
+ }
+}
+
+[DataDefinition, Serializable, NetSerializable]
+public sealed partial class TileHistoryChunk
+{
+ [DataField]
+ public Dictionary<Vector2i, List<ProtoId<ContentTileDefinition>>> History = new();
+
+ [ViewVariables]
+ public GameTick LastModified;
+
+ public TileHistoryChunk()
+ {
+ }
+
+ public TileHistoryChunk(TileHistoryChunk other)
+ {
+ History = new Dictionary<Vector2i, List<ProtoId<ContentTileDefinition>>>(other.History.Count);
+ foreach (var (key, value) in other.History)
+ {
+ History[key] = new List<ProtoId<ContentTileDefinition>>(value);
+ }
+ LastModified = other.LastModified;
+ }
+}
using System.Linq;
using System.Numerics;
+using Content.Shared.CCVar;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Decals;
+using Content.Shared.Tiles;
+using Robust.Shared.Configuration;
+using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
+using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared.Maps;
/// </summary>
public sealed class TileSystem : EntitySystem
{
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly SharedDecalSystem _decal = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+
+ public const int ChunkSize = 16;
+
+ private int _tileStackLimit;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent<GridInitializeEvent>(OnGridStartup);
+ SubscribeLocalEvent<TileHistoryComponent, ComponentGetState>(OnGetState);
+ SubscribeLocalEvent<TileHistoryComponent, ComponentHandleState>(OnHandleState);
+ SubscribeLocalEvent<TileHistoryComponent, FloorTileAttemptEvent>(OnFloorTileAttempt);
+
+ _cfg.OnValueChanged(CCVars.TileStackLimit, t => _tileStackLimit = t, true);
+ }
+
+ private void OnHandleState(EntityUid uid, TileHistoryComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not TileHistoryState state && args.Current is not TileHistoryDeltaState)
+ return;
+
+ if (args.Current is TileHistoryState fullState)
+ {
+ component.ChunkHistory.Clear();
+ foreach (var (key, value) in fullState.ChunkHistory)
+ {
+ component.ChunkHistory[key] = new TileHistoryChunk(value);
+ }
+
+ return;
+ }
+
+ if (args.Current is TileHistoryDeltaState deltaState)
+ {
+ deltaState.ApplyToComponent(component);
+ }
+ }
+
+ private void OnGetState(EntityUid uid, TileHistoryComponent component, ref ComponentGetState args)
+ {
+ if (args.FromTick <= component.CreationTick || args.FromTick <= component.ForceTick)
+ {
+ var fullHistory = new Dictionary<Vector2i, TileHistoryChunk>(component.ChunkHistory.Count);
+ foreach (var (key, value) in component.ChunkHistory)
+ {
+ fullHistory[key] = new TileHistoryChunk(value);
+ }
+ args.State = new TileHistoryState(fullHistory);
+ return;
+ }
+
+ var data = new Dictionary<Vector2i, TileHistoryChunk>();
+ foreach (var (index, chunk) in component.ChunkHistory)
+ {
+ if (chunk.LastModified >= args.FromTick)
+ data[index] = new TileHistoryChunk(chunk);
+ }
+
+ args.State = new TileHistoryDeltaState(data, new(component.ChunkHistory.Keys));
+ }
+
+ /// <summary>
+ /// On grid startup, ensure that we have Tile History.
+ /// </summary>
+ private void OnGridStartup(GridInitializeEvent ev)
+ {
+ if (HasComp<MapComponent>(ev.EntityUid))
+ return;
+
+ EnsureComp<TileHistoryComponent>(ev.EntityUid);
+ }
/// <summary>
/// Returns a weighted pick of a tile variant.
return PryTile(tileRef);
}
- public bool PryTile(TileRef tileRef)
+ public bool PryTile(TileRef tileRef)
{
return PryTile(tileRef, false);
}
if (tile.IsEmpty)
return false;
- var tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.TypeId];
+ var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.TypeId];
if (!tileDef.CanCrowbar)
return false;
return ReplaceTile(tileref, replacementTile, tileref.GridUid, grid);
}
- public bool ReplaceTile(TileRef tileref, ContentTileDefinition replacementTile, EntityUid grid, MapGridComponent? component = null)
+ public bool ReplaceTile(TileRef tileref, ContentTileDefinition replacementTile, EntityUid grid, MapGridComponent? component = null, byte? variant = null)
{
DebugTools.Assert(tileref.GridUid == grid);
if (!Resolve(grid, ref component))
return false;
+ var key = tileref.GridIndices;
+ var currentTileDef = (ContentTileDefinition) _tileDefinitionManager[tileref.Tile.TypeId];
+
+ // If the tile we're placing has a baseTurf that matches the tile we're replacing, we don't need to create a history
+ // unless the tile already has a history.
+ var history = EnsureComp<TileHistoryComponent>(grid);
+ var chunkIndices = SharedMapSystem.GetChunkIndices(key, ChunkSize);
+ history.ChunkHistory.TryGetValue(chunkIndices, out var chunk);
+ var historyExists = chunk != null && chunk.History.ContainsKey(key);
+
+ if (replacementTile.BaseTurf != currentTileDef.ID || historyExists)
+ {
+ if (chunk == null)
+ {
+ chunk = new TileHistoryChunk();
+ history.ChunkHistory[chunkIndices] = chunk;
+ }
+
+ chunk.LastModified = _timing.CurTick;
+ Dirty(grid, history);
+
+ //Create stack if needed
+ if (!chunk.History.TryGetValue(key, out var stack))
+ {
+ stack = new List<ProtoId<ContentTileDefinition>>();
+ chunk.History[key] = stack;
+ }
+
+ //Prevent the doomstack
+ if (stack.Count >= _tileStackLimit && _tileStackLimit != 0)
+ return false;
+
+ //Push current tile to the stack, if not empty
+ if (!tileref.Tile.IsEmpty)
+ {
+ stack.Add(currentTileDef.ID);
+ }
+ }
- var variant = PickVariant(replacementTile);
+ variant ??= PickVariant(replacementTile);
var decals = _decal.GetDecalsInRange(tileref.GridUid, _turf.GetTileCenter(tileref).Position, 0.5f);
foreach (var (id, _) in decals)
{
_decal.RemoveDecal(tileref.GridUid, id);
}
- _maps.SetTile(grid, component, tileref.GridIndices, new Tile(replacementTile.TileId, 0, variant));
+ _maps.SetTile(grid, component, tileref.GridIndices, new Tile(replacementTile.TileId, 0, variant.Value));
return true;
}
- public bool DeconstructTile(TileRef tileRef)
+
+ public bool DeconstructTile(TileRef tileRef, bool spawnItem = true)
{
if (tileRef.Tile.IsEmpty)
return false;
- var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileRef.Tile.TypeId];
+ var tileDef = (ContentTileDefinition)_tileDefinitionManager[tileRef.Tile.TypeId];
- if (string.IsNullOrEmpty(tileDef.BaseTurf))
+ //Can't deconstruct anything that doesn't have a base turf.
+ if (tileDef.BaseTurf == null)
return false;
var gridUid = tileRef.GridUid;
(_robustRandom.NextFloat() - 0.5f) * bounds,
(_robustRandom.NextFloat() - 0.5f) * bounds));
- //Actually spawn the relevant tile item at the right position and give it some random offset.
- var tileItem = Spawn(tileDef.ItemDropPrototypeName, coordinates);
- Transform(tileItem).LocalRotation = _robustRandom.NextDouble() * Math.Tau;
+ var historyComp = EnsureComp<TileHistoryComponent>(gridUid);
+ ProtoId<ContentTileDefinition> previousTileId;
- // Destroy any decals on the tile
+ var chunkIndices = SharedMapSystem.GetChunkIndices(indices, ChunkSize);
+
+ //Pop from stack if we have history
+ if (historyComp.ChunkHistory.TryGetValue(chunkIndices, out var chunk) &&
+ chunk.History.TryGetValue(indices, out var stack) && stack.Count > 0)
+ {
+ chunk.LastModified = _timing.CurTick;
+ Dirty(gridUid, historyComp);
+
+ previousTileId = stack.Last();
+ stack.RemoveAt(stack.Count - 1);
+
+ //Clean up empty stacks to avoid memory buildup
+ if (stack.Count == 0)
+ {
+ chunk.History.Remove(indices);
+ }
+
+ // Clean up empty chunks
+ if (chunk.History.Count == 0)
+ {
+ historyComp.ChunkHistory.Remove(chunkIndices);
+ }
+ }
+ else
+ {
+ //No stack? Assume BaseTurf was the layer below
+ previousTileId = tileDef.BaseTurf.Value;
+ }
+
+ if (spawnItem)
+ {
+ //Actually spawn the relevant tile item at the right position and give it some random offset.
+ var tileItem = Spawn(tileDef.ItemDropPrototypeName, coordinates);
+ Transform(tileItem).LocalRotation = _robustRandom.NextDouble() * Math.Tau;
+ }
+
+ //Destroy any decals on the tile
var decals = _decal.GetDecalsInRange(gridUid, coordinates.SnapToGrid(EntityManager, _mapManager).Position, 0.5f);
foreach (var (id, _) in decals)
{
_decal.RemoveDecal(tileRef.GridUid, id);
}
- var plating = _tileDefinitionManager[tileDef.BaseTurf];
- _maps.SetTile(gridUid, mapGrid, tileRef.GridIndices, new Tile(plating.TileId));
+ //Replace tile with the one it was placed on
+ var previousDef = (ContentTileDefinition)_tileDefinitionManager[previousTileId];
+ _maps.SetTile(gridUid, mapGrid, indices, new Tile(previousDef.TileId));
return true;
}
+
+ private void OnFloorTileAttempt(Entity<TileHistoryComponent> ent, ref FloorTileAttemptEvent args)
+ {
+ if (_tileStackLimit == 0)
+ return;
+ var chunkIndices = SharedMapSystem.GetChunkIndices(args.GridIndices, ChunkSize);
+ if (!ent.Comp.ChunkHistory.TryGetValue(chunkIndices, out var chunk) ||
+ !chunk.History.TryGetValue(args.GridIndices, out var stack))
+ return;
+ args.Cancelled = stack.Count >= _tileStackLimit; // greater or equals because the attempt itself counts as a tile we're trying to place
+ }
}
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly TurfSystem _turf = default!;
+ [Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
if (target == null)
{
- // Deconstruct tile (either converts the tile to lattice, or removes lattice)
- var tileDef = (_turf.GetContentTileDefinition(tile).ID != "Lattice") ? new Tile(_tileDefMan["Lattice"].TileId) : Tile.Empty;
- _mapSystem.SetTile(gridUid, mapGrid, position, tileDef);
- _adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to set grid: {gridUid} tile: {position} open to space");
+ // Deconstruct tile, don't drop tile as item
+ if (_tile.DeconstructTile(tile, spawnItem: false))
+ _adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to set grid: {gridUid} tile: {position} open to space");
}
else
{
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
+using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Shared.Tiles;
var baseTurf = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId];
- if (HasBaseTurf(currentTileDefinition, baseTurf.ID))
+ if (CanPlaceOn(currentTileDefinition, baseTurf.ID))
{
if (!_stackSystem.TryUse((uid, stack), 1))
continue;
return;
}
}
- else if (HasBaseTurf(currentTileDefinition, ContentTileDefinition.SpaceID))
+ else if (HasBaseTurf(currentTileDefinition, new ProtoId<ContentTileDefinition>(ContentTileDefinition.SpaceID)))
{
if (!_stackSystem.TryUse((uid, stack), 1))
continue;
}
}
- public bool HasBaseTurf(ContentTileDefinition tileDef, string baseTurf)
+ public bool HasBaseTurf(ContentTileDefinition tileDef, ProtoId<ContentTileDefinition> baseTurf)
{
return tileDef.BaseTurf == baseTurf;
}
+ private bool CanPlaceOn(ContentTileDefinition tileDef, ProtoId<ContentTileDefinition> currentTurfId)
+ {
+ //Check exact BaseTurf match
+ if (tileDef.BaseTurf == currentTurfId)
+ return true;
+
+ // Check whitelist match
+ if (tileDef.BaseWhitelist.Count > 0 && tileDef.BaseWhitelist.Contains(currentTurfId))
+ return true;
+
+ return false;
+ }
+
private void PlaceAt(EntityUid user, EntityUid gridUid, MapGridComponent mapGrid, EntityCoordinates location,
ushort tileId, SoundSpecifier placeSound, float offset = 0)
{
_adminLogger.Add(LogType.Tile, LogImpact.Low, $"{ToPrettyString(user):actor} placed tile {_tileDefinitionManager[tileId].Name} at {ToPrettyString(gridUid)} {location}");
- var random = new System.Random((int) _timing.CurTick.Value);
- var variant = _tile.PickVariant((ContentTileDefinition) _tileDefinitionManager[tileId], random);
- _map.SetTile(gridUid, mapGrid,location.Offset(new Vector2(offset, offset)), new Tile(tileId, 0, variant));
+ var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileId];
+ var random = new System.Random((int)_timing.CurTick.Value);
+ var variant = _tile.PickVariant(tileDef, random);
+
+ var tileRef = _map.GetTileRef(gridUid, mapGrid, location.Offset(new Vector2(offset, offset)));
+ _tile.ReplaceTile(tileRef, tileDef, gridUid, mapGrid, variant: variant);
_audio.PlayPredicted(placeSound, location, user);
}
+- type: tile
+ id: BaseStationTile
+ abstract: true
+ isSubfloor: false
+ deconstructTools: [ Prying ]
+ footstepSounds:
+ collection: FootstepFloor
+ heatCapacity: 10000
+ baseTurf: Plating
+ baseWhitelist:
+ - PlatingBrass
+ - FloorAsteroidIronsand
+ - FloorAsteroidSand
+ - FloorAsteroidSandBorderless
+ - FloorAsteroidIronsandBorderless
+ - FloorAsteroidSandRedBorderless
+ - PlatingAsteroid
+ - PlatingSnow
+ - FloorPlanetDirt
+ - FloorDesert
+ - FloorLowDesert
+ - FloorPlanetGrass
+ - FloorSnow
+ - FloorDirt
+
- type: tile
id: FloorSteel
+ parent: BaseStationTile
name: tiles-steel-floor
sprite: /Textures/Tiles/steel.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteel
- heatCapacity: 10000
- type: tile
id: FloorSteelCheckerLight
+ parent: BaseStationTile
name: tiles-steel-floor-checker-light
sprite: /Textures/Tiles/cafeteria.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteelCheckerLight
- heatCapacity: 10000
- type: tile
id: FloorSteelCheckerDark
+ parent: BaseStationTile
name: tiles-steel-floor-checker-dark
sprite: /Textures/Tiles/checker_dark.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteelCheckerDark
- heatCapacity: 10000
- type: tile
id: FloorSteelMini
+ parent: BaseStationTile
name: tiles-steel-floor-mini
sprite: /Textures/Tiles/steel_mini.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteelMini
- heatCapacity: 10000
- type: tile
id: FloorSteelPavement
+ parent: BaseStationTile
name: tiles-steel-floor-pavement
sprite: /Textures/Tiles/steel_pavement.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteelPavement
- heatCapacity: 10000
- type: tile
id: FloorSteelDiagonal
+ parent: BaseStationTile
name: tiles-steel-floor-diagonal
sprite: /Textures/Tiles/steel_diagonal.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteelDiagonal
- heatCapacity: 10000
- type: tile
id: FloorSteelOffset
+ parent: BaseStationTile
name: tiles-steel-floor-offset
sprite: /Textures/Tiles/steel_offset.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteelOffset
- heatCapacity: 10000
- type: tile
id: FloorSteelMono
+ parent: BaseStationTile
name: tiles-steel-floor-mono
sprite: /Textures/Tiles/steel_mono.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepTile
itemDrop: FloorTileItemSteelMono
- heatCapacity: 10000
- type: tile
id: FloorSteelPavementVertical
+ parent: BaseStationTile
name: tiles-steel-floor-pavement-vertical
sprite: /Textures/Tiles/steel_pavement_vertical.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepTile
itemDrop: FloorTileItemSteelPavementVertical
- heatCapacity: 10000
- type: tile
id: FloorSteelHerringbone
+ parent: BaseStationTile
name: tiles-steel-floor-herringbone
sprite: /Textures/Tiles/steel_herringbone.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepTile
itemDrop: FloorTileItemSteelHerringbone
- heatCapacity: 10000
- type: tile
id: FloorSteelDiagonalMini
+ parent: BaseStationTile
name: tiles-steel-floor-diagonal-mini
sprite: /Textures/Tiles/steel_diagonal_mini.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepTile
itemDrop: FloorTileItemSteelDiagonalMini
- heatCapacity: 10000
- type: tile
id: FloorBrassFilled
+ parent: BaseStationTile
name: tiles-brass-floor-filled
sprite: /Textures/Tiles/Misc/clockwork/clockwork_floor_filled.png
- baseTurf: PlatingBrass
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemBrassFilled
- heatCapacity: 10000
- type: tile
id: FloorBrassReebe
+ parent: BaseStationTile
name: tiles-brass-floor-reebe
sprite: /Textures/Tiles/Misc/clockwork/reebe.png
- baseTurf: PlatingBrass
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemBrassReebe
- heatCapacity: 10000
- type: tile
id: FloorPlastic
+ parent: BaseStationTile
name: tiles-plastic-floor
sprite: /Textures/Tiles/plastic.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteel
- heatCapacity: 10000
- type: tile
id: FloorWood
+ parent: BaseStationTile
name: tiles-wood
sprite: /Textures/Tiles/wood.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepWood
barestepSounds:
collection: BarestepWood
itemDrop: FloorTileItemWood
- heatCapacity: 10000
- type: tile
id: FloorWhite
+ parent: BaseStationTile
name: tiles-white-floor
sprite: /Textures/Tiles/white.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhite
- heatCapacity: 10000
- type: tile
id: FloorWhiteMini
+ parent: BaseStationTile
name: tiles-white-floor-mini
sprite: /Textures/Tiles/white_mini.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhiteMini
- heatCapacity: 10000
- type: tile
id: FloorWhitePavement
+ parent: BaseStationTile
name: tiles-white-floor-pavement
sprite: /Textures/Tiles/white_pavement.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhitePavement
- heatCapacity: 10000
- type: tile
id: FloorWhiteDiagonal
+ parent: BaseStationTile
name: tiles-white-floor-diagonal
sprite: /Textures/Tiles/white_diagonal.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhiteDiagonal
- heatCapacity: 10000
- type: tile
id: FloorWhiteOffset
+ parent: BaseStationTile
name: tiles-white-floor-offset
sprite: /Textures/Tiles/white_offset.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhiteOffset
- heatCapacity: 10000
- type: tile
id: FloorWhiteMono
+ parent: BaseStationTile
name: tiles-white-floor-mono
sprite: /Textures/Tiles/white_mono.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhiteMono
- heatCapacity: 10000
- type: tile
id: FloorWhitePavementVertical
+ parent: BaseStationTile
name: tiles-white-floor-pavement-vertical
sprite: /Textures/Tiles/white_pavement_vertical.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhitePavementVertical
- heatCapacity: 10000
- type: tile
id: FloorWhiteHerringbone
+ parent: BaseStationTile
name: tiles-white-floor-herringbone
sprite: /Textures/Tiles/white_herringbone.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhiteHerringbone
- heatCapacity: 10000
- type: tile
id: FloorWhiteDiagonalMini
+ parent: BaseStationTile
name: tiles-white-floor-diagonal-mini
sprite: /Textures/Tiles/white_diagonal_mini.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhiteDiagonalMini
- heatCapacity: 10000
- type: tile
id: FloorWhitePlastic
+ parent: BaseStationTile
name: tiles-plastic-white-floor
sprite: /Textures/Tiles/white_plastic.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemWhite
- heatCapacity: 10000
- type: tile
id: FloorDark
+ parent: BaseStationTile
name: tiles-dark-floor
sprite: /Textures/Tiles/dark.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDark
- heatCapacity: 10000
- type: tile
id: FloorDarkMini
+ parent: BaseStationTile
name: tiles-dark-floor-mini
sprite: /Textures/Tiles/dark_mini.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkMini
- heatCapacity: 10000
- type: tile
id: FloorDarkPavement
+ parent: BaseStationTile
name: tiles-dark-floor-pavement
sprite: /Textures/Tiles/dark_pavement.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkPavement
- heatCapacity: 10000
- type: tile
id: FloorDarkDiagonal
+ parent: BaseStationTile
name: tiles-dark-floor-diagonal
sprite: /Textures/Tiles/dark_diagonal.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkDiagonal
- heatCapacity: 10000
- type: tile
id: FloorDarkOffset
+ parent: BaseStationTile
name: tiles-dark-floor-offset
sprite: /Textures/Tiles/dark_offset.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkOffset
- heatCapacity: 10000
- type: tile
id: FloorDarkMono
+ parent: BaseStationTile
name: tiles-dark-floor-mono
sprite: /Textures/Tiles/dark_mono.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkMono
- heatCapacity: 10000
- type: tile
id: FloorDarkPavementVertical
+ parent: BaseStationTile
name: tiles-dark-floor-pavement-vertical
sprite: /Textures/Tiles/dark_pavement_vertical.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkPavementVertical
- heatCapacity: 10000
- type: tile
id: FloorDarkHerringbone
+ parent: BaseStationTile
name: tiles-dark-floor-herringbone
sprite: /Textures/Tiles/dark_herringbone.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkHerringbone
- heatCapacity: 10000
- type: tile
id: FloorDarkDiagonalMini
+ parent: BaseStationTile
name: tiles-dark-floor-diagonal-mini
sprite: /Textures/Tiles/dark_diagonal_mini.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDarkDiagonalMini
- heatCapacity: 10000
- type: tile
id: FloorDarkPlastic
+ parent: BaseStationTile
name: tiles-plastic-dark-floor
sprite: /Textures/Tiles/dark_plastic.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemDark
- heatCapacity: 10000
- type: tile
id: FloorTechMaint
+ parent: BaseStationTile
name: tiles-techmaint-floor
sprite: /Textures/Tiles/tech_maint.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemTechmaint
- heatCapacity: 10000
- type: tile
id: FloorTechMaintDark
+ parent: BaseStationTile
name: tiles-techmaint-floor-dark
sprite: /Textures/Tiles/tech_maint_dark.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemTechmaintDark
- heatCapacity: 10000
- type: tile
id: FloorReinforced
+ parent: BaseStationTile
name: tiles-reinforced-floor
sprite: /Textures/Tiles/reinforced.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: PartRodMetal1
- heatCapacity: 10000
- type: tile
id: FloorMono
+ parent: BaseStationTile
name: tiles-mono-floor
sprite: /Textures/Tiles/mono.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemMono
- heatCapacity: 10000
- type: tile
id: FloorLino
+ parent: BaseStationTile
name: tiles-linoleum-floor
sprite: /Textures/Tiles/lino.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemLino
- heatCapacity: 10000
- type: tile
id: FloorSteelDirty
+ parent: BaseStationTile
name: tiles-dirty-steel-floor
sprite: /Textures/Tiles/steel_dirty.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepPlating
itemDrop: FloorTileItemDirty
- heatCapacity: 10000
- type: tile
id: FloorElevatorShaft
+ parent: BaseStationTile
name: tiles-elevator-shaft
sprite: /Textures/Tiles/elevator_shaft.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemElevatorShaft
- heatCapacity: 10000
- type: tile
id: FloorMetalDiamond
+ parent: BaseStationTile
name: tiles-diamond-plate-floor
sprite: /Textures/Tiles/metaldiamond.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemMetalDiamond
- heatCapacity: 10000
- type: tile
id: FloorRockVault
+ parent: BaseStationTile
name: tiles-rock-floor
sprite: /Textures/Tiles/rock_vault.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepAsteroid
itemDrop: FloorTileItemRockVault
- heatCapacity: 10000
- type: tile
id: FloorBlue
+ parent: BaseStationTile
name: tiles-blue-tile
sprite: /Textures/Tiles/blue.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemBlue
- heatCapacity: 10000
- type: tile
id: FloorSteelLime
+ parent: BaseStationTile
name: tiles-lime-floor
sprite: /Textures/Tiles/lime.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemLime
- heatCapacity: 10000
- type: tile
id: FloorMining
+ parent: BaseStationTile
name: tiles-mining-tile
sprite: /Textures/Tiles/mining_floor.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemMining
- heatCapacity: 10000
- type: tile
id: FloorMiningDark
+ parent: BaseStationTile
name: tiles-mining-dark-tile
sprite: /Textures/Tiles/mining_floor_dark.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemMiningDark
- heatCapacity: 10000
- type: tile
id: FloorMiningLight
+ parent: BaseStationTile
name: tiles-mining-light-tile
sprite: /Textures/Tiles/mining_floor_light.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemMiningLight
- heatCapacity: 10000
# Departmental
- type: tile
id: FloorFreezer
+ parent: BaseStationTile
name: tiles-freezer
sprite: /Textures/Tiles/freezer.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemFreezer
- heatCapacity: 10000
- type: tile
id: FloorShowroom
+ parent: BaseStationTile
name: tiles-showroom-floor
sprite: /Textures/Tiles/showroom.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShowroom
- heatCapacity: 10000
- type: tile
id: FloorHydro
+ parent: BaseStationTile
name: tiles-hydro-floor
sprite: /Textures/Tiles/hydro.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemHydro
- heatCapacity: 10000
- type: tile
id: FloorBar
+ parent: BaseStationTile
name: tiles-bar-floor
sprite: /Textures/Tiles/bar.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemBar
- heatCapacity: 10000
- type: tile
id: FloorClown
+ parent: BaseStationTile
name: tiles-clown-floor
sprite: /Textures/Tiles/clown.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemClown
- heatCapacity: 10000
- type: tile
id: FloorMime
+ parent: BaseStationTile
name: tiles-mime-floor
sprite: /Textures/Tiles/mime.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemMime
- heatCapacity: 10000
- type: tile
id: FloorKitchen
+ parent: BaseStationTile
name: tiles-kitchen-floor
- sprite: /Textures/Tiles/kitchen.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
+ sprite: /Textures/Tiles/kitchen.png
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemKitchen
- heatCapacity: 10000
- type: tile
id: FloorLaundry
+ parent: BaseStationTile
name: tiles-laundry-floor
sprite: /Textures/Tiles/laundry.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemLaundry
- heatCapacity: 10000
- type: tile
id: FloorSteelDamaged
+ parent: BaseStationTile
name: tiles-steel-floor
sprite: /Textures/Tiles/steel_damaged.png
variants: 5
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemSteel #This should probably be made null when it becomes possible to make it such, in SS13 prying destroyed tiles wouldn't give you anything.
- heatCapacity: 10000
# Concrete
- type: tile
id: FloorConcrete
+ parent: BaseStationTile
name: tiles-concrete-tile
sprite: /Textures/Tiles/Planet/Concrete/concrete.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemConcrete
- heatCapacity: 10000
- type: tile
id: FloorConcreteMono
+ parent: BaseStationTile
name: tiles-concrete-slab
sprite: /Textures/Tiles/Planet/Concrete/concrete_mono.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemConcreteMono
- heatCapacity: 10000
- type: tile
id: FloorConcreteSmooth
+ parent: BaseStationTile
name: tiles-concrete-smooth
sprite: /Textures/Tiles/Planet/Concrete/concrete_smooth.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemConcreteSmooth
- heatCapacity: 10000
- type: tile
id: FloorGrayConcrete
+ parent: BaseStationTile
name: tiles-gray-concrete-tile
sprite: /Textures/Tiles/Planet/Concrete/grayconcrete.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemGrayConcrete
- heatCapacity: 10000
- type: tile
id: FloorGrayConcreteMono
+ parent: BaseStationTile
name: tiles-gray-concrete-slab
sprite: /Textures/Tiles/Planet/Concrete/grayconcrete_mono.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemGrayConcreteMono
- heatCapacity: 10000
- type: tile
id: FloorGrayConcreteSmooth
+ parent: BaseStationTile
name: tiles-gray-concrete-smooth
sprite: /Textures/Tiles/Planet/Concrete/grayconcrete_smooth.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemGrayConcreteSmooth
- heatCapacity: 10000
- type: tile
id: FloorOldConcrete
+ parent: BaseStationTile
name: tiles-old-concrete-tile
sprite: /Textures/Tiles/Planet/Concrete/oldconcrete.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemOldConcrete
- heatCapacity: 10000
- type: tile
id: FloorOldConcreteMono
+ parent: BaseStationTile
name: tiles-old-concrete-slab
sprite: /Textures/Tiles/Planet/Concrete/oldconcrete_mono.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemOldConcreteMono
- heatCapacity: 10000
- type: tile
id: FloorOldConcreteSmooth
+ parent: BaseStationTile
name: tiles-old-concrete-smooth
sprite: /Textures/Tiles/Planet/Concrete/oldconcrete_smooth.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemOldConcreteSmooth
- heatCapacity: 10000
# Carpets (non smoothing)
- type: tile
id: FloorArcadeBlue
+ parent: BaseStationTile
name: tiles-blue-arcade-floor
sprite: /Textures/Tiles/arcadeblue.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
friction: 1.25
itemDrop: FloorTileItemArcadeBlue
- heatCapacity: 10000
- type: tile
id: FloorArcadeBlue2
+ parent: BaseStationTile
name: tiles-blue-arcade-floor
sprite: /Textures/Tiles/arcadeblue2.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
friction: 1.25
itemDrop: FloorTileItemArcadeBlue2
- heatCapacity: 10000
- type: tile
id: FloorArcadeRed
+ parent: BaseStationTile
name: tiles-red-arcade-floor
sprite: /Textures/Tiles/arcadered.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
friction: 1.25
itemDrop: FloorTileItemArcadeRed
- heatCapacity: 10000
- type: tile
id: FloorEighties
+ parent: BaseStationTile
name: tiles-eighties-floor
sprite: /Textures/Tiles/eighties.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
friction: 1.25
itemDrop: FloorTileItemEighties
- heatCapacity: 10000
- type: tile
id: FloorCarpetClown
+ parent: BaseStationTile
name: tiles-clown-carpet-floor
sprite: /Textures/Tiles/carpetclown.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
friction: 1.25
itemDrop: FloorTileItemCarpetClown
- heatCapacity: 10000
- type: tile
id: FloorCarpetOffice
+ parent: BaseStationTile
name: tiles-office-carpet-floor
sprite: /Textures/Tiles/carpetoffice.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
friction: 1.25
itemDrop: FloorTileItemCarpetOffice
- heatCapacity: 10000
- type: tile
id: FloorBoxing
+ parent: BaseStationTile
name: tiles-boxing-ring-floor
sprite: /Textures/Tiles/boxing.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
friction: 1.25
itemDrop: FloorTileItemBoxing
- heatCapacity: 10000
- type: tile
id: FloorGym
+ parent: BaseStationTile
name: tiles-gym-floor
sprite: /Textures/Tiles/gym.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
friction: 1.25
itemDrop: FloorTileItemGym
- heatCapacity: 10000
# Shuttle
- type: tile
id: FloorShuttleWhite
+ parent: BaseStationTile
name: tiles-white-shuttle-floor
sprite: /Textures/Tiles/shuttlewhite.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttleWhite
- heatCapacity: 10000
- type: tile
id: FloorShuttleGrey
+ parent: BaseStationTile
name: tiles-grey-shuttle-floor
sprite: /Textures/Tiles/shuttlegrey.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttleGrey
- heatCapacity: 10000
- type: tile
id: FloorShuttleBlack
+ parent: BaseStationTile
name: tiles-black-shuttle-floor
sprite: /Textures/Tiles/shuttleblack.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttleBlack
- heatCapacity: 10000
- type: tile
id: FloorShuttleBlue
+ parent: BaseStationTile
name: tiles-blue-shuttle-floor
sprite: /Textures/Tiles/shuttleblue.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttleBlue
- heatCapacity: 10000
- type: tile
id: FloorShuttleOrange
+ parent: BaseStationTile
name: tiles-orange-shuttle-floor
sprite: /Textures/Tiles/shuttleorange.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttleOrange
- heatCapacity: 10000
- type: tile
id: FloorShuttlePurple
+ parent: BaseStationTile
name: tiles-purple-shuttle-floor
sprite: /Textures/Tiles/shuttlepurple.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttlePurple
- heatCapacity: 10000
- type: tile
id: FloorShuttleRed
+ parent: BaseStationTile
name: tiles-red-shuttle-floor
sprite: /Textures/Tiles/shuttlered.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemShuttleRed
- heatCapacity: 10000
# Materials
- type: tile
id: FloorGold
+ parent: BaseStationTile
name: tiles-gold-tile
sprite: /Textures/Tiles/gold.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemGold
- heatCapacity: 10000
- type: tile
id: FloorSilver
+ parent: BaseStationTile
name: tiles-silver-tile
sprite: /Textures/Tiles/silver.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemSilver
- heatCapacity: 10000
- type: tile
id: FloorGlass
+ parent: BaseStationTile
name: tiles-glass-floor
sprite: /Textures/Tiles/glass.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: SheetGlass1
- heatCapacity: 10000
- type: tile
id: FloorRGlass
+ parent: BaseStationTile
name: tiles-reinforced-glass-floor
sprite: /Textures/Tiles/rglass.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: SheetRGlass1
- heatCapacity: 10000
- type: tile
id: FloorMetalFoam
+ parent: BaseStationTile
name: tiles-metal-foam
sprite: /Textures/Tiles/foammetal.png
variants: 1
placementVariants:
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: SheetSteel1
- heatCapacity: 10000
# Circuits
- type: tile
id: FloorGreenCircuit
+ parent: BaseStationTile
name: tiles-green-circuit-floor
sprite: /Textures/Tiles/green_circuit.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemGCircuit
- heatCapacity: 10000
- type: tile
id: FloorBlueCircuit
+ parent: BaseStationTile
name: tiles-blue-circuit-floor
sprite: /Textures/Tiles/blue_circuit.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemBCircuit
- heatCapacity: 10000
- type: tile
id: FloorRedCircuit
+ parent: BaseStationTile
name: tiles-red-circuit-floor
sprite: /Textures/Tiles/red_circuit.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemRCircuit
- heatCapacity: 10000
# Terrain
- type: tile
sprite: /Textures/Tiles/Asteroid/asteroid.png
variants: 13
placementVariants:
- - 0.8
- - 0.0166 #Should be roughly 20%.... I think??? I don't know dude, I'm just a YAML monkey.
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0166
- - 0.0116
- - 0.0116
+ - 0.8
+ - 0.0166 #Should be roughly 20%.... I think??? I don't know dude, I'm just a YAML monkey.
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0166
+ - 0.0116
+ - 0.0116
baseTurf: Space
isSubfloor: true
footstepSounds:
- type: tile
id: FloorFlesh
+ parent: BaseStationTile
name: tiles-flesh-floor
sprite: /Textures/Tiles/meat.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepBlood
itemDrop: FloorTileItemFlesh
friction: 0.25 #slippy
- heatCapacity: 10000
- type: tile
id: FloorTechMaint2
+ parent: BaseStationTile
name: tiles-techmaint2-floor
sprite: /Textures/Tiles/steel_maint.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemSteelMaint
- heatCapacity: 10000
- type: tile
id: FloorTechMaint3
+ parent: BaseStationTile
name: tiles-techmaint3-floor
sprite: /Textures/Tiles/grating_maint.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemGratingMaint
- heatCapacity: 10000
- type: tile
id: FloorWoodTile
+ parent: BaseStationTile
name: tiles-wood2
sprite: /Textures/Tiles/wood_tile.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepWood
barestepSounds:
collection: BarestepWood
itemDrop: FloorTileItemWoodPattern
- heatCapacity: 10000
- type: tile
id: FloorBrokenWood
+ parent: BaseStationTile
name: tiles-wood3
sprite: /Textures/Tiles/wood_broken.png
variants: 7
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepWood
barestepSounds:
collection: BarestepWood
itemDrop: MaterialWoodPlank1
- heatCapacity: 10000
- type: tile
id: FloorWebTile
+ parent: BaseStationTile
name: tiles-web
sprite: /Textures/Tiles/Misc/Web/web_tile.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepCarpet
barestepSounds:
collection: BarestepCarpet
itemDrop: FloorTileItemWeb
- heatCapacity: 10000
- type: tile
id: FloorChromite
#Hull tiles
- type: tile
id: FloorHull
+ parent: BaseStationTile
name: tiles-hull
sprite: /Textures/Tiles/hull.png
- baseTurf: Plating
- isSubfloor: false
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemSteel #probably should not be normally obtainable, but the game shits itself and dies when you try to put null here
- heatCapacity: 10000
- type: tile
id: FloorHullReinforced
+ parent: BaseStationTile
name: tiles-hull-reinforced
sprite: /Textures/Tiles/hull_reinforced.png
- baseTurf: Plating
- isSubfloor: false
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemSteel
- type: tile
id: FloorReinforcedHardened
+ parent: BaseStationTile
name: tiles-super-reinforced-floor
sprite: /Textures/Tiles/super_reinforced.png
- baseTurf: Plating
- isSubfloor: false
footstepSounds:
collection: FootstepHull
itemDrop: PartRodMetal1 #same case as FloorHull
# Grass
- type: tile
id: FloorAstroGrass
+ parent: BaseStationTile
name: tiles-astro-grass
sprite: /Textures/Tiles/Planet/Grass/grass.png
variants: 4
East: /Textures/Tiles/Planet/Grass/double_edge.png
North: /Textures/Tiles/Planet/Grass/double_edge.png
West: /Textures/Tiles/Planet/Grass/double_edge.png
- baseTurf: Plating
- isSubfloor: false
deconstructTools: [ Cutting ]
footstepSounds:
collection: FootstepGrass
itemDrop: FloorTileItemAstroGrass
- heatCapacity: 10000
- type: tile
id: FloorMowedAstroGrass
+ parent: [ BaseStationTile, FloorGrass ]
name: tiles-mowed-astro-grass
- parent: FloorGrass
- baseTurf: Plating
isSubfloor: false
deconstructTools: [ Cutting ]
itemDrop: FloorTileItemMowedAstroGrass
- type: tile
id: FloorJungleAstroGrass
+ parent: [ BaseStationTile, FloorGrassJungle ]
name: tiles-jungle-astro-grass
- parent: FloorGrassJungle
- baseTurf: Plating
isSubfloor: false
deconstructTools: [ Cutting ]
itemDrop: FloorTileItemJungleAstroGrass
# Ice
- type: tile
id: FloorAstroIce
+ parent: BaseStationTile
name: tiles-astro-ice
sprite: /Textures/Tiles/Planet/Snow/ice.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
friction: 0.05
- heatCapacity: 10000
mobFriction: 0.05
mobAcceleration: 0.1
itemDrop: FloorTileItemAstroIce
- type: tile
id: FloorAstroSnow
+ parent: [ BaseStationTile, FloorSnow ]
name: tiles-astro-snow
- parent: FloorSnow
- baseTurf: Plating
isSubfloor: false
deconstructTools: [ Prying ]
itemDrop: FloorTileItemAstroSnow
# Asteroid Sand
- type: tile
id: FloorAstroAsteroidSand
+ parent: [ BaseStationTile, FloorAsteroidSand ]
name: tiles-astro-asteroid-sand
- parent: FloorAsteroidSand
- baseTurf: Plating
isSubfloor: false
deconstructTools: [ Prying ]
itemDrop: FloorTileItemAstroAsteroidSand
- type: tile
id: FloorAstroAsteroidSandBorderless
+ parent: [ BaseStationTile, FloorAsteroidSandBorderless ]
name: tiles-astro-asteroid-sand-borderless
- parent: FloorAsteroidSandBorderless
- baseTurf: Plating
isSubfloor: false
deconstructTools: [ Prying ]
itemDrop: FloorTileItemAstroAsteroidSand
- type: tile
id: FloorWoodLarge
+ parent: BaseStationTile
name: tiles-wood-large
sprite: /Textures/Tiles/wood_large.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepWood
barestepSounds:
collection: BarestepWood
itemDrop: FloorTileItemWoodLarge
- heatCapacity: 10000
- type: tile
id: FloorXenoborg
- type: tile
id: FloorXeno
+ parent: BaseStationTile
name: tiles-xeno-floor
sprite: /Textures/Tiles/xeno_flooring.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepBlood
itemDrop: FloorTileItemXeno
- heatCapacity: 10000
- type: tile
id: FloorXenoSteel
+ parent: BaseStationTile
name: tiles-xeno-steel
sprite: /Textures/Tiles/xeno_steel.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemXenoSteel
- heatCapacity: 10000
allowRotationMirror: true
- type: tile
id: FloorXenoSteelCorner
+ parent: BaseStationTile
name: tiles-xeno-steel-corner
sprite: /Textures/Tiles/xeno_steel_corner.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
itemDrop: FloorTileItemXenoSteelCorner
- heatCapacity: 10000
allowRotationMirror: true
- type: tile
id: FloorDarkSquiggly
+ parent: BaseStationTile
name: tiles-dark-squiggly
sprite: /Textures/Tiles/dark_squiggly.png
variants: 4
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
- footstepSounds:
- collection: FootstepFloor
itemDrop: FloorTileItemDarkSquiggly
- heatCapacity: 10000
allowRotationMirror: true
- type: tile
id: FloorXenoMaint
+ parent: BaseStationTile
name: tiles-xeno-maint
sprite: /Textures/Tiles/xeno_maint.png
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepHull
itemDrop: FloorTileItemXenoMaint
- heatCapacity: 10000
- type: tile
id: FloorWhiteMarble
+ parent: BaseStationTile
name: tiles-white-marble
sprite: /Textures/Tiles/white_marble.png
variants: 8
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
friction: 0.8
itemDrop: FloorTileItemWhiteMarble
- heatCapacity: 10000
- type: tile
id: FloorDarkMarble
+ parent: BaseStationTile
name: tiles-dark-marble
sprite: /Textures/Tiles/dark_marble.png
variants: 8
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
friction: 0.8
itemDrop: FloorTileItemDarkMarble
- heatCapacity: 10000
- type: tile
id: FloorPlasmaMarble
+ parent: BaseStationTile
name: tiles-plasma-marble
sprite: /Textures/Tiles/plasmarble.png
variants: 8
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
friction: 0.8
itemDrop: FloorTileItemPlasmaMarble
- heatCapacity: 10000
- type: tile
id: FloorUraniumMarble
+ parent: BaseStationTile
name: tiles-uranium-marble
sprite: /Textures/Tiles/uranium_marble.png
variants: 8
- 1.0
- 1.0
- 1.0
- baseTurf: Plating
- isSubfloor: false
- deconstructTools: [ Prying ]
footstepSounds:
collection: FootstepTile
friction: 0.8
itemDrop: FloorTileItemUraniumMarble
- heatCapacity: 10000
+- type: tile
+ id: BaseFloorPlanet
+ abstract: true
+ heatCapacity: 10000
+ isSubfloor: true
+ footstepSounds:
+ collection: FootstepAsteroid
+ weather: true
+ indestructible: true
+
- type: tile
id: FloorPlanetDirt
+ parent: BaseFloorPlanet
name: tiles-dirt-planet-floor
sprite: /Textures/Tiles/Planet/dirt.rsi/dirt.png
variants: 4
- 1.0
- 1.0
- 1.0
- isSubfloor: true
- footstepSounds:
- collection: FootstepAsteroid
- heatCapacity: 10000
- weather: true
- indestructible: true
# Desert
- type: tile
id: FloorDesert
+ parent: BaseFloorPlanet
name: tiles-desert-floor
sprite: /Textures/Tiles/Planet/Desert/desert.png
variants: 6
- 1.0
- 1.0
- 1.0
- isSubfloor: true
- footstepSounds:
- collection: FootstepAsteroid
- heatCapacity: 10000
- weather: true
- indestructible: true
- type: tile
id: FloorLowDesert
- 1.0
- 1.0
- 1.0
- isSubfloor: true
- footstepSounds:
- collection: FootstepAsteroid
- heatCapacity: 10000
- weather: true
- indestructible: true
# Grass
- type: tile
id: FloorPlanetGrass
+ parent: BaseFloorPlanet
name: tiles-grass-planet-floor
sprite: /Textures/Tiles/Planet/Grass/grass.png
variants: 4
North: /Textures/Tiles/Planet/Grass/double_edge.png
West: /Textures/Tiles/Planet/Grass/double_edge.png
baseTurf: FloorPlanetDirt
- isSubfloor: true
footstepSounds:
collection: FootstepGrass
- itemDrop: FloorTileItemGrass
- heatCapacity: 10000
- weather: true
- indestructible: true
# Lava
- type: tile
id: FloorBasalt
name: tiles-basalt-floor
+ parent: BaseFloorPlanet
sprite: /Textures/Tiles/Planet/basalt.png
- isSubfloor: true
- footstepSounds:
- collection: FootstepAsteroid
- heatCapacity: 10000
- weather: true
- indestructible: true
# Snow
- type: tile
id: FloorSnow
+ parent: BaseFloorPlanet
name: tiles-snow
sprite: /Textures/Tiles/Planet/Snow/snow.png
variants: 13
East: /Textures/Tiles/Planet/Snow/snow_double_edge_east.png
North: /Textures/Tiles/Planet/Snow/snow_double_edge_north.png
West: /Textures/Tiles/Planet/Snow/snow_double_edge_west.png
- isSubfloor: true
footstepSounds:
collection: FootstepSnow
- heatCapacity: 10000
- weather: true
- indestructible: true
# Ice
- type: tile
# Dug snow
- type: tile
id: FloorSnowDug
+ parent: BaseFloorPlanet
name: tiles-snow-dug
sprite: /Textures/Tiles/Planet/Snow/snow_dug.png
edgeSpritePriority: 1
East: /Textures/Tiles/Planet/Snow/snow_dug_double_edge_east.png
North: /Textures/Tiles/Planet/Snow/snow_dug_double_edge_north.png
West: /Textures/Tiles/Planet/Snow/snow_dug_double_edge_west.png
- isSubfloor: true
footstepSounds:
collection: FootstepSnow
- heatCapacity: 10000
- weather: true
- indestructible: true
# Wasteland
- type: tile
- id: Plating
- name: tiles-plating
- sprite: /Textures/Tiles/plating.png
- baseTurf: Lattice
+ id: BasePlating
+ abstract: true
+ friction: 1.5
+ heatCapacity: 10000
isSubfloor: true
footstepSounds:
collection: FootstepPlating
- friction: 1.5
- heatCapacity: 10000
+ baseTurf: Lattice
+ baseWhitelist:
+ - TrainLattice
+
+- type: tile
+ id: Plating
+ parent: BasePlating
+ name: tiles-plating
+ sprite: /Textures/Tiles/plating.png
- type: tile
id: PlatingDamaged
+ parent: BasePlating
name: tiles-plating
sprite: /Textures/Tiles/plating_damaged.png
variants: 3
- 1.0
- 1.0
- 1.0
- baseTurf: Lattice
- isSubfloor: true
- footstepSounds:
- collection: FootstepPlating
- friction: 1.5
- heatCapacity: 10000
- type: tile
id: PlatingAsteroid
+ parent: BasePlating
name: tiles-asteroid-plating
sprite: /Textures/Tiles/Asteroid/asteroid_plating.png
- baseTurf: Lattice
- isSubfloor: true
- footstepSounds:
- collection: FootstepPlating
- friction: 1.5
- heatCapacity: 10000
- type: tile
id: PlatingBrass
+ parent: BasePlating
name: tiles-brass-plating
sprite: /Textures/Tiles/Misc/clockwork/clockwork_floor.png
- baseTurf: Lattice
- isSubfloor: true
- footstepSounds:
- collection: FootstepPlating
- friction: 1.5
- heatCapacity: 10000
- type: tile
id: PlatingSnow
name: tiles-snow-plating
+ parent: BasePlating
sprite: /Textures/Tiles/snow_plating.png #Not in the snow planet RSI because it doesn't have any metadata. Should probably be moved to its own folder later.
- baseTurf: Lattice
- isSubfloor: true
- footstepSounds:
- collection: FootstepPlating
friction: 0.75 #a little less then actual snow
- heatCapacity: 10000
- type: tile
id: PlatingIronsand
- type: tile
id: TrainLattice
+ parent: Lattice
name: tiles-lattice-train
sprite: /Textures/Tiles/latticeTrain.png
- baseTurf: Space
- isSubfloor: true
- deconstructTools: [ Cutting ]
- weather: true
footstepSounds:
collection: FootstepPlating
- friction: 1.5
- isSpace: true
- itemDrop: PartRodMetal1
- heatCapacity: 10000
- mass: 200