ETileArea(const BaseStation *st, TileIndex tile, TriggerArea ta) { switch (ta) { default: NOT_REACHED(); case TA_TILE: this->tile = tile; this->w = 1; this->h = 1; break; case TA_PLATFORM: { TileIndex start, end; Axis axis = GetRailStationAxis(tile); TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis)); for (end = tile; IsRailStationTile(end + delta) && IsCompatibleTrainStationTile(end + delta, tile); end += delta) { /* Nothing */ } for (start = tile; IsRailStationTile(start - delta) && IsCompatibleTrainStationTile(start - delta, tile); start -= delta) { /* Nothing */ } this->tile = start; this->w = TileX(end) - TileX(start) + 1; this->h = TileY(end) - TileY(start) + 1; break; } case TA_WHOLE: st->GetTileArea(this, Station::IsExpected(st) ? STATION_RAIL : STATION_WAYPOINT); break; } }
/** * Configure a ViewPort for rendering (a part of) the map into a screenshot. * @param t Screenshot type * @param [out] vp Result viewport */ void SetupScreenshotViewport(ScreenshotType t, ViewPort *vp) { /* Determine world coordinates of screenshot */ if (t == SC_WORLD) { vp->zoom = ZOOM_LVL_WORLD_SCREENSHOT; TileIndex north_tile = _settings_game.construction.freeform_edges ? TileXY(1, 1) : TileXY(0, 0); TileIndex south_tile = MapSize() - 1; /* We need to account for a hill or high building at tile 0,0. */ int extra_height_top = TilePixelHeight(north_tile) + 150; /* If there is a hill at the bottom don't create a large black area. */ int reclaim_height_bottom = TilePixelHeight(south_tile); vp->virtual_left = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, 0).x; vp->virtual_top = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(north_tile) * TILE_SIZE, extra_height_top).y; vp->virtual_width = RemapCoords(TileX(north_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, 0).x - vp->virtual_left + 1; vp->virtual_height = RemapCoords(TileX(south_tile) * TILE_SIZE, TileY(south_tile) * TILE_SIZE, reclaim_height_bottom).y - vp->virtual_top + 1; } else { vp->zoom = (t == SC_ZOOMEDIN) ? _settings_client.gui.zoom_min : ZOOM_LVL_VIEWPORT; Window *w = FindWindowById(WC_MAIN_WINDOW, 0); vp->virtual_left = w->viewport->virtual_left; vp->virtual_top = w->viewport->virtual_top; vp->virtual_width = w->viewport->virtual_width; vp->virtual_height = w->viewport->virtual_height; } /* Compute pixel coordinates */ vp->left = 0; vp->top = 0; vp->width = UnScaleByZoom(vp->virtual_width, vp->zoom); vp->height = UnScaleByZoom(vp->virtual_height, vp->zoom); vp->overlay = NULL; }
/** * Gets the other end of the aqueduct, if possible. * @param tile_from The begin tile for the aqueduct. * @param [out] tile_to The tile till where to show a selection for the aqueduct. * @return The other end of the aqueduct, or otherwise a tile in line with the aqueduct to cause the right error message. */ static TileIndex GetOtherAqueductEnd(TileIndex tile_from, TileIndex *tile_to = NULL) { int z; DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile_from, &z)); /* If the direction isn't right, just return the next tile so the command * complains about the wrong slope instead of the ends not matching up. * Make sure the coordinate is always a valid tile within the map, so we * don't go "off" the map. That would cause the wrong error message. */ if (!IsValidDiagDirection(dir)) return TILE_ADDXY(tile_from, TileX(tile_from) > 2 ? -1 : 1, 0); /* Direction the aqueduct is built to. */ TileIndexDiff offset = TileOffsByDiagDir(ReverseDiagDir(dir)); /* The maximum length of the aqueduct. */ int max_length = min(_settings_game.construction.max_bridge_length, DistanceFromEdgeDir(tile_from, ReverseDiagDir(dir)) - 1); TileIndex endtile = tile_from; for (int length = 0; IsValidTile(endtile) && TileX(endtile) != 0 && TileY(endtile) != 0; length++) { endtile = TILE_ADD(endtile, offset); if (length > max_length) break; if (GetTileMaxZ(endtile) > z) { if (tile_to != NULL) *tile_to = endtile; break; } } return endtile; }
/** * Returns the driveable Trackdirs on a tile. * * One-way-roads are taken into account. Signals are not tested. * * @param dst_tile The tile of interest. * @param src_trackdir The direction the vehicle is currently moving. * @param type The transporttype of the vehicle. * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle. * @return The Trackdirs the vehicle can continue moving on. */ static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype) { TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype)); if (trackdirbits == 0 && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) { /* GetTileTrackStatus() returns 0 for single tram bits. * As we cannot change it there (easily) without breaking something, change it here */ switch (GetSingleTramBit(dst_tile)) { case DIAGDIR_NE: case DIAGDIR_SW: trackdirbits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW; break; case DIAGDIR_NW: case DIAGDIR_SE: trackdirbits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE; break; default: break; } } DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits); /* Select only trackdirs we can reach from our current trackdir */ trackdirbits &= TrackdirReachesTrackdirs(src_trackdir); /* Filter out trackdirs that would make 90 deg turns for trains */ if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir); DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits); return trackdirbits; }
/** Allocates space for a new tile in the matrix. * @param tile Tile to add. */ void AllocateStorage(TileIndex tile) { uint old_left = TileX(this->area.tile) / N; uint old_top = TileY(this->area.tile) / N; uint old_w = this->area.w / N; uint old_h = this->area.h / N; /* Add the square the tile is in to the tile area. We do this * by adding top-left and bottom-right of the square. */ uint grid_x = (TileX(tile) / N) * N; uint grid_y = (TileY(tile) / N) * N; this->area.Add(TileXY(grid_x, grid_y)); this->area.Add(TileXY(grid_x + N - 1, grid_y + N - 1)); /* Allocate new storage. */ T *new_data = CallocT<T>(this->area.w / N * this->area.h / N); if (old_w > 0) { /* Copy old data if present. */ uint offs_x = old_left - TileX(this->area.tile) / N; uint offs_y = old_top - TileY(this->area.tile) / N; for (uint row = 0; row < old_h; row++) { MemCpyT(&new_data[(row + offs_y) * this->area.w / N + offs_x], &this->data[row * old_w], old_w); } } free(this->data); this->data = new_data; }
static Direction ShipGetNewDirectionFromTiles(TileIndex new_tile, TileIndex old_tile) { uint offs = (TileY(new_tile) - TileY(old_tile) + 1) * 4 + TileX(new_tile) - TileX(old_tile) + 1; assert(offs < 11 && offs != 3 && offs != 7); return _new_vehicle_direction_table[offs]; }
/** * Add a single tile to a tile area; enlarge if needed. * @param to_add The tile to add */ void TileArea::Add(TileIndex to_add) { if (this->tile == INVALID_TILE) { this->tile = to_add; this->w = 1; this->h = 1; return; } uint sx = TileX(this->tile); uint sy = TileY(this->tile); uint ex = sx + this->w - 1; uint ey = sy + this->h - 1; uint ax = TileX(to_add); uint ay = TileY(to_add); sx = min(ax, sx); sy = min(ay, sy); ex = max(ax, ex); ey = max(ay, ey); this->tile = TileXY(sx, sy); this->w = ex - sx + 1; this->h = ey - sy + 1; }
/** * Construct the iterator. * @param corner1 Tile from where to begin iterating. * @param corner2 Tile where to end the iterating. */ DiagonalTileIterator::DiagonalTileIterator(TileIndex corner1, TileIndex corner2) : TileIterator(corner2), base_x(TileX(corner2)), base_y(TileY(corner2)), a_cur(0), b_cur(0) { assert(corner1 < MapSize()); assert(corner2 < MapSize()); int dist_x = TileX(corner1) - TileX(corner2); int dist_y = TileY(corner1) - TileY(corner2); this->a_max = dist_x + dist_y; this->b_max = dist_y - dist_x; /* Unfortunately we can't find a new base and make all a and b positive because * the new base might be a "flattened" corner where there actually is no single * tile. If we try anyway the result is either inaccurate ("one off" half of the * time) or the code gets much more complex; * * We also need to increment here to have equality as marker for the end of a row or * column. Like that it's shorter than having another if/else in operator++ */ if (this->a_max > 0) { this->a_max++; } else { this->a_max--; } if (this->b_max > 0) { this->b_max++; } else { this->b_max--; } }
static uint NPFSlopeCost(AyStarNode *current) { TileIndex next = current->tile + TileOffsByDiagDir(TrackdirToExitdir(current->direction)); /* Get center of tiles */ int x1 = TileX(current->tile) * TILE_SIZE + TILE_SIZE / 2; int y1 = TileY(current->tile) * TILE_SIZE + TILE_SIZE / 2; int x2 = TileX(next) * TILE_SIZE + TILE_SIZE / 2; int y2 = TileY(next) * TILE_SIZE + TILE_SIZE / 2; int dx4 = (x2 - x1) / 4; int dy4 = (y2 - y1) / 4; /* Get the height on both sides of the tile edge. * Avoid testing the height on the tile-center. This will fail for halftile-foundations. */ int z1 = GetSlopeZ(x1 + dx4, y1 + dy4); int z2 = GetSlopeZ(x2 - dx4, y2 - dy4); if (z2 - z1 > 1) { /* Slope up */ return _settings_game.pf.npf.npf_rail_slope_penalty; } return 0; /* Should we give a bonus for slope down? Probably not, we * could just substract that bonus from the penalty, because * there is only one level of steepness... */ }
/** * Adds all tiles that incident with the north corner of a specific tile to the "tile_table" in a TerraformerState. * * @param ts TerraformerState. * @param tile Tile. * @ingroup dirty */ static void TerraformAddDirtyTileAround(TerraformerState *ts, TileIndex tile) { /* Make sure all tiles passed to TerraformAddDirtyTile are within [0, MapSize()] */ if (TileY(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY( 0, -1)); if (TileY(tile) >= 1 && TileX(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, -1)); if (TileX(tile) >= 1) TerraformAddDirtyTile(ts, tile + TileDiffXY(-1, 0)); TerraformAddDirtyTile(ts, tile); }
bool StationRect::AfterRemoveRect(BaseStation *st, TileIndex tile, int w, int h) { assert(PtInExtendedRect(TileX(tile), TileY(tile))); assert(PtInExtendedRect(TileX(tile) + w - 1, TileY(tile) + h - 1)); bool empty = this->AfterRemoveTile(st, tile); if (w != 1 || h != 1) empty = empty || AfterRemoveTile(st, TILE_ADDXY(tile, w - 1, h - 1)); return empty; }
bool StationRect::AfterRemoveRect(BaseStation *st, TileArea ta) { assert(this->PtInExtendedRect(TileX(ta.tile), TileY(ta.tile))); assert(this->PtInExtendedRect(TileX(ta.tile) + ta.w - 1, TileY(ta.tile) + ta.h - 1)); bool empty = this->AfterRemoveTile(st, ta.tile); if (ta.w != 1 || ta.h != 1) empty = empty || this->AfterRemoveTile(st, TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1)); return empty; }
/** A small helper function to initialize the terrain */ static void TgenSetTileHeight(TileIndex tile, int height) { SetTileHeight(tile, height); /* Only clear the tiles within the map area. */ if (TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY() && (!_settings_game.construction.freeform_edges || (TileX(tile) != 0 && TileY(tile) != 0))) { MakeClear(tile, CLEAR_GRASS, 3); } }
/** * Gets the distance to the edge of the map in given direction. * @param tile the tile to get the distance from * @param diagdir the direction of interest * @return the distance from the edge in tiles */ uint DistanceFromEdgeDir(TileIndex tile, DiagDirection dir) { switch (dir) { case DIAGDIR_NE: return TileX(tile) - (_settings_game.construction.freeform_edges ? 1 : 0); case DIAGDIR_NW: return TileY(tile) - (_settings_game.construction.freeform_edges ? 1 : 0); case DIAGDIR_SW: return MapMaxX() - TileX(tile) - 1; case DIAGDIR_SE: return MapMaxY() - TileY(tile) - 1; default: NOT_REACHED(); } }
/** * Get top height of the tile inside the map. * @param t Tile to compute height of * @return Maximum height of the tile */ int GetTileMaxZ(TileIndex t) { if (TileX(t) == MapMaxX() || TileY(t) == MapMaxY()) return TileHeightOutsideMap(TileX(t), TileY(t)); int h = TileHeight(t); // N corner h = max<int>(h, TileHeight(t + TileDiffXY(1, 0))); // W corner h = max<int>(h, TileHeight(t + TileDiffXY(0, 1))); // E corner h = max<int>(h, TileHeight(t + TileDiffXY(1, 1))); // S corner return h; }
/** * Construct this tile area based on two points. * @param start the start of the area * @param end the end of the area */ TileArea::TileArea(TileIndex start, TileIndex end) { uint sx = TileX(start); uint sy = TileY(start); uint ex = TileX(end); uint ey = TileY(end); if (sx > ex) Swap(sx, ex); if (sy > ey) Swap(sy, ey); this->tile = TileXY(sx, sy); this->w = ex - sx + 1; this->h = ey - sy + 1; }
static uint32 GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_axis, bool centred) { int tx = TileX(tile); int ty = TileY(tile); int sx = TileX(FindRailStationEnd(tile, TileDiffXY(-1, 0), check_type, check_axis)); int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), check_type, check_axis)); int ex = TileX(FindRailStationEnd(tile, TileDiffXY( 1, 0), check_type, check_axis)) + 1; int ey = TileY(FindRailStationEnd(tile, TileDiffXY( 0, 1), check_type, check_axis)) + 1; tx -= sx; ex -= sx; ty -= sy; ey -= sy; return GetPlatformInfo(GetRailStationAxis(tile), GetStationGfx(tile), ex, ey, tx, ty, centred); }
CommandCost StationRect::BeforeAddTile(TileIndex tile, StationRectMode mode) { int x = TileX(tile); int y = TileY(tile); if (this->IsEmpty()) { /* we are adding the first station tile */ if (mode != ADD_TEST) { this->left = this->right = x; this->top = this->bottom = y; } } else if (!this->PtInExtendedRect(x, y)) { /* current rect is not empty and new point is outside this rect * make new spread-out rectangle */ Rect new_rect = {min(x, this->left), min(y, this->top), max(x, this->right), max(y, this->bottom)}; /* check new rect dimensions against preset max */ int w = new_rect.right - new_rect.left + 1; int h = new_rect.bottom - new_rect.top + 1; if (mode != ADD_FORCE && (w > _settings_game.station.station_spread || h > _settings_game.station.station_spread)) { assert(mode != ADD_TRY); return_cmd_error(STR_ERROR_STATION_TOO_SPREAD_OUT); } /* spread-out ok, return true */ if (mode != ADD_TEST) { /* we should update the station rect */ *this = new_rect; } } else { ; // new point is inside the rect, we don't need to do anything } return CommandCost(); }
/** * Calculates the minimum distance traveled to get from t0 to t1 when only * using tracks (ie, only making 45 degree turns). Returns the distance in the * NPF scale, ie the number of full tiles multiplied by NPF_TILE_LENGTH to * prevent rounding. */ static uint NPFDistanceTrack(TileIndex t0, TileIndex t1) { const uint dx = Delta(TileX(t0), TileX(t1)); const uint dy = Delta(TileY(t0), TileY(t1)); const uint straightTracks = 2 * min(dx, dy); // The number of straight (not full length) tracks /* OPTIMISATION: * Original: diagTracks = max(dx, dy) - min(dx,dy); * Proof: * (dx+dy) - straightTracks == (min + max) - straightTracks = min + max - 2 * min = max - min */ const uint diagTracks = dx + dy - straightTracks; // The number of diagonal (full tile length) tracks. /* Don't factor out NPF_TILE_LENGTH below, this will round values and lose * precision */ return diagTracks * NPF_TILE_LENGTH + straightTracks * NPF_TILE_LENGTH * STRAIGHT_TRACK_LENGTH; }
/* Calcs the heuristic to the target station or tile. For train stations, it * takes into account the direction of approach. */ static int32 NPFCalcStationOrTileHeuristic(AyStar *as, AyStarNode *current, OpenListNode *parent) { NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target; NPFFoundTargetData *ftd = (NPFFoundTargetData*)as->user_path; TileIndex from = current->tile; TileIndex to = fstd->dest_coords; uint dist; /* for train-stations, we are going to aim for the closest station tile */ if (as->user_data[NPF_TYPE] != TRANSPORT_WATER && fstd->station_index != INVALID_STATION) to = CalcClosestStationTile(fstd->station_index, from, fstd->station_type); if (as->user_data[NPF_TYPE] == TRANSPORT_ROAD) { /* Since roads only have diagonal pieces, we use manhattan distance here */ dist = DistanceManhattan(from, to) * NPF_TILE_LENGTH; } else { /* Ships and trains can also go diagonal, so the minimum distance is shorter */ dist = NPFDistanceTrack(from, to); } DEBUG(npf, 4, "Calculating H for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), dist); if (dist < ftd->best_bird_dist) { ftd->best_bird_dist = dist; ftd->best_trackdir = (Trackdir)current->user_data[NPF_TRACKDIR_CHOICE]; } return dist; }
ExtraViewportWindow(WindowDesc *desc, int window_number, TileIndex tile) : Window(desc) { this->InitNested(window_number); NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(WID_EV_VIEWPORT); nvp->InitializeViewport(this, 0, ZOOM_LVL_VIEWPORT); if (_settings_client.gui.zoom_min == ZOOM_LVL_VIEWPORT) this->DisableWidget(WID_EV_ZOOM_IN); Point pt; if (tile == INVALID_TILE) { /* No tile? Use center of main viewport. */ const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); /* center on same place as main window (zoom is maximum, no adjustment needed) */ pt.x = w->viewport->scrollpos_x + w->viewport->virtual_width / 2; pt.y = w->viewport->scrollpos_y + w->viewport->virtual_height / 2; } else { pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile)); } this->viewport->scrollpos_x = pt.x - this->viewport->virtual_width / 2; this->viewport->scrollpos_y = pt.y - this->viewport->virtual_height / 2; this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x; this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; }
ExtraViewportWindow(const WindowDesc *desc, int window_number, TileIndex tile) : Window() { this->InitNested(desc, window_number); NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(EVW_VIEWPORT); nvp->InitializeViewport(this, 0, ZOOM_LVL_NORMAL); this->DisableWidget(EVW_ZOOMIN); Point pt; if (tile == INVALID_TILE) { /* the main window with the main view */ const Window *w = FindWindowById(WC_MAIN_WINDOW, 0); /* center on same place as main window (zoom is maximum, no adjustment needed) */ pt.x = w->viewport->scrollpos_x + w->viewport->virtual_width / 2; pt.y = w->viewport->scrollpos_y + w->viewport->virtual_height / 2; } else { pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile)); } this->viewport->scrollpos_x = pt.x - this->viewport->virtual_width / 2; this->viewport->scrollpos_y = pt.y - this->viewport->virtual_height / 2; this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x; this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y; }
void Load_TOWN() { int index; while ((index = SlIterateArray()) != -1) { Town *t = new (index) Town(); SlObject(t, _town_desc); t->LoadCargoSourceSink(); if (IsSavegameVersionBefore(161)) continue; SlObject(&t->cargo_accepted, GetTileMatrixDesc()); if (t->cargo_accepted.area.w != 0) { uint arr_len = t->cargo_accepted.area.w / AcceptanceMatrix::GRID * t->cargo_accepted.area.h / AcceptanceMatrix::GRID; t->cargo_accepted.data = MallocT<uint32>(arr_len); SlArray(t->cargo_accepted.data, arr_len, SLE_UINT32); /* Rebuild total cargo acceptance. */ UpdateTownCargoTotal(t); } /* Cache the aligned tile index of the centre tile. */ uint town_x = (TileX(t->xy) / AcceptanceMatrix::GRID) * AcceptanceMatrix::GRID; uint town_y = (TileY(t->xy) / AcceptanceMatrix::GRID) * AcceptanceMatrix::GRID; t->xy_aligned= TileXY(town_x, town_y); } }
/** * Callback function for Station::RecomputeIndustriesNear() * Tests whether tile is an industry and possibly adds * the industry to station's industries_near list. * @param ind_tile tile to check * @param user_data pointer to RectAndIndustryVector * @return always false, we want to search all tiles */ static bool FindIndustryToDeliver(TileIndex ind_tile, void *user_data) { /* Only process industry tiles */ if (!IsTileType(ind_tile, MP_INDUSTRY)) return false; RectAndIndustryVector *riv = (RectAndIndustryVector *)user_data; Industry *ind = Industry::GetByTile(ind_tile); /* Don't check further if this industry is already in the list */ if (riv->industries_near->Contains(ind)) return false; /* Only process tiles in the station acceptance rectangle */ int x = TileX(ind_tile); int y = TileY(ind_tile); if (x < riv->rect.left || x > riv->rect.right || y < riv->rect.top || y > riv->rect.bottom) return false; /* Include only industries that can accept cargo */ uint cargo_index; for (cargo_index = 0; cargo_index < lengthof(ind->accepts_cargo); cargo_index++) { if (ind->accepts_cargo[cargo_index] != CT_INVALID) break; } if (cargo_index >= lengthof(ind->accepts_cargo)) return false; *riv->industries_near->Append() = ind; return false; }
/** * Copy and paste heights from one map to another. * * @param src_area Area to read heights from. It consists of tiles, not of tile corners * e.g. if you pass a single tile area then 4 corners will be terraformed. * @param dst_area_north Norhern tile of the area to write heigths at. * @param transformation Transformation to perform on tile indices. * @param height_delta Offset, number of units to add to each height. */ void CopyPasteHeights(const GenericTileArea &src_area, GenericTileIndex dst_area_north, DirTransformation transformation, int height_delta) { /* include also corners at SW and SE edges */ GenericTileArea src_corners(src_area.tile, src_area.w + 1, src_area.h + 1); /* transform the most northern corner */ GenericTileIndex transformed_north_corner = src_corners.TransformedNorth(dst_area_north, transformation); #ifdef WITH_ASSERT { assert(IsValidTileIndex(dst_area_north)); uint x = TileX(dst_area_north); uint y = TileY(dst_area_north); assert(!IsMainMapTile(dst_area_north) || !_settings_game.construction.freeform_edges || (x > 0 && y > 0)); Dimension dst_dim = { src_corners.w, src_corners.h }; dst_dim = TransformDimension(dst_dim, transformation); assert(x + dst_dim.width <= MapSizeX(MapOf(dst_area_north)) && y + dst_dim.height <= MapSizeY(MapOf(dst_area_north))); } #endif /* WITH_ASSERT */ if (IsMainMapTile(dst_area_north)) { HeightsCopyPastingIterator iter(src_corners, AsMainMapTile(transformed_north_corner), transformation, height_delta); TerraformPasteTiles(&iter); } else { for (TransformationTileIteratorT<true, true> iter(src_corners, transformed_north_corner, transformation); IsValidTileIndex(iter); ++iter) { SetTileHeight(iter.DstTile(), TileHeight(iter.SrcTile())); } } }
TileIndex TileAdd(TileIndex tile, TileIndexDiff add, const char *exp, const char *file, int line) { int dx; int dy; uint x; uint y; dx = add & MapMaxX(); if (dx >= (int)MapSizeX() / 2) dx -= MapSizeX(); dy = (add - dx) / (int)MapSizeX(); x = TileX(tile) + dx; y = TileY(tile) + dy; if (x >= MapSizeX() || y >= MapSizeY()) { char buf[512]; snprintf(buf, lengthof(buf), "TILE_ADD(%s) when adding 0x%.4X and 0x%.4X failed", exp, tile, add); #if !defined(_MSC_VER) || defined(WINCE) fprintf(stderr, "%s:%d %s\n", file, line, buf); #else _assert(buf, (char*)file, line); #endif } assert(TileXY(x, y) == TILE_MASK(tile + add)); return TileXY(x, y); }
/** * Place a sign at the given coordinates. Ownership of sign has * no effect whatsoever except for the colour the sign gets for easy recognition, * but everybody is able to rename/remove it. * @param tile tile to place sign at * @param flags type of operation * @param p1 unused * @param p2 unused * @param text unused * @return the cost of this operation or an error */ CommandCost CmdPlaceSign(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { /* Try to locate a new sign */ if (!Sign::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_SIGNS); /* Check sign text length if any */ if (!StrEmpty(text) && Utf8StringLength(text) >= MAX_LENGTH_SIGN_NAME_CHARS) return CMD_ERROR; /* When we execute, really make the sign */ if (flags & DC_EXEC) { Sign *si = new Sign(_current_company); int x = TileX(tile) * TILE_SIZE; int y = TileY(tile) * TILE_SIZE; si->x = x; si->y = y; si->z = GetSlopeZ(x, y); if (!StrEmpty(text)) { si->name = strdup(text); } si->UpdateVirtCoord(); InvalidateWindowData(WC_SIGN_LIST, 0, 0); _new_sign_id = si->index; } return CommandCost(); }
/* * Adds a node from where to start an algorithm. Multiple nodes can be added * if wanted. You should make sure that clear() is called before adding nodes * if the AyStar has been used before (though the normal main loop calls * clear() automatically when the algorithm finishes * g is the cost for starting with this node. */ static void AyStarMain_AddStartNode(AyStar *aystar, AyStarNode *start_node, uint g) { #ifdef AYSTAR_DEBUG printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", TileX(start_node->tile), TileY(start_node->tile), start_node->direction); #endif AyStarMain_OpenList_Add(aystar, NULL, start_node, 0, g); }
/** * Adds a node from where to start an algorithm. Multiple nodes can be added * if wanted. You should make sure that #Clear() is called before adding nodes * if the #AyStar has been used before (though the normal main loop calls * #Clear() automatically when the algorithm finishes. * @param start_node Node to start with. * @param g the cost for starting with this node. */ void AyStar::AddStartNode(AyStarNode *start_node, uint g) { #ifdef AYSTAR_DEBUG printf("[AyStar] Starting A* Algorithm from node (%d, %d, %d)\n", TileX(start_node->tile), TileY(start_node->tile), start_node->direction); #endif this->OpenListAdd(NULL, start_node, 0, g); }
/** * Update the virtual coords needed to draw the waypoint sign. */ void Waypoint::UpdateVirtCoord() { Point pt = RemapCoords2(TileX(this->xy) * TILE_SIZE, TileY(this->xy) * TILE_SIZE); SetDParam(0, this->index); this->sign.UpdatePosition(pt.x, pt.y - 32 * ZOOM_LVL_BASE, STR_VIEWPORT_WAYPOINT); /* Recenter viewport */ InvalidateWindowData(WC_WAYPOINT_VIEW, this->index); }