/** * Finds the distance for the closest tile with water/land given a tile * @param tile the tile to find the distance too * @param water whether to find water or land * @return distance to nearest water (max 0x7F) / land (max 0x1FF; 0x200 if there is no land) */ uint GetClosestWaterDistance(TileIndex tile, bool water) { if (WaterMap.HasTileWaterGround(tile) == water) { return(0); } uint max_dist = (uint)(water ? 0x7F : 0x200); int x = (int)TileX(tile); int y = (int)TileY(tile); uint max_x = MapMaxX(); uint max_y = MapMaxY(); uint min_xy = (uint)(_settings_game.construction.freeform_edges ? 1 : 0); /* go in a 'spiral' with increasing manhattan distance in each iteration */ for (uint dist = 1; dist < max_dist; dist++) { /* next 'diameter' */ y--; /* going counter-clockwise around this square */ for (var dir = (int)DiagDirection.DIAGDIR_BEGIN; dir < (int)DiagDirection.DIAGDIR_END; dir++) { int dx = ddx[dir]; int dy = ddy[dir]; /* each side of this square has length 'dist' */ for (uint a = 0; a < dist; a++) { /* MP_VOID tiles are not checked (interval is [min; max) for IsInsideMM())*/ if (MathFuncs.IsInsideMM(x, min_xy, max_x) && MathFuncs.IsInsideMM(y, min_xy, max_y)) { TileIndex t = TileXY((uint)x, (uint)y); if (WaterMap.HasTileWaterGround(t) == water) { return(dist); } } x += dx; y += dy; } } } if (!water) { /* no land found - is this a water-only map? */ for (TileIndex t = 0; t < MapSize(); t++) { if (!TileMap.IsTileType(t, TileType.MP_VOID) && !TileMap.IsTileType(t, TileType.MP_WATER)) { return(0x1FF); } } } return(max_dist); }
/** * Make the given tile a station tile. * @param t the tile to make a station tile * @param o the owner of the station * @param sid the station to which this tile belongs * @param st the type this station tile * @param section the StationGfx to be used for this tile * @param wc The water class of the station */ public static void MakeStation(this TileIndex t, Owner o, StationID sid, StationType st, byte section, WaterClass wc = WaterClass.WATER_CLASS_INVALID) { TileMap.SetTileType(t, TileType.MP_STATION); TileMap.SetTileOwner(t, o); WaterMap.SetWaterClass(t, wc); Map._m[t].m2 = sid; Map._m[t].m3 = 0; Map._m[t].m4 = 0; Map._m[t].m5 = section; Map._me[t].m6 = BitMath.SB(Map._me[t].m6, 2, 1, 0); Map._me[t].m6 = BitMath.SB(Map._me[t].m6, 3, 3, st); Map._me[t].m7 = 0; }
/** * Clean up unnecessary RoadBits of a planed tile. * @param tile current tile * @param org_rb planed RoadBits * @return optimised RoadBits */ RoadBits CleanUpRoadBits(TileIndex tile, RoadBits org_rb) { if (!TileMap.IsValidTile(tile)) { return(RoadBits.ROAD_NONE); } for (DiagDirection dir = DiagDirection.DIAGDIR_BEGIN; dir < DiagDirection.DIAGDIR_END; dir++) { TileIndex neighbor_tile = TileAddByDiagDir(tile, dir); /* Get the Roadbit pointing to the neighbor_tile */ RoadBits target_rb = DiagDirToRoadBits(dir); /* If the roadbit is in the current plan */ if (org_rb & target_rb) { bool connective = false; const RoadBits mirrored_rb = MirrorRoadBits(target_rb); if (TileMap.IsValidTile(neighbor_tile)) { switch (TileMap.GetTileType(neighbor_tile)) { /* Always connective ones */ case TileType.MP_CLEAR: case TileType.MP_TREES: connective = true; break; /* The conditionally connective ones */ case TileType.MP_TUNNELBRIDGE: case TileType.MP_STATION: case TileType.MP_ROAD: if (IsNormalRoadTile(neighbor_tile)) { /* Always connective */ connective = true; } else { const RoadBits neighbor_rb = GetAnyRoadBits(neighbor_tile, RoadType.ROADTYPE_ROAD) | GetAnyRoadBits(neighbor_tile, RoadType.ROADTYPE_TRAM); /* Accept only connective tiles */ connective = (neighbor_rb & mirrored_rb) != RoadBits.ROAD_NONE; } break; case TileType.MP_RAILWAY: connective = IsPossibleCrossing(neighbor_tile, DiagDirToAxis(dir)); break; case TileType.MP_WATER: /* Check for real water tile */ connective = !WaterMap.IsWater(neighbor_tile); break; /* The definitely not connective ones */ default: break; } } /* If the neighbor tile is inconnective, remove the planed road connection to it */ if (!connective) { org_rb ^= target_rb; } } } return(org_rb); }