pEast = Transform.WithEntityId(pEast, MapData.Grid);
pWest = Transform.WithEntityId(pWest, MapData.Grid);
- await SetTile(Plating, SEntMan.GetNetCoordinates(pNorth), MapData.Grid);
- await SetTile(Plating, SEntMan.GetNetCoordinates(pSouth), MapData.Grid);
- await SetTile(Plating, SEntMan.GetNetCoordinates(pEast), MapData.Grid);
+ await SetTile(PlatingRCD, SEntMan.GetNetCoordinates(pNorth), MapData.Grid);
+ await SetTile(PlatingRCD, SEntMan.GetNetCoordinates(pSouth), MapData.Grid);
+ await SetTile(PlatingRCD, SEntMan.GetNetCoordinates(pEast), MapData.Grid);
await SetTile(Lattice, SEntMan.GetNetCoordinates(pWest), MapData.Grid);
Assert.That(ProtoMan.TryIndex(RCDSettingWall, out var settingWall), $"RCDPrototype not found: {RCDSettingWall}.");
// Deconstruct the steel tile.
await Interact(null, pEast);
await RunSeconds(settingDeconstructTile.Delay + 1); // wait for the deconstruction to finish
- await AssertTile(Plating, FromServer(pEast));
+ await AssertTile(PlatingRCD, FromServer(pEast));
// Check that the cost of the deconstruction was subtracted from the current charges.
newCharges = sCharges.GetCurrentCharges(ToServer(rcd));
var tile = _mapSystem.GetTileRef(gridUid.Value, mapGrid, location);
var position = _mapSystem.TileIndicesFor(gridUid.Value, mapGrid, location);
- if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, args.Target, args.User))
+ if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, component.ConstructionDirection, args.Target, args.User))
return;
if (!_net.IsServer)
var tile = _mapSystem.GetTileRef(gridUid.Value, mapGrid, location);
var position = _mapSystem.TileIndicesFor(gridUid.Value, mapGrid, location);
- if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, args.Event.Target, args.Event.User))
+ if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, args.Event.Direction, args.Event.Target, args.Event.User))
args.Cancel();
}
var position = _mapSystem.TileIndicesFor(gridUid.Value, mapGrid, location);
// Ensure the RCD operation is still valid
- if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, args.Target, args.User))
+ if (!IsRCDOperationStillValid(uid, component, gridUid.Value, mapGrid, tile, position, args.Direction, args.Target, args.User))
return;
// Finalize the operation (this should handle prediction properly)
#region Entity construction/deconstruction rule checks
public bool IsRCDOperationStillValid(EntityUid uid, RCDComponent component, EntityUid gridUid, MapGridComponent mapGrid, TileRef tile, Vector2i position, EntityUid? target, EntityUid user, bool popMsgs = true)
+ {
+ return IsRCDOperationStillValid(uid, component, gridUid, mapGrid, tile, position, component.ConstructionDirection, target, user, popMsgs);
+ }
+
+ public bool IsRCDOperationStillValid(EntityUid uid, RCDComponent component, EntityUid gridUid, MapGridComponent mapGrid, TileRef tile, Vector2i position, Direction direction, EntityUid? target, EntityUid user, bool popMsgs = true)
{
var prototype = _protoManager.Index(component.ProtoId);
{
case RcdMode.ConstructTile:
case RcdMode.ConstructObject:
- return IsConstructionLocationValid(uid, component, gridUid, mapGrid, tile, position, user, popMsgs);
+ return IsConstructionLocationValid(uid, component, gridUid, mapGrid, tile, position, direction, user, popMsgs);
case RcdMode.Deconstruct:
return IsDeconstructionStillValid(uid, tile, target, user, popMsgs);
}
return false;
}
- private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, EntityUid gridUid, MapGridComponent mapGrid, TileRef tile, Vector2i position, EntityUid user, bool popMsgs = true)
+ private bool IsConstructionLocationValid(EntityUid uid, RCDComponent component, EntityUid gridUid, MapGridComponent mapGrid, TileRef tile, Vector2i position, Direction direction, EntityUid user, bool popMsgs = true)
{
var prototype = _protoManager.Index(component.ProtoId);
return false;
}
+ var tileDef = _turf.GetContentTileDefinition(tile);
+
+ // Check rule: Respect baseTurf and baseWhitelist
+ if (prototype.Prototype != null && _tileDefMan.TryGetDefinition(prototype.Prototype, out var replacementDef))
+ {
+ var replacementContentDef = (ContentTileDefinition) replacementDef;
+
+ if (replacementContentDef.BaseTurf != tileDef.ID && !replacementContentDef.BaseWhitelist.Contains(tileDef.ID))
+ {
+ if (popMsgs)
+ _popup.PopupClient(Loc.GetString("rcd-component-cannot-build-on-empty-tile-message"), uid, user);
+
+ return false;
+ }
+ }
+
// Check rule: Tiles can't be identical
- if (_turf.GetContentTileDefinition(tile).ID == prototype.Prototype)
+ if (tileDef.ID == prototype.Prototype)
{
if (popMsgs)
_popup.PopupClient(Loc.GetString("rcd-component-cannot-build-identical-tile"), uid, user);
foreach (var ent in _intersectingEntities)
{
+ // If the entity is the exact same prototype as what we are trying to build, then block it.
+ // This is to prevent spamming objects on the same tile (e.g. lights)
+ if (prototype.Prototype != null && MetaData(ent).EntityPrototype?.ID == prototype.Prototype)
+ {
+ var isIdentical = true;
+
+ if (prototype.AllowMultiDirection)
+ {
+ var entDirection = Transform(ent).LocalRotation.GetCardinalDir();
+ if (entDirection != direction)
+ isIdentical = false;
+ }
+
+ if (isIdentical)
+ {
+ if (popMsgs)
+ _popup.PopupClient(Loc.GetString("rcd-component-cannot-build-identical-entity"), uid, user);
+
+ return false;
+ }
+ }
+
if (isWindow && HasComp<SharedCanBuildWindowOnTopComponent>(ent))
continue;
switch (prototype.Mode)
{
case RcdMode.ConstructTile:
- _mapSystem.SetTile(gridUid, mapGrid, position, new Tile(_tileDefMan[prototype.Prototype].TileId));
+ if (!_tileDefMan.TryGetDefinition(prototype.Prototype, out var tileDef))
+ return;
+
+ _tile.ReplaceTile(tile, (ContentTileDefinition) tileDef, gridUid, mapGrid);
_adminLogger.Add(LogType.RCD, LogImpact.High, $"{ToPrettyString(user):user} used RCD to set grid: {gridUid} {position} to {prototype.Prototype}");
break;