private GridCoordinates FindRandomGrid(IMapGrid mapGrid) { // TODO: Need to get valid tiles? (maybe just move right if the tile we chose is invalid?) var randomX = _robustRandom.Next((int)mapGrid.WorldBounds.Left, (int)mapGrid.WorldBounds.Right); var randomY = _robustRandom.Next((int)mapGrid.WorldBounds.Bottom, (int)mapGrid.WorldBounds.Top); return(mapGrid.GridTileToLocal(new MapIndices(randomX, randomY))); }
private void PlaceNewTile(GridCoordinates coordinates, ushort tileType, IMap map, Vector2 position) { // tile can snap up to 0.75m away from grid var gridSearchBox = new Box2(-0.5f, -0.5f, 0.5f, 0.5f) .Scale(1.5f) .Translated(position); var gridsInArea = map.FindGridsIntersecting(gridSearchBox); IMapGrid closest = null; float distance = float.PositiveInfinity; Box2 intersect = new Box2(); foreach (var grid in gridsInArea) { // figure out closest intersect var gridIntersect = gridSearchBox.Intersect(grid.WorldBounds); var gridDist = (gridIntersect.Center - position).LengthSquared; if (gridDist >= distance) { continue; } distance = gridDist; closest = grid; intersect = gridIntersect; } if (closest != null) // stick to existing grid { // round to nearest cardinal dir var normal = new Angle(position - intersect.Center).GetCardinalDir().ToVec(); // round coords to center of tile var tileIndices = closest.WorldToTile(intersect.Center); var tileCenterLocal = closest.GridTileToLocal(tileIndices); var tileCenterWorld = tileCenterLocal.ToWorld(_mapManager).Position; // move mouse one tile out along normal var newTilePos = tileCenterWorld + normal * closest.TileSize; // you can always remove a tile if (Tile.Empty.TypeId != tileType) { var tileBounds = Box2.UnitCentered.Scale(closest.TileSize).Translated(newTilePos); var collideCount = map.FindGridsIntersecting(tileBounds).Count(); // prevent placing a tile if it overlaps more than one grid if (collideCount > 1) { return; } } var pos = closest.WorldToTile(position); closest.SetTile(pos, new Tile(tileType)); } else // create a new grid { var newGrid = map.CreateGrid(); newGrid.WorldPosition = position + (newGrid.TileSize / 2f); // assume bottom left tile origin var tilePos = newGrid.WorldToTile(position); newGrid.SetTile(tilePos, new Tile(tileType)); } }
private bool IsRCDStillValid(AfterInteractEventArgs eventArgs, IMapGrid mapGrid, TileRef tile, MapIndices snapPos, RcdMode startingMode) { //Less expensive checks first. Failing those ones, we need to check that the tile isn't obstructed. if (_ammo <= 0) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"The RCD is out of ammo!"); return(false); } if (_mode != startingMode) { return(false); } var coordinates = mapGrid.GridTileToLocal(tile.GridIndices); if (coordinates == GridCoordinates.InvalidGrid || !InteractionChecks.InRangeUnobstructed(eventArgs)) { return(false); } switch (_mode) { //Floor mode just needs the tile to be a space tile (subFloor) case RcdMode.Floors: if (!tile.Tile.IsEmpty) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"You can only build a floor on space!"); return(false); } return(true); //We don't want to place a space tile on something that's already a space tile. Let's do the inverse of the last check. case RcdMode.Deconstruct: if (tile.Tile.IsEmpty) { return(false); } //They tried to decon a turf but the turf is blocked if (eventArgs.Target == null && tile.IsBlockedTurf(true)) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"That tile is obstructed!"); return(false); } //They tried to decon a non-turf but it's not in the whitelist if (eventArgs.Target != null && !eventArgs.Target.TryGetComponent(out RCDDeconstructWhitelist rcd_decon)) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"You can't deconstruct that!"); return(false); } return(true); //Walls are a special behaviour, and require us to build a new object with a transform rather than setting a grid tile, thus we early return to avoid the tile set code. case RcdMode.Walls: if (tile.Tile.IsEmpty) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"Cannot build a wall on space!"); return(false); } if (tile.IsBlockedTurf(true)) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"That tile is obstructed!"); return(false); } return(true); case RcdMode.Airlock: if (tile.Tile.IsEmpty) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"Cannot build an airlock on space!"); return(false); } if (tile.IsBlockedTurf(true)) { _serverNotifyManager.PopupMessage(Owner, eventArgs.User, $"That tile is obstructed!"); return(false); } return(true); default: return(false); //I don't know why this would happen, but sure I guess. Get out of here invalid state! } }
public override void AlignPlacementMode(ScreenCoordinates mouseScreen) { const float SearchBoxSize = 1.5f; // size of search box in meters MouseCoords = ScreenToCursorGrid(mouseScreen); var mapGrid = pManager.MapManager.GetGrid(MouseCoords.GridID); if (mapGrid.IsDefaultGrid) { // check if we are on an edge of a grid // create a box around the cursor DebugTools.Assert(mapGrid.WorldPosition == Vector2.Zero); // assert that LocalPos == WorldPos var gridSearchBox = Box2.UnitCentered.Scale(SearchBoxSize).Translated(MouseCoords.Position); // find grids in search box var gridsInArea = mapGrid.ParentMap.FindGridsIntersecting(gridSearchBox); // find closest grid intersecting our search box. IMapGrid closest = null; var distance = float.PositiveInfinity; var intersect = new Box2(); foreach (var grid in gridsInArea) { // figure out closest intersect var gridIntersect = gridSearchBox.Intersect(grid.WorldBounds); var gridDist = (gridIntersect.Center - MouseCoords.Position).LengthSquared; if (gridDist >= distance) { continue; } distance = gridDist; closest = grid; intersect = gridIntersect; } if (closest != null) // stick to existing grid { // round to nearest cardinal dir var normal = new Angle(MouseCoords.Position - intersect.Center).GetCardinalDir().ToVec(); // round coords to center of tile var tileIndices = closest.WorldToTile(intersect.Center); var tileCenterLocal = closest.GridTileToLocal(tileIndices); var tileCenterWorld = tileCenterLocal.ToWorld(pManager.MapManager).Position; // move mouse one tile out along normal var newTilePos = tileCenterWorld + normal * closest.TileSize; MouseCoords = new GridCoordinates(closest.WorldToLocal(newTilePos), closest.Index); } //else free place } CurrentTile = mapGrid.GetTileRef(MouseCoords); float tileSize = mapGrid.TileSize; //convert from ushort to float GridDistancing = tileSize; if (pManager.CurrentPermission.IsTile) { if (!mapGrid.IsDefaultGrid) { MouseCoords = new GridCoordinates(CurrentTile.X + tileSize / 2, CurrentTile.Y + tileSize / 2, MouseCoords.GridID); } // else we don't modify coords } else { MouseCoords = new GridCoordinates(CurrentTile.X + tileSize / 2 + pManager.PlacementOffset.X, CurrentTile.Y + tileSize / 2 + pManager.PlacementOffset.Y, MouseCoords.GridID); } }