# HG changeset patch # User rubidium # Date 2009-07-22 08:59:57 # Node ID a7cb564c6c56bff93d381958c76c7342ad2f67f9 # Parent 548f0e01a73859cbe570efc93db6235905c573ae (svn r16909) -Fix [FS#2996]: NewGRF stations would be triggering assertions all over the place when using the more advanced station types. -Change: make (rail) waypoints sub classes of 'base stations', make buoys waypoints and unify code between them where possible. diff --git a/src/ai/api/ai_buoylist.cpp b/src/ai/api/ai_buoylist.cpp --- a/src/ai/api/ai_buoylist.cpp +++ b/src/ai/api/ai_buoylist.cpp @@ -3,12 +3,12 @@ /** @file ai_buoylist.cpp Implementation of AIBuoyList and friends. */ #include "ai_buoylist.hpp" -#include "../../station_base.h" +#include "../../waypoint.h" AIBuoyList::AIBuoyList() { - Station *st; - FOR_ALL_STATIONS(st) { - if (st->IsBuoy()) this->AddItem(st->xy); + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { + if (wp->facilities & FACIL_DOCK) this->AddItem(wp->xy); } } diff --git a/src/ai/api/ai_order.cpp b/src/ai/api/ai_order.cpp --- a/src/ai/api/ai_order.cpp +++ b/src/ai/api/ai_order.cpp @@ -25,18 +25,14 @@ static OrderType GetOrderTypeByTile(Tile switch (::GetTileType(t)) { default: break; case MP_STATION: + if (IsBuoy(t) || IsRailWaypoint(t)) return OT_GOTO_WAYPOINT; if (IsHangar(t)) return OT_GOTO_DEPOT; - if (IsBuoy(t)) return OT_GOTO_WAYPOINT; return OT_GOTO_STATION; break; case MP_WATER: if (::IsShipDepot(t)) return OT_GOTO_DEPOT; break; case MP_ROAD: if (::GetRoadTileType(t) == ROAD_TILE_DEPOT) return OT_GOTO_DEPOT; break; case MP_RAILWAY: - switch (::GetRailTileType(t)) { - case RAIL_TILE_DEPOT: return OT_GOTO_DEPOT; - case RAIL_TILE_WAYPOINT: return OT_GOTO_WAYPOINT; - default: break; - } + if (IsRailDepot(t)) return OT_GOTO_DEPOT; break; } @@ -359,7 +355,7 @@ static const Order *ResolveOrder(Vehicle break; case OT_GOTO_WAYPOINT: - order.MakeGoToWaypoint(::Vehicle::Get(vehicle_id)->type == VEH_TRAIN ? ::GetWaypointIndex(destination) : ::GetStationIndex(destination)); + order.MakeGoToWaypoint(::GetStationIndex(destination)); break; default: diff --git a/src/ai/api/ai_rail.cpp b/src/ai/api/ai_rail.cpp --- a/src/ai/api/ai_rail.cpp +++ b/src/ai/api/ai_rail.cpp @@ -45,7 +45,7 @@ { if (!::IsValidTile(tile)) return false; - return ::IsTileType(tile, MP_RAILWAY) && ::IsRailWaypointTile(tile); + return ::IsRailWaypointTile(tile); } /* static */ bool AIRail::IsRailTypeAvailable(RailType rail_type) @@ -200,8 +200,7 @@ { if (!IsRailTile(tile)) return RAILTRACK_INVALID; - if (IsRailWaypointTile(tile)) return ::GetRailWaypointBits(tile); - if (IsRailStationTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile)); + if (IsRailStationTile(tile) || IsRailWaypointTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile)); if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile); if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE; return ::GetTrackBits(tile); diff --git a/src/ai/api/ai_waypoint.cpp b/src/ai/api/ai_waypoint.cpp --- a/src/ai/api/ai_waypoint.cpp +++ b/src/ai/api/ai_waypoint.cpp @@ -22,7 +22,7 @@ { if (!AIRail::IsRailWaypointTile(tile)) return WAYPOINT_INVALID; - return ::GetWaypointIndex(tile); + return ::GetStationIndex(tile); } /* static */ char *AIWaypoint::GetName(WaypointID waypoint_id) diff --git a/src/ai/api/ai_waypointlist.cpp b/src/ai/api/ai_waypointlist.cpp --- a/src/ai/api/ai_waypointlist.cpp +++ b/src/ai/api/ai_waypointlist.cpp @@ -13,7 +13,7 @@ AIWaypointList::AIWaypointList() { const Waypoint *wp; FOR_ALL_WAYPOINTS(wp) { - if (wp->owner == _current_company) this->AddItem(wp->index); + if (wp->facilities & FACIL_TRAIN && wp->owner == _current_company) this->AddItem(wp->index); } } diff --git a/src/date.cpp b/src/date.cpp --- a/src/date.cpp +++ b/src/date.cpp @@ -154,7 +154,6 @@ Date ConvertYMDToDate(Year year, Month m /** Functions used by the IncreaseDate function */ -extern void WaypointsDailyLoop(); extern void EnginesDailyLoop(); extern void DisasterDailyLoop(); extern void IndustryDailyLoop(); @@ -222,7 +221,6 @@ void IncreaseDate() #endif /* ENABLE_NETWORK */ DisasterDailyLoop(); - WaypointsDailyLoop(); IndustryDailyLoop(); if (_game_mode != GM_MENU) { diff --git a/src/elrail.cpp b/src/elrail.cpp --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -81,8 +81,6 @@ static TrackBits GetRailTrackBitsUnivers switch (GetRailTileType(t)) { case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS: return GetTrackBits(t); - case RAIL_TILE_WAYPOINT: - return GetRailWaypointBits(t); default: return TRACK_BIT_NONE; } @@ -101,7 +99,7 @@ static TrackBits GetRailTrackBitsUnivers return GetCrossingRailBits(t); case MP_STATION: - if (!IsRailwayStation(t)) return TRACK_BIT_NONE; + if (!IsRailwayStation(t) && !IsRailWaypoint(t)) return TRACK_BIT_NONE; if (!HasCatenary(GetRailType(t))) return TRACK_BIT_NONE; if (!IsStationTileElectrifiable(t)) return TRACK_BIT_NONE; return TrackToTrackBits(GetRailStationTrack(t)); diff --git a/src/lang/english.txt b/src/lang/english.txt --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1185,8 +1185,10 @@ STR_HEADING_FOR_WAYPOINT_VEL STR_GO_TO_WAYPOINT :Go via {WAYPOINT} STR_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT} -STR_WAYPOINTNAME_CITY :Waypoint {TOWN} -STR_WAYPOINTNAME_CITY_SERIAL :Waypoint {TOWN} #{COMMA} +STR_WAYPOINTNAME_CITY :{TOWN} Waypoint +STR_WAYPOINTNAME_CITY_SERIAL :{TOWN} Waypoint #{COMMA} +STR_BUOYNAME_CITY :{TOWN} Buoy +STR_BUOYNAME_CITY_SERIAL :{TOWN} Buoy #{COMMA} STR_LANDINFO_WAYPOINT :Waypoint STR_WAYPOINT :{WHITE}Waypoint @@ -2077,15 +2079,9 @@ STR_SV_STNAME_AIRPORT STR_SV_STNAME_OILFIELD :{STRING1} Oilfield STR_SV_STNAME_MINES :{STRING1} Mines STR_SV_STNAME_DOCKS :{STRING1} Docks -STR_SV_STNAME_BUOY_1 :{STRING1} Buoy 1 -STR_SV_STNAME_BUOY_2 :{STRING1} Buoy 2 -STR_SV_STNAME_BUOY_3 :{STRING1} Buoy 3 -STR_SV_STNAME_BUOY_4 :{STRING1} Buoy 4 -STR_SV_STNAME_BUOY_5 :{STRING1} Buoy 5 -STR_SV_STNAME_BUOY_6 :{STRING1} Buoy 6 -STR_SV_STNAME_BUOY_7 :{STRING1} Buoy 7 -STR_SV_STNAME_BUOY_8 :{STRING1} Buoy 8 -STR_SV_STNAME_BUOY_9 :{STRING1} Buoy 9 +STR_SV_STNAME_BUOY :{STRING2} +STR_SV_STNAME_WAYPOINT :{STRING2} +##id 0x6020 STR_SV_STNAME_ANNEXE :{STRING1} Annexe STR_SV_STNAME_SIDINGS :{STRING1} Sidings STR_SV_STNAME_BRANCH :{STRING1} Branch diff --git a/src/misc.cpp b/src/misc.cpp --- a/src/misc.cpp +++ b/src/misc.cpp @@ -31,7 +31,6 @@ extern TileIndex _cur_tileloop_tile; extern void MakeNewgameSettingsLive(); void InitializeVehicles(); -void InitializeWaypoints(); void InitializeDepots(); void InitializeEngineRenews(); void InitializeOrders(); @@ -79,7 +78,6 @@ void InitializeGame(uint size_x, uint si InitializeEngineRenews(); InitializeVehicles(); - InitializeWaypoints(); InitializeDepots(); InitializeOrders(); InitializeGroup(); diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -272,30 +272,20 @@ uint32 GetPlatformInfo(Axis axis, byte t */ static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis) { - bool waypoint; byte orig_type = 0; Axis orig_axis = AXIS_X; - - waypoint = IsTileType(tile, MP_RAILWAY); + StationID sid = GetStationIndex(tile); - if (waypoint) { - if (check_axis) orig_axis = GetWaypointAxis(tile); - } else { - if (check_type) orig_type = GetCustomStationSpecIndex(tile); - if (check_axis) orig_axis = GetRailStationAxis(tile); - } + if (check_type) orig_type = GetCustomStationSpecIndex(tile); + if (check_axis) orig_axis = GetRailStationAxis(tile); while (true) { TileIndex new_tile = TILE_ADD(tile, delta); - if (waypoint) { - if (!IsRailWaypointTile(new_tile)) break; - if (check_axis && GetWaypointAxis(new_tile) != orig_axis) break; - } else { - if (!IsRailwayStationTile(new_tile)) break; - if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break; - if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break; - } + if (!IsTileType(new_tile, MP_STATION) || GetStationIndex(new_tile) != sid) break; + if (!IsRailwayStation(new_tile) && !IsRailWaypoint(new_tile)) break; + if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break; + if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break; tile = new_tile; } @@ -311,12 +301,11 @@ static uint32 GetPlatformInfoHelper(Tile 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; - Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile); tx -= sx; ex -= sx; ty -= sy; ey -= sy; - return GetPlatformInfo(axis, IsTileType(tile, MP_RAILWAY) ? 2 : GetStationGfx(tile), ex, ey, tx, ty, centred); + return GetPlatformInfo(GetRailStationAxis(tile), GetStationGfx(tile), ex, ey, tx, ty, centred); } @@ -330,7 +319,7 @@ static uint32 GetRailContinuationInfo(Ti static const Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N }; static const DiagDirection y_exits[8] = { DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NW, DIAGDIR_SE, DIAGDIR_NW }; - Axis axis = IsTileType(tile, MP_RAILWAY) ? GetWaypointAxis(tile) : GetRailStationAxis(tile); + Axis axis = GetRailStationAxis(tile); /* Choose appropriate lookup table to use */ const Direction *dir = axis == AXIS_X ? x_dir : y_dir; @@ -450,12 +439,7 @@ static uint32 StationGetVariable(const R case 0x42: return GetTerrainType(tile) | (GetRailType(tile) << 8); case 0x43: return st->owner; // Station owner - case 0x44: - if (IsRailWaypointTile(tile)) { - return HasDepotReservation(tile) ? 7 : 4; - } else { - return HasStationReservation(tile) ? 7 : 4; // PBS status - } + case 0x44: return HasStationReservation(tile) ? 7 : 4; // PBS status case 0x45: if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(tile); SetBit(_svc.valid, 2); } return _svc.v45; @@ -583,7 +567,7 @@ uint32 Waypoint::GetNewGRFVariable(const { switch (variable) { case 0x48: return 0; // Accepted cargo types - case 0x8A: return HVOT_TRAIN; + case 0x8A: return HVOT_WAYPOINT; case 0xF1: return 0; // airport type case 0xF2: return 0; // truck stop status case 0xF3: return 0; // bus stop status @@ -944,20 +928,11 @@ bool DrawStationTile(int x, int y, RailT const StationSpec *GetStationSpec(TileIndex t) { - if (IsRailwayStationTile(t)) { - if (!IsCustomStationSpecIndex(t)) return NULL; + if (!IsCustomStationSpecIndex(t)) return NULL; - const BaseStation *st = BaseStation::GetByTile(t); - uint specindex = GetCustomStationSpecIndex(t); - return specindex < st->num_specs ? st->speclist[specindex].spec : NULL; - } - - if (IsRailWaypointTile(t)) { - const BaseStation *st = BaseStation::GetByTile(t); - return st->num_specs != 0 ? st->speclist[1].spec : NULL; - } - - return NULL; + const BaseStation *st = BaseStation::GetByTile(t); + uint specindex = GetCustomStationSpecIndex(t); + return specindex < st->num_specs ? st->speclist[specindex].spec : NULL; } diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -542,18 +542,19 @@ CommandCost CmdInsertOrder(TileIndex til } case OT_GOTO_WAYPOINT: { + const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination()); + if (wp == NULL) return CMD_ERROR; + switch (v->type) { default: return CMD_ERROR; - case VEH_TRAIN: { - const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination()); - if (wp == NULL || !CheckOwnership(wp->owner)) return CMD_ERROR; - } break; + case VEH_TRAIN: + if (!CheckOwnership(wp->owner)) return CMD_ERROR; + break; - case VEH_SHIP: { - const Station *st = Station::GetIfValid(new_order.GetDestination()); - if (st == NULL || (!CheckOwnership(st->owner) && st->owner != OWNER_NONE)) return CMD_ERROR; - } break; + case VEH_SHIP: + if (!CheckOwnership(wp->owner) && wp->owner != OWNER_NONE) return CMD_ERROR; + break; } /* Order flags can be any of the following for waypoints: diff --git a/src/order_gui.cpp b/src/order_gui.cpp --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -253,15 +253,8 @@ void DrawOrderString(const Vehicle *v, c break; case OT_GOTO_WAYPOINT: - if (v->type == VEH_TRAIN) { - SetDParam(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT); - SetDParam(2, order->GetDestination()); - } else { - SetDParam(1, STR_GO_TO_STATION); - SetDParam(2, STR_ORDER_GO_VIA); - SetDParam(3, order->GetDestination()); - SetDParam(4, STR_EMPTY); - } + SetDParam(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT); + SetDParam(2, order->GetDestination()); break; case OT_CONDITIONAL: @@ -357,7 +350,7 @@ static Order GetOrderCmdFromTile(const V return order; } - if (IsBuoyTile(tile) && v->type == VEH_SHIP) { + if ((IsBuoyTile(tile) && v->type == VEH_SHIP) || (IsRailWaypointTile(tile) && v->type == VEH_TRAIN)) { order.MakeGoToWaypoint(GetStationIndex(tile)); return order; } @@ -775,12 +768,9 @@ public: this->SetWidgetLoweredState(ORDER_WIDGET_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); switch (order->GetType()) { case OT_GOTO_STATION: - if (!Station::Get(order->GetDestination())->IsBuoy()) { - this->SetWidgetLoweredState(ORDER_WIDGET_FULL_LOAD, order->GetLoadType() == OLF_FULL_LOAD_ANY); - this->SetWidgetLoweredState(ORDER_WIDGET_UNLOAD, order->GetUnloadType() == OUFB_UNLOAD); - break; - } - /* Fall-through */ + this->SetWidgetLoweredState(ORDER_WIDGET_FULL_LOAD, order->GetLoadType() == OLF_FULL_LOAD_ANY); + this->SetWidgetLoweredState(ORDER_WIDGET_UNLOAD, order->GetUnloadType() == OUFB_UNLOAD); + break; case OT_GOTO_WAYPOINT: this->DisableWidget(ORDER_WIDGET_FULL_LOAD_DROPDOWN); diff --git a/src/pbs.cpp b/src/pbs.cpp --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -26,7 +26,7 @@ TrackBits GetReservedTrackbits(TileIndex break; case MP_STATION: - if (IsRailwayStation(t)) return GetStationReservationTrackBits(t); + if (IsRailwayStation(t) || IsRailWaypoint(t)) return GetStationReservationTrackBits(t); break; case MP_TUNNELBRIDGE: @@ -99,7 +99,7 @@ bool TryReserveRailTrack(TileIndex tile, break; case MP_STATION: - if (IsRailwayStation(tile) && !HasStationReservation(tile)) { + if ((IsRailwayStation(tile) || IsRailWaypoint(tile)) && !HasStationReservation(tile)) { SetRailwayStationReservation(tile, true); MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track return true; @@ -150,7 +150,7 @@ bool TryReserveRailTrack(TileIndex tile, break; case MP_STATION: - if (IsRailwayStation(tile)) { + if (IsRailwayStation(tile) || IsRailWaypoint(tile)) { SetRailwayStationReservation(tile, false); MarkTileDirtyByTile(tile); } diff --git a/src/rail.cpp b/src/rail.cpp --- a/src/rail.cpp +++ b/src/rail.cpp @@ -155,7 +155,7 @@ RailType GetTileRailType(TileIndex tile) break; case MP_STATION: - if (IsRailwayStationTile(tile)) return GetRailType(tile); + if (IsRailwayStation(tile) || IsRailWaypoint(tile)) return GetRailType(tile); break; case MP_TUNNELBRIDGE: diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1281,7 +1281,7 @@ CommandCost CmdConvertRail(TileIndex til case MP_RAILWAY: break; case MP_STATION: - if (!IsRailwayStation(tile)) continue; + if (!IsRailwayStation(tile) && !IsRailWaypoint(tile)) continue; break; case MP_ROAD: if (!IsLevelCrossing(tile)) continue; @@ -1329,14 +1329,6 @@ CommandCost CmdConvertRail(TileIndex til switch (tt) { case MP_RAILWAY: switch (GetRailTileType(tile)) { - case RAIL_TILE_WAYPOINT: - if (flags & DC_EXEC) { - /* notify YAPF about the track layout change */ - YapfNotifyTrackLayoutChange(tile, GetRailWaypointTrack(tile)); - } - cost.AddCost(RailConvertCost(type, totype)); - break; - case RAIL_TILE_DEPOT: if (flags & DC_EXEC) { /* notify YAPF about the track layout change */ @@ -1501,9 +1493,6 @@ static CommandCost ClearTile_Track(TileI case RAIL_TILE_DEPOT: return RemoveTrainDepot(tile, flags); - case RAIL_TILE_WAYPOINT: - return RemoveTrainWaypoint(tile, flags, false); - default: return CMD_ERROR; } @@ -1906,7 +1895,7 @@ static void DrawTile_Track(TileInfo *ti) if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails); } else { - /* draw depot/waypoint */ + /* draw depot */ const DrawTileSprites *dts; const DrawTileSeqStruct *dtss; uint32 relocation; @@ -1914,78 +1903,37 @@ static void DrawTile_Track(TileInfo *ti) if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); - if (IsRailDepot(ti->tile)) { - if (IsInvisibilitySet(TO_BUILDINGS)) { - /* Draw rail instead of depot */ - dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)]; - } else { - dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)]; - } - - relocation = rti->total_offset; - - image = dts->ground.sprite; - if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset; - - /* adjust ground tile for desert - * don't adjust for snow, because snow in depots looks weird */ - if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) { - if (image != SPR_FLAT_GRASS_TILE) { - image += rti->snow_offset; // tile with tracks - } else { - image = SPR_FLAT_SNOWY_TILE; // flat ground - } - } + if (IsInvisibilitySet(TO_BUILDINGS)) { + /* Draw rail instead of depot */ + dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)]; } else { - /* look for customization */ - const StationSpec *statspec = GetStationSpec(ti->tile); - - if (statspec != NULL) { - const BaseStation *st = BaseStation::GetByTile(ti->tile); - uint gfx = 2; - - if (HasBit(statspec->callbackmask, CBM_STATION_SPRITE_LAYOUT)) { - uint16 callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile); - if (callback != CALLBACK_FAILED) gfx = callback; - } - - if (statspec->renderdata == NULL) { - dts = GetStationTileLayout(STATION_RAIL, gfx); - } else { - dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)]; - } - - if (dts != NULL && dts->seq != NULL) { - relocation = GetCustomStationRelocation(statspec, st, ti->tile); - - image = dts->ground.sprite; - if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) { - image += GetCustomStationGroundRelocation(statspec, st, ti->tile); - image += rti->custom_ground_offset; - } else { - image += rti->total_offset; - } - - pal = dts->ground.pal; - } else { - goto default_waypoint; - } + dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)]; + } + + relocation = rti->total_offset; + + image = dts->ground.sprite; + if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset; + + /* adjust ground tile for desert + * don't adjust for snow, because snow in depots looks weird */ + if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) { + if (image != SPR_FLAT_GRASS_TILE) { + image += rti->snow_offset; // tile with tracks } else { -default_waypoint: - /* There is no custom layout, fall back to the default graphics */ - dts = GetStationTileLayout(STATION_WAYPOINT, GetWaypointAxis(ti->tile)); - relocation = 0; - image = dts->ground.sprite + rti->total_offset; - if (IsSnowRailGround(ti->tile)) image += rti->snow_offset; + image = SPR_FLAT_SNOWY_TILE; // flat ground } } DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette)); /* PBS debugging, draw reserved tracks darker */ - if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile) && - (!IsRailDepot(ti->tile) || GetRailDepotDirection(ti->tile) == DIAGDIR_SW || GetRailDepotDirection(ti->tile) == DIAGDIR_SE)) { - DrawGroundSprite(GetWaypointAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH); + if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile)) { + switch (GetRailDepotDirection(ti->tile)) { + case DIAGDIR_SW: DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); break; + case DIAGDIR_SE: DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH); break; + default: break; + } } if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti); @@ -2292,10 +2240,6 @@ static TrackStatus GetTileTrackStatus_Tr trackbits = DiagDirToDiagTrackBits(dir); break; } - - case RAIL_TILE_WAYPOINT: - trackbits = GetRailWaypointBits(tile); - break; } return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals); @@ -2303,11 +2247,10 @@ static TrackStatus GetTileTrackStatus_Tr static bool ClickTile_Track(TileIndex tile) { - switch (GetRailTileType(tile)) { - case RAIL_TILE_DEPOT: ShowDepotWindow(tile, VEH_TRAIN); return true; - case RAIL_TILE_WAYPOINT: ShowWaypointWindow(Waypoint::GetByTile(tile)); return true; - default: return false; - } + if (!IsRailDepot(tile)) return false; + + ShowDepotWindow(tile, VEH_TRAIN); + return true; } static void GetTileDesc_Track(TileIndex tile, TileDesc *td) @@ -2387,10 +2330,8 @@ static void GetTileDesc_Track(TileIndex td->str = STR_RAILROAD_TRAIN_DEPOT; break; - case RAIL_TILE_WAYPOINT: default: - td->str = STR_LANDINFO_WAYPOINT; - break; + NOT_REACHED(); } } @@ -2579,22 +2520,9 @@ static CommandCost TerraformTile_Track(T /* allow terraforming */ return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price.clear_water : (Money)0); - } else { - if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) { - switch (GetRailTileType(tile)) { - case RAIL_TILE_WAYPOINT: { - CommandCost cost = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, GetRailWaypointBits(tile)); - if (!CmdFailed(cost)) return cost; // allow autoslope - break; - } - - case RAIL_TILE_DEPOT: - if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform); - break; - - default: NOT_REACHED(); - } - } + } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() && + AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) { + return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform); } return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); } diff --git a/src/rail_map.h b/src/rail_map.h --- a/src/rail_map.h +++ b/src/rail_map.h @@ -18,7 +18,6 @@ enum RailTileType { RAIL_TILE_NORMAL = 0, ///< Normal rail tile without signals RAIL_TILE_SIGNALS = 1, ///< Normal rail tile with signals - RAIL_TILE_WAYPOINT = 2, ///< Waypoint (X or Y direction) RAIL_TILE_DEPOT = 3, ///< Depot (one entrance) }; @@ -83,27 +82,6 @@ static inline void SetHasSignals(TileInd } /** - * Is this rail tile a rail waypoint? - * @param t the tile to get the information from - * @pre IsTileType(t, MP_RAILWAY) - * @return true if and only if the tile is a rail waypoint - */ -static inline bool IsRailWaypoint(TileIndex t) -{ - return GetRailTileType(t) == RAIL_TILE_WAYPOINT; -} - -/** - * Is this tile rail tile and a rail waypoint? - * @param t the tile to get the information from - * @return true if and only if the tile is a rail waypoint - */ -static inline bool IsRailWaypointTile(TileIndex t) -{ - return IsTileType(t, MP_RAILWAY) && IsRailWaypoint(t); -} - -/** * Is this rail tile a rail depot? * @param t the tile to get the information from * @pre IsTileType(t, MP_RAILWAY) @@ -203,51 +181,6 @@ static inline Track GetRailDepotTrack(Ti /** - * Returns the axis of the waypoint - * @param t the tile to get the waypoint axis from - * @pre IsRailWaypointTile(t) - * @return the axis of the waypoint - */ -static inline Axis GetWaypointAxis(TileIndex t) -{ - return (Axis)GB(_m[t].m5, 0, 1); -} - -/** - * Returns the track of the waypoint - * @param t the tile to get the waypoint track from - * @pre IsRailWaypointTile(t) - * @return the track of the waypoint - */ -static inline Track GetRailWaypointTrack(TileIndex t) -{ - return AxisToTrack(GetWaypointAxis(t)); -} - -/** - * Returns the track bits of the waypoint - * @param t the tile to get the waypoint track bits from - * @pre IsRailWaypointTile(t) - * @return the track bits of the waypoint - */ -static inline TrackBits GetRailWaypointBits(TileIndex t) -{ - return TrackToTrackBits(GetRailWaypointTrack(t)); -} - -/** - * Returns waypoint index (for the waypoint pool) - * @param t the tile to get the waypoint index from - * @pre IsRailWaypointTile(t) - * @return the waypoint index - */ -static inline WaypointID GetWaypointIndex(TileIndex t) -{ - return (WaypointID)_m[t].m2; -} - - -/** * Returns the reserved track bits of the tile * @pre IsPlainRailTile(t) * @param t the tile to query @@ -336,17 +269,6 @@ static inline void SetDepotReservation(T } /** - * Get the reserved track bits for a waypoint - * @pre IsRailWaypoint(t) - * @param t the tile - * @return reserved track bits - */ -static inline TrackBits GetWaypointReservationTrackBits(TileIndex t) -{ - return HasDepotReservation(t) ? GetRailWaypointBits(t) : TRACK_BIT_NONE; -} - -/** * Get the reserved track bits for a depot * @pre IsRailDepot(t) * @param t the tile @@ -635,17 +557,4 @@ static inline void MakeRailDepot(TileInd _me[t].m7 = 0; } - -static inline void MakeRailWaypoint(TileIndex t, Owner o, Axis a, RailType r, uint index) -{ - SetTileType(t, MP_RAILWAY); - SetTileOwner(t, o); - _m[t].m2 = index; - _m[t].m3 = r; - _m[t].m4 = 0; - _m[t].m5 = RAIL_TILE_WAYPOINT << 6 | a; - SB(_m[t].m6, 2, 4, 0); - _me[t].m7 = 0; -} - #endif /* RAIL_MAP_H */ diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -606,9 +606,7 @@ bool AfterLoadGame() switch (GetTileType(t)) { case MP_STATION: { Station *st = Station::GetByTile(t); - - /* Set up station spread; buoys do not have one */ - if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE); + if (st == NULL) break; switch (GetStationType(t)) { case STATION_TRUCK: @@ -987,29 +985,11 @@ bool AfterLoadGame() FOR_ALL_COMPANIES(c) c->settings.renew_keep_length = false; } - /* In version 17, ground type is moved from m2 to m4 for depots and - * waypoints to make way for storing the index in m2. The custom graphics - * id which was stored in m4 is now saved as a grf/id reference in the - * waypoint struct. */ - if (CheckSavegameVersion(17)) { - Waypoint *wp; - - FOR_ALL_WAYPOINTS(wp) { - if (wp->delete_ctr == 0) { - if (HasBit(_m[wp->xy].m3, 4)) { - AllocateSpecToStation(GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1), wp, true); - } - - /* Move ground type bits from m2 to m4. */ - _m[wp->xy].m4 = GB(_m[wp->xy].m2, 0, 4); - /* Store waypoint index in the tile. */ - _m[wp->xy].m2 = wp->index; - } - } - } else { - /* As of version 17, we recalculate the custom graphic ID of waypoints - * from the GRF ID / station index. */ - AfterLoadWaypoints(); + if (CheckSavegameVersion(123)) { + /* Waypoints became subclasses of stations ... */ + MoveWaypointsToBaseStations(); + /* ... and buoys were moved to waypoints. */ + MoveBuoysToWaypoints(); } /* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making @@ -1275,9 +1255,9 @@ bool AfterLoadGame() /* Buoys do now store the owner of the previous water tile, which can never * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ if (CheckSavegameVersion(46)) { - Station *st; - FOR_ALL_STATIONS(st) { - if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER); + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { + if ((wp->facilities & FACIL_DOCK) != 0 && IsTileOwner(wp->xy, OWNER_NONE) && TileHeight(wp->xy) == 0) SetTileOwner(wp->xy, OWNER_WATER); } } @@ -1487,15 +1467,6 @@ bool AfterLoadGame() } if (CheckSavegameVersion(84)) { - /* Update go to buoy orders because they are just waypoints */ - Order *order; - FOR_ALL_ORDERS(order) { - if (order->IsType(OT_GOTO_STATION) && Station::Get(order->GetDestination())->IsBuoy()) { - order->SetLoadType(OLF_LOAD_IF_POSSIBLE); - order->SetUnloadType(OUF_UNLOAD_IF_POSSIBLE); - } - } - /* Set all share owners to INVALID_COMPANY for * 1) all inactive companies * (when inactive companies were stored in the savegame - TTD, TTDP and some @@ -1561,7 +1532,7 @@ bool AfterLoadGame() if (IsBuoyTile(t)) { /* reset buoy owner to OWNER_NONE in the station struct * (even if it is owned by active company) */ - Station::GetByTile(t)->owner = OWNER_NONE; + Waypoint::GetByTile(t)->owner = OWNER_NONE; } } else if (IsTileType(t, MP_ROAD)) { /* works for all RoadTileType */ @@ -1805,16 +1776,6 @@ bool AfterLoadGame() FOR_ALL_STATIONS(st) { if (!Company::IsValidID(st->owner)) st->owner = OWNER_NONE; } - - /* Give owners to waypoints, based on rail tracks it is sitting on. - * If none is available, specify OWNER_NONE. - * This code was in CheckSavegameVersion(101) in the past, but in some cases, - * the owner of waypoints could be incorrect. */ - Waypoint *wp; - FOR_ALL_WAYPOINTS(wp) { - Owner owner = IsTileType(wp->xy, MP_RAILWAY) ? GetTileOwner(wp->xy) : OWNER_NONE; - wp->owner = Company::IsValidID(owner) ? owner : OWNER_NONE; - } } /* Trains could now stop in a specific location. */ @@ -1913,14 +1874,6 @@ bool AfterLoadGame() } s->cargo_type = CT_INVALID; } - - Order *o; - FOR_ALL_ORDERS(o) { - /* Buoys are now go to waypoint orders */ - if (!o->IsType(OT_GOTO_STATION) || !Station::Get(o->GetDestination())->IsBuoy()) continue; - - o->MakeGoToWaypoint(o->GetDestination()); - } } AfterLoadLabelMaps(); @@ -1950,8 +1903,7 @@ void ReloadNewGRFData() AfterLoadVehicles(false); StartupEngines(); SetCachedEngineCounts(); - /* update station and waypoint graphics */ - AfterLoadWaypoints(); + /* update station graphics */ AfterLoadStations(); /* Check and update house and town values */ UpdateHousesAndTowns(); diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -41,7 +41,7 @@ #include "saveload_internal.h" -extern const uint16 SAVEGAME_VERSION = 122; +extern const uint16 SAVEGAME_VERSION = 123; SavegameType _savegame_type; ///< type of savegame we are loading @@ -873,6 +873,7 @@ size_t SlCalcObjMemberLength(const void break; case SL_WRITEBYTE: return 1; // a byte is logically of size 1 case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); + case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription()); default: NOT_REACHED(); } return 0; @@ -934,6 +935,10 @@ bool SlObjectMember(void *ptr, const Sav SlObject(ptr, GetVehicleDescription(VEH_END)); break; + case SL_ST_INCLUDE: + SlObject(ptr, GetBaseStationDescription()); + break; + default: NOT_REACHED(); } return true; diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -182,6 +182,7 @@ enum SaveLoadTypes { /* non-normal save-load types */ SL_WRITEBYTE = 8, SL_VEH_INCLUDE = 9, + SL_ST_INCLUDE = 10, SL_END = 15 }; @@ -235,6 +236,7 @@ typedef SaveLoad SaveLoadGlobVarList; #define SLE_WRITEBYTEX(offset, something) SLE_GENERALX(SL_WRITEBYTE, offset, 0, 0, something, 0) #define SLE_VEH_INCLUDEX() SLE_GENERALX(SL_VEH_INCLUDE, 0, 0, 0, 0, SL_MAX_VERSION) +#define SLE_ST_INCLUDEX() SLE_GENERALX(SL_ST_INCLUDE, 0, 0, 0, 0, SL_MAX_VERSION) /* End marker */ #define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL} diff --git a/src/saveload/saveload_internal.h b/src/saveload/saveload_internal.h --- a/src/saveload/saveload_internal.h +++ b/src/saveload/saveload_internal.h @@ -16,7 +16,10 @@ StringID RemapOldStringID(StringID s); char *CopyFromOldName(StringID id); void ResetOldNames(); -void AfterLoadWaypoints(); +void MoveBuoysToWaypoints(); +void MoveWaypointsToBaseStations(); +const SaveLoad *GetBaseStationDescription(); + void AfterLoadVehicles(bool part_of_load); void AfterLoadStations(); void AfterLoadLabelMaps(); diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -4,27 +4,98 @@ #include "../stdafx.h" #include "../station_base.h" +#include "../waypoint.h" #include "../roadstop_base.h" +#include "../order_base.h" +#include "../vehicle_base.h" #include "../core/bitmath_func.hpp" #include "../core/alloc_func.hpp" #include "../variables.h" #include "../newgrf_station.h" #include "saveload.h" +#include "table/strings.h" +/** + * Update the buoy orders to be waypoint orders. + * @param o the order 'list' to check. + */ +static void UpdateWaypointOrder(Order *o) +{ + if (!o->IsType(OT_GOTO_STATION)) return; + + const Station *st = Station::Get(o->GetDestination()); + if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) return; + + o->MakeGoToWaypoint(o->GetDestination()); +} + +/** + * Perform all steps to upgrade from the old station buoys to the new version + * that uses waypoints. This includes some old saveload mechanics. + */ +void MoveBuoysToWaypoints() +{ + /* Buoy orders become waypoint orders */ + OrderList *ol; + FOR_ALL_ORDER_LISTS(ol) { + if (ol->GetFirstSharedVehicle()->type != VEH_SHIP) continue; + + for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); + } + + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type != VEH_SHIP) continue; + + UpdateWaypointOrder(&v->current_order); + } + + /* Now make the stations waypoints */ + Station *st; + FOR_ALL_STATIONS(st) { + if ((st->had_vehicle_of_type & HVOT_WAYPOINT) == 0) continue; + + StationID index = st->index; + TileIndex xy = st->xy; + Town *town = st->town; + StringID string_id = st->string_id; + char *name = st->name; + Date build_date = st->build_date; + + /* Delete the station, so we can make it a real waypoint. */ + delete st; + + Waypoint *wp = new (index) Waypoint(xy); + wp->town = town; + wp->string_id = STR_SV_STNAME_BUOY; + wp->name = name; + wp->delete_ctr = 0; // Just reset delete counter for once. + wp->build_date = build_date; + wp->owner = OWNER_NONE; + + if (IsInsideBS(string_id, STR_SV_STNAME_BUOY, 9)) wp->town_cn = string_id - STR_SV_STNAME_BUOY; + + if (IsBuoyTile(xy) && GetStationIndex(xy) == index) { + wp->facilities |= FACIL_DOCK; + } + } +} void AfterLoadStations() { /* Update the speclists of all stations to point to the currently loaded custom stations. */ - Station *st; - FOR_ALL_STATIONS(st) { + BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { for (uint i = 0; i < st->num_specs; i++) { if (st->speclist[i].grfid == 0) continue; st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx, NULL); } - for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache(); + if (Station::IsExpected(st)) { + for (CargoID c = 0; c < NUM_CARGO; c++) Station::From(st)->goods[c].cargo.InvalidateCache(); + } StationUpdateAnimTriggers(st); } @@ -48,7 +119,7 @@ static const SaveLoad _roadstop_desc[] = SLE_END() }; -static const SaveLoad _station_desc[] = { +static const SaveLoad _old_station_desc[] = { SLE_CONDVAR(Station, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile @@ -145,66 +216,54 @@ const SaveLoad *GetGoodsDesc() } -static void SaveLoad_STNS(Station *st) -{ - SlObject(st, _station_desc); - - _waiting_acceptance = 0; - - uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; - for (CargoID i = 0; i < num_cargo; i++) { - GoodsEntry *ge = &st->goods[i]; - SlObject(ge, GetGoodsDesc()); - if (CheckSavegameVersion(68)) { - SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); - if (GB(_waiting_acceptance, 0, 12) != 0) { - /* Don't construct the packet with station here, because that'll fail with old savegames */ - CargoPacket *cp = new CargoPacket(); - /* In old versions, enroute_from used 0xFF as INVALID_STATION */ - cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; - cp->count = GB(_waiting_acceptance, 0, 12); - cp->days_in_transit = _cargo_days; - cp->feeder_share = _cargo_feeder_share; - cp->source_xy = _cargo_source_xy; - cp->days_in_transit = _cargo_days; - cp->feeder_share = _cargo_feeder_share; - SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1); - ge->cargo.Append(cp); - } - } - } - - if (st->num_specs != 0) { - /* Allocate speclist memory when loading a game */ - if (st->speclist == NULL) st->speclist = CallocT(st->num_specs); - for (uint i = 0; i < st->num_specs; i++) { - SlObject(&st->speclist[i], _station_speclist_desc); - } - } -} - -static void Save_STNS() -{ - Station *st; - /* Write the stations */ - FOR_ALL_STATIONS(st) { - SlSetArrayIndex(st->index); - SlAutolength((AutolengthProc*)SaveLoad_STNS, st); - } -} - static void Load_STNS() { int index; while ((index = SlIterateArray()) != -1) { Station *st = new (index) Station(); - SaveLoad_STNS(st); + SlObject(st, _old_station_desc); + + _waiting_acceptance = 0; + + uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; + for (CargoID i = 0; i < num_cargo; i++) { + GoodsEntry *ge = &st->goods[i]; + SlObject(ge, GetGoodsDesc()); + if (CheckSavegameVersion(68)) { + SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); + if (GB(_waiting_acceptance, 0, 12) != 0) { + /* Don't construct the packet with station here, because that'll fail with old savegames */ + CargoPacket *cp = new CargoPacket(); + /* In old versions, enroute_from used 0xFF as INVALID_STATION */ + cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; + cp->count = GB(_waiting_acceptance, 0, 12); + cp->days_in_transit = _cargo_days; + cp->feeder_share = _cargo_feeder_share; + cp->source_xy = _cargo_source_xy; + cp->days_in_transit = _cargo_days; + cp->feeder_share = _cargo_feeder_share; + SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1); + ge->cargo.Append(cp); + } + } + } + + if (st->num_specs != 0) { + /* Allocate speclist memory when loading a game */ + st->speclist = CallocT(st->num_specs); + for (uint i = 0; i < st->num_specs; i++) { + SlObject(&st->speclist[i], _station_speclist_desc); + } + } } } void Ptrs_STNS() { + /* Don't run when savegame version is higher than or equal to 123. */ + if (!CheckSavegameVersion(123)) return; + Station *st; FOR_ALL_STATIONS(st) { if (!CheckSavegameVersion(68)) { @@ -213,11 +272,147 @@ void Ptrs_STNS() SlObject(ge, GetGoodsDesc()); } } - SlObject(st, _station_desc); + SlObject(st, _old_station_desc); } } +static const SaveLoad _base_station_desc[] = { + SLE_VAR(BaseStation, xy, SLE_UINT32), + SLE_REF(BaseStation, town, REF_TOWN), + SLE_VAR(BaseStation, string_id, SLE_STRINGID), + SLE_STR(BaseStation, name, SLE_STR, 0), + SLE_VAR(BaseStation, delete_ctr, SLE_UINT8), + SLE_VAR(BaseStation, owner, SLE_UINT8), + SLE_VAR(BaseStation, facilities, SLE_UINT8), + SLE_VAR(BaseStation, build_date, SLE_INT32), + + /* Used by newstations for graphic variations */ + SLE_VAR(BaseStation, random_bits, SLE_UINT16), + SLE_VAR(BaseStation, waiting_triggers, SLE_UINT8), + SLE_VAR(BaseStation, num_specs, SLE_UINT8), + + SLE_END() +}; + +static const SaveLoad _station_desc[] = { + SLE_WRITEBYTE(Station, facilities, FACIL_NONE), + SLE_ST_INCLUDEX(), + + SLE_VAR(Station, train_tile, SLE_UINT32), + SLE_VAR(Station, trainst_w, SLE_UINT8), + SLE_VAR(Station, trainst_h, SLE_UINT8), + + SLE_REF(Station, bus_stops, REF_ROADSTOPS), + SLE_REF(Station, truck_stops, REF_ROADSTOPS), + SLE_VAR(Station, dock_tile, SLE_UINT32), + SLE_VAR(Station, airport_tile, SLE_UINT32), + SLE_VAR(Station, airport_type, SLE_UINT8), + SLE_VAR(Station, airport_flags, SLE_UINT64), + + SLE_VAR(Station, indtype, SLE_UINT8), + + SLE_VAR(Station, time_since_load, SLE_UINT8), + SLE_VAR(Station, time_since_unload, SLE_UINT8), + SLE_VAR(Station, last_vehicle_type, SLE_UINT8), + SLE_VAR(Station, had_vehicle_of_type, SLE_UINT8), + SLE_LST(Station, loading_vehicles, REF_VEHICLE), + + SLE_END() +}; + +static const SaveLoad _waypoint_desc[] = { + SLE_WRITEBYTE(Waypoint, facilities, FACIL_WAYPOINT), + SLE_ST_INCLUDEX(), + + SLE_VAR(Waypoint, town_cn, SLE_UINT16), + + SLE_END() +}; + +/** + * Get the base station description to be used for SL_ST_INCLUDE + * @return the base station description. + */ +const SaveLoad *GetBaseStationDescription() +{ + return _base_station_desc; +} + +static void RealSave_STNN(BaseStation *bst) +{ + bool waypoint = (bst->facilities & FACIL_WAYPOINT) != 0; + SlObject(bst, waypoint ? _waypoint_desc : _station_desc); + + if (!waypoint) { + Station *st = Station::From(bst); + for (CargoID i = 0; i < NUM_CARGO; i++) { + SlObject(&st->goods[i], GetGoodsDesc()); + } + } + + for (uint i = 0; i < bst->num_specs; i++) { + SlObject(&bst->speclist[i], _station_speclist_desc); + } +} + +static void Save_STNN() +{ + BaseStation *st; + /* Write the stations */ + FOR_ALL_BASE_STATIONS(st) { + SlSetArrayIndex(st->index); + SlAutolength((AutolengthProc*)RealSave_STNN, st); + } +} + +static void Load_STNN() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0; + + BaseStation *bst = waypoint ? (BaseStation *)new (index) Waypoint() : new (index) Station(); + SlObject(bst, waypoint ? _waypoint_desc : _station_desc); + + if (!waypoint) { + Station *st = Station::From(bst); + for (CargoID i = 0; i < NUM_CARGO; i++) { + SlObject(&st->goods[i], GetGoodsDesc()); + } + } + + if (bst->num_specs != 0) { + /* Allocate speclist memory when loading a game */ + bst->speclist = CallocT(bst->num_specs); + for (uint i = 0; i < bst->num_specs; i++) { + SlObject(&bst->speclist[i], _station_speclist_desc); + } + } + } +} + +static void Ptrs_STNN() +{ + /* Don't run when savegame version lower than 123. */ + if (CheckSavegameVersion(123)) return; + + Station *st; + FOR_ALL_STATIONS(st) { + for (CargoID i = 0; i < NUM_CARGO; i++) { + GoodsEntry *ge = &st->goods[i]; + SlObject(ge, GetGoodsDesc()); + } + SlObject(st, _station_desc); + } + + Waypoint *wp; + FOR_ALL_WAYPOINTS(wp) { + SlObject(wp, _waypoint_desc); + } +} + static void Save_ROADSTOP() { RoadStop *rs; @@ -248,6 +443,7 @@ static void Ptrs_ROADSTOP() } extern const ChunkHandler _station_chunk_handlers[] = { - { 'STNS', Save_STNS, Load_STNS, Ptrs_STNS, CH_ARRAY }, + { 'STNS', NULL, Load_STNS, Ptrs_STNS, CH_ARRAY }, + { 'STNN', Save_STNN, Load_STNN, Ptrs_STNN, CH_ARRAY }, { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, CH_ARRAY | CH_LAST}, }; diff --git a/src/saveload/waypoint_sl.cpp b/src/saveload/waypoint_sl.cpp --- a/src/saveload/waypoint_sl.cpp +++ b/src/saveload/waypoint_sl.cpp @@ -5,120 +5,187 @@ #include "../stdafx.h" #include "../waypoint.h" #include "../newgrf_station.h" +#include "../vehicle_base.h" #include "../town.h" +#include "../station_map.h" #include "table/strings.h" #include "saveload.h" #include "saveload_internal.h" -/** - * Update waypoint graphics id against saved GRFID/localidx. - * This is to ensure the chosen graphics are correct if GRF files are changed. - */ -void AfterLoadWaypoints() -{ - Waypoint *wp; +/** Helper structure to convert from the old waypoint system. */ +struct OldWaypoint { + size_t index; + TileIndex xy; + TownID town_index; + Town *town; + uint16 town_cn; + StringID string_id; + char *name; + uint8 delete_ctr; + Date build_date; + uint8 localidx; + uint32 grfid; + const StationSpec *spec; + OwnerByte owner; - FOR_ALL_WAYPOINTS(wp) { - if (wp->num_specs == 0) continue; + size_t new_index; +}; + +/** Temporary array with old waypoints. */ +static SmallVector _old_waypoints; - for (uint i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) { - const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i); - if (statspec != NULL && statspec->grffile->grfid == wp->speclist[1].grfid && statspec->localidx == wp->speclist[1].localidx) { - wp->speclist[1].spec = statspec; - break; - } - } +/** + * Update the waypoint orders to get the new waypoint ID. + * @param o the order 'list' to check. + */ +static void UpdateWaypointOrder(Order *o) +{ + if (!o->IsType(OT_GOTO_WAYPOINT)) return; + + for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { + if (wp->index != o->GetDestination()) continue; + + o->SetDestination(wp->new_index); + return; } } -static uint16 _waypoint_town_index; -static StringID _waypoint_string_id; -static StationSpecList _waypoint_spec; +/** + * Perform all steps to upgrade from the old waypoints to the new version + * that uses station. This includes some old saveload mechanics. + */ +void MoveWaypointsToBaseStations() +{ + /* In version 17, ground type is moved from m2 to m4 for depots and + * waypoints to make way for storing the index in m2. The custom graphics + * id which was stored in m4 is now saved as a grf/id reference in the + * waypoint struct. */ + if (CheckSavegameVersion(17)) { + for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { + if (wp->delete_ctr == 0 && HasBit(_m[wp->xy].m3, 4)) { + wp->spec = GetCustomStationSpec(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1); + } + } + } else { + /* As of version 17, we recalculate the custom graphic ID of waypoints + * from the GRF ID / station index. */ + for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { + for (uint i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) { + const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i); + if (statspec != NULL && statspec->grffile->grfid == wp->grfid && statspec->localidx == wp->localidx) { + wp->spec = statspec; + break; + } + } + } + } + + /* All saveload conversions have been done. Create the new waypoints! */ + for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { + Waypoint *new_wp = new Waypoint(wp->xy); + new_wp->town = wp->town; + new_wp->town_cn = wp->town_cn; + new_wp->name = wp->name; + new_wp->delete_ctr = 0; // Just reset delete counter for once. + new_wp->build_date = wp->build_date; + new_wp->owner = wp->owner; + + new_wp->string_id = STR_SV_STNAME_WAYPOINT; + + TileIndex t = wp->xy; + if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp->index) { + /* The tile might've been reserved! */ + bool reserved = !CheckSavegameVersion(100) && HasBit(_m[t].m5, 4); -static const SaveLoad _waypoint_desc[] = { - SLE_CONDVAR(Waypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(Waypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION), - SLEG_CONDVAR(_waypoint_town_index, SLE_UINT16, 12, 121), - SLE_CONDREF(Waypoint, town, REF_TOWN, 122, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, 12, 88), - SLE_CONDVAR(Waypoint, town_cn, SLE_UINT16, 89, SL_MAX_VERSION), - SLEG_CONDVAR(_waypoint_string_id, SLE_STRINGID, 0, 83), - SLE_CONDSTR(Waypoint, name, SLE_STR, 0, 84, SL_MAX_VERSION), - SLE_VAR(Waypoint, delete_ctr, SLE_UINT8), + /* The tile really has our waypoint, so reassign the map array */ + MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t)); + new_wp->facilities |= FACIL_TRAIN; + new_wp->owner = GetTileOwner(t); + + SetRailwayStationReservation(t, reserved); + + if (wp->spec != NULL) { + SetCustomStationSpecIndex(t, AllocateSpecToStation(wp->spec, new_wp, true)); + } + } + + wp->new_index = new_wp->index; + } + + /* Update the orders of vehicles */ + OrderList *ol; + FOR_ALL_ORDER_LISTS(ol) { + if (ol->GetFirstSharedVehicle()->type != VEH_TRAIN) continue; + + for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); + } - SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), - SLE_CONDVAR(Waypoint, build_date, SLE_INT32, 31, SL_MAX_VERSION), - SLEG_CONDVAR(_waypoint_spec.localidx, SLE_UINT8, 3, SL_MAX_VERSION), - SLEG_CONDVAR(_waypoint_spec.grfid, SLE_UINT32, 17, SL_MAX_VERSION), - SLE_CONDVAR(Waypoint, owner, SLE_UINT8, 101, SL_MAX_VERSION), + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v->type != VEH_TRAIN) continue; + + UpdateWaypointOrder(&v->current_order); + } + + _old_waypoints.Reset(); +} + +static const SaveLoad _old_waypoint_desc[] = { + SLE_CONDVAR(OldWaypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(OldWaypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(OldWaypoint, town_index, SLE_UINT16, 12, 121), + SLE_CONDREF(OldWaypoint, town, REF_TOWN, 122, SL_MAX_VERSION), + SLE_CONDVAR(OldWaypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, 12, 88), + SLE_CONDVAR(OldWaypoint, town_cn, SLE_UINT16, 89, SL_MAX_VERSION), + SLE_CONDVAR(OldWaypoint, string_id, SLE_STRINGID, 0, 83), + SLE_CONDSTR(OldWaypoint, name, SLE_STR, 0, 84, SL_MAX_VERSION), + SLE_VAR(OldWaypoint, delete_ctr, SLE_UINT8), + + SLE_CONDVAR(OldWaypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, 3, 30), + SLE_CONDVAR(OldWaypoint, build_date, SLE_INT32, 31, SL_MAX_VERSION), + SLE_CONDVAR(OldWaypoint, localidx, SLE_UINT8, 3, SL_MAX_VERSION), + SLE_CONDVAR(OldWaypoint, grfid, SLE_UINT32, 17, SL_MAX_VERSION), + SLE_CONDVAR(OldWaypoint, owner, SLE_UINT8, 101, SL_MAX_VERSION), SLE_END() }; -static void Save_WAYP() -{ - Waypoint *wp; - - FOR_ALL_WAYPOINTS(wp) { - if (wp->num_specs == 0) { - _waypoint_spec.grfid = 0; - } else { - _waypoint_spec = wp->speclist[1]; - } - - SlSetArrayIndex(wp->index); - SlObject(wp, _waypoint_desc); - } -} - static void Load_WAYP() { + /* Precaution for when loading failed and it didn't get cleared */ + _old_waypoints.Clear(); + int index; while ((index = SlIterateArray()) != -1) { - _waypoint_string_id = 0; - _waypoint_town_index = 0; - _waypoint_spec.grfid = 0; - - Waypoint *wp = new (index) Waypoint(); - SlObject(wp, _waypoint_desc); - - wp->facilities |= FACIL_TRAIN; + OldWaypoint *wp = _old_waypoints.Append(); + memset(wp, 0, sizeof(*wp)); - if (_waypoint_spec.grfid != 0) { - wp->num_specs = 2; - wp->speclist = CallocT(2); - wp->speclist[1] = _waypoint_spec; - } - - if (CheckSavegameVersion(84)) wp->name = (char *)(size_t)_waypoint_string_id; - if (CheckSavegameVersion(122)) wp->town = (Town *)(size_t)_waypoint_town_index; + wp->index = index; + SlObject(wp, _old_waypoint_desc); } } static void Ptrs_WAYP() { - Waypoint *wp; + for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { + SlObject(wp, _old_waypoint_desc); - FOR_ALL_WAYPOINTS(wp) { - SlObject(wp, _waypoint_desc); - - StringID sid = (StringID)(size_t)wp->name; if (CheckSavegameVersion(12)) { - wp->town_cn = (sid & 0xC000) == 0xC000 ? (sid >> 8) & 0x3F : 0; + wp->town_cn = (wp->string_id & 0xC000) == 0xC000 ? (wp->string_id >> 8) & 0x3F : 0; wp->town = ClosestTownFromTile(wp->xy, UINT_MAX); } else if (CheckSavegameVersion(122)) { /* Only for versions 12 .. 122 */ - wp->town = Town::Get((size_t)wp->town); + wp->town = Town::Get(wp->town_index); } if (CheckSavegameVersion(84)) { - wp->name = CopyFromOldName(sid); + wp->name = CopyFromOldName(wp->string_id); } } } extern const ChunkHandler _waypoint_chunk_handlers[] = { - { 'CHKP', Save_WAYP, Load_WAYP, Ptrs_WAYP, CH_ARRAY | CH_LAST}, + { 'CHKP', NULL, Load_WAYP, Ptrs_WAYP, CH_ARRAY | CH_LAST}, }; diff --git a/src/signal.cpp b/src/signal.cpp --- a/src/signal.cpp +++ b/src/signal.cpp @@ -288,14 +288,6 @@ static SigFlags ExploreSegment(Owner own } } - if (GetRailTileType(tile) == RAIL_TILE_WAYPOINT) { - if (GetWaypointAxis(tile) != DiagDirToAxis(enterdir)) continue; - if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN; - tile += TileOffsByDiagDir(exitdir); - /* enterdir and exitdir stay the same */ - break; - } - TrackBits tracks = GetTrackBits(tile); // trackbits of tile TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits diff --git a/src/station.cpp b/src/station.cpp --- a/src/station.cpp +++ b/src/station.cpp @@ -50,12 +50,6 @@ Station::Station(TileIndex tile) : /* this->random_bits is set in Station::AddFacility() */ } -/* static */ BaseStation *BaseStation::GetByTile(TileIndex tile) -{ - if (IsRailWaypointTile(tile)) return Waypoint::GetByTile(tile); - return Station::GetByTile(tile); -} - /** * Clean up a station by clearing vehicle orders and invalidating windows. * Aircraft-Hangar orders need special treatment here, as the hangars are diff --git a/src/station_base.h b/src/station_base.h --- a/src/station_base.h +++ b/src/station_base.h @@ -21,7 +21,7 @@ #include "station_map.h" #include -typedef Pool StationPool; +typedef Pool StationPool; extern StationPool _station_pool; static const byte INITIAL_STATION_RATING = 175; @@ -85,7 +85,7 @@ struct TileArea { }; /** Base class for all station-ish types */ -struct BaseStation { +struct BaseStation : StationPool::PoolItem<&_station_pool> { TileIndex xy; ///< Base tile of the station ViewportSign sign; ///< NOSAVE: Dimensions of sign byte delete_ctr; ///< Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is deleted. @@ -144,9 +144,14 @@ struct BaseStation { * @param tile The tile to get the base station from. * @return the station associated with that tile. */ - static BaseStation *GetByTile(TileIndex tile); + static FORCEINLINE BaseStation *GetByTile(TileIndex tile) + { + return BaseStation::Get(GetStationIndex(tile)); + } }; +#define FOR_ALL_BASE_STATIONS(var) FOR_ALL_ITEMS_FROM(BaseStation, station_index, var, 0) + /** * Class defining several overloaded accessors so we don't * have to cast base stations that often @@ -176,6 +181,44 @@ struct SpecializedStation : public BaseS } /** + * Tests whether given index is a valid index for station of this type + * @param index tested index + * @return is this index valid index of T? + */ + static FORCEINLINE bool IsValidID(size_t index) + { + return BaseStation::IsValidID(index) && IsExpected(BaseStation::Get(index)); + } + + /** + * Gets station with given index + * @return pointer to station with given index casted to T * + */ + static FORCEINLINE T *Get(size_t index) + { + return (T *)BaseStation::Get(index); + } + + /** + * Returns station if the index is a valid index for this station type + * @return pointer to station with given index if it's a station of this type + */ + static FORCEINLINE T *GetIfValid(size_t index) + { + return IsValidID(index) ? Get(index) : NULL ; + } + + /** + * Get the station belonging to a specific tile. + * @param tile The tile to get the station from. + * @return the station associated with that tile. + */ + static FORCEINLINE T *GetByTile(TileIndex tile) + { + return GetIfValid(GetStationIndex(tile)); + } + + /** * Converts a BaseStation to SpecializedStation with type checking. * @param st BaseStation pointer * @return pointer to SpecializedStation @@ -198,11 +241,13 @@ struct SpecializedStation : public BaseS } }; +#define FOR_ALL_BASE_STATIONS_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, station_index, var, 0) if (name::IsExpected(var)) + typedef SmallVector IndustryVector; /** Station data structure */ -struct Station : StationPool::PoolItem<&_station_pool>, SpecializedStation { +struct Station : SpecializedStation { public: RoadStop *GetPrimaryRoadStop(RoadStopType type) const { @@ -274,24 +319,9 @@ public: /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; - /** - * Determines whether a station is a buoy only. - * @todo Ditch this encoding of buoys - */ - FORCEINLINE bool IsBuoy() const - { - return (this->had_vehicle_of_type & HVOT_BUOY) != 0; - } - - static FORCEINLINE Station *GetByTile(TileIndex tile) - { - return Station::Get(GetStationIndex(tile)); - } - static void PostDestructor(size_t index); }; -#define FOR_ALL_STATIONS_FROM(var, start) FOR_ALL_ITEMS_FROM(Station, station_index, var, start) -#define FOR_ALL_STATIONS(var) FOR_ALL_STATIONS_FROM(var, 0) +#define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var) #endif /* STATION_BASE_H */ diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -197,7 +197,6 @@ enum StationNaming { STATIONNAMING_AIRPORT, STATIONNAMING_OILRIG, STATIONNAMING_DOCK, - STATIONNAMING_BUOY, STATIONNAMING_HELIPORT, }; @@ -239,7 +238,6 @@ static StringID GenerateStationName(Stat 1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT 1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG 1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK - 0x1FFU << M(STR_SV_STNAME_BUOY_1), // STATIONNAMING_BUOY 1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT }; @@ -266,24 +264,22 @@ static StringID GenerateStationName(Stat } } - if (name_class != STATIONNAMING_BUOY) { - TileIndex indtile = tile; - StationNameInformation sni = { free_names, indtypes }; - if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) { - /* An industry has been found nearby */ - IndustryType indtype = GetIndustryType(indtile); - const IndustrySpec *indsp = GetIndustrySpec(indtype); - /* STR_NULL means it only disables oil rig/mines */ - if (indsp->station_name != STR_NULL) { - st->indtype = indtype; - return STR_SV_STNAME_FALLBACK; - } + TileIndex indtile = tile; + StationNameInformation sni = { free_names, indtypes }; + if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) { + /* An industry has been found nearby */ + IndustryType indtype = GetIndustryType(indtile); + const IndustrySpec *indsp = GetIndustrySpec(indtype); + /* STR_NULL means it only disables oil rig/mines */ + if (indsp->station_name != STR_NULL) { + st->indtype = indtype; + return STR_SV_STNAME_FALLBACK; } - - /* Oil rigs/mines name could be marked not free by looking for a near by industry. */ - free_names = sni.free_names; } + /* Oil rigs/mines name could be marked not free by looking for a near by industry. */ + free_names = sni.free_names; + /* check default names */ uint32 tmp = free_names & _gen_station_name_bits[name_class]; if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp); @@ -540,9 +536,6 @@ CargoArray GetAcceptanceAroundTiles(Tile */ static void UpdateStationAcceptance(Station *st, bool show_msg) { - /* Don't update acceptance for a buoy */ - if (st->IsBuoy()) return; - /* old accepted goods types */ uint old_acc = GetAcceptanceMask(st); @@ -1963,31 +1956,23 @@ CommandCost CmdBuildBuoy(TileIndex tile, if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); /* allocate and initialize new station */ - if (!Station::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); + if (!Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING); if (flags & DC_EXEC) { - Station *st = new Station(tile); - - st->town = ClosestTownFromTile(tile, UINT_MAX); - st->string_id = GenerateStationName(st, tile, STATIONNAMING_BUOY); - - if (Company::IsValidID(_current_company)) { - SetBit(st->town->have_ratings, _current_company); - } - st->dock_tile = tile; + Waypoint *st = new Waypoint(tile); + + st->string_id = STR_SV_STNAME_BUOY; + st->facilities |= FACIL_DOCK; - /* Buoys are marked in the Station struct by this flag. Yes, it is this - * braindead.. */ - st->had_vehicle_of_type |= HVOT_BUOY; st->owner = OWNER_NONE; st->build_date = _date; + if (st->town == NULL) MakeDefaultWaypointName(st); + MakeBuoy(tile, st->index, GetWaterClass(tile)); st->UpdateVirtCoord(); - UpdateStationAcceptance(st, false); - st->RecomputeIndustriesNear(); InvalidateWindowData(WC_STATION_LIST, st->owner, 0); InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS); } @@ -2008,7 +1993,7 @@ bool HasStationInUse(StationID station, if (company == INVALID_COMPANY || v->owner == company) { const Order *order; FOR_VEHICLE_ORDERS(v, order) { - if (order->IsType(OT_GOTO_STATION) && order->GetDestination() == station) { + if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT)) && order->GetDestination() == station) { return true; } } @@ -2028,18 +2013,14 @@ static CommandCost RemoveBuoy(TileIndex /* XXX: strange stuff, allow clearing as invalid company when clearing landscape */ if (!Company::IsValidID(_current_company) && !(flags & DC_BANKRUPT)) return_cmd_error(INVALID_STRING_ID); - Station *st = Station::GetByTile(tile); + Waypoint *st = Waypoint::GetByTile(tile); if (HasStationInUse(st->index, INVALID_COMPANY)) return_cmd_error(STR_BUOY_IS_IN_USE); /* remove the buoy if there is a ship on tile when company goes bankrupt... */ if (!(flags & DC_BANKRUPT) && !EnsureNoVehicleOnGround(tile)) return CMD_ERROR; if (flags & DC_EXEC) { - st->dock_tile = INVALID_TILE; - /* Buoys are marked in the Station struct by this flag. Yes, it is this - * braindead.. */ st->facilities &= ~FACIL_DOCK; - st->had_vehicle_of_type &= ~HVOT_BUOY; InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS); @@ -2050,8 +2031,7 @@ static CommandCost RemoveBuoy(TileIndex MarkTileDirtyByTile(tile); st->UpdateVirtCoord(); - st->RecomputeIndustriesNear(); - DeleteStationIfEmpty(st); + st->delete_ctr = 0; } return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_truck_station); @@ -2227,7 +2207,7 @@ static void DrawTile_Station(TileInfo *t int32 total_offset; int32 custom_ground_offset; - if (IsRailwayStation(ti->tile)) { + if (IsRailwayStation(ti->tile) || IsRailWaypoint(ti->tile)) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); roadtypes = ROADTYPES_NONE; total_offset = rti->total_offset; @@ -2238,7 +2218,7 @@ static void DrawTile_Station(TileInfo *t custom_ground_offset = 0; } uint32 relocation = 0; - const Station *st = NULL; + const BaseStation *st = NULL; const StationSpec *statspec = NULL; Owner owner = GetTileOwner(ti->tile); @@ -2256,7 +2236,7 @@ static void DrawTile_Station(TileInfo *t if (IsCustomStationSpecIndex(ti->tile)) { /* look for customization */ - st = Station::GetByTile(ti->tile); + st = BaseStation::GetByTile(ti->tile); statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec; if (statspec != NULL) { @@ -2304,13 +2284,13 @@ static void DrawTile_Station(TileInfo *t DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette)); /* PBS debugging, draw reserved tracks darker */ - if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && IsRailwayStation(ti->tile) && HasStationReservation(ti->tile)) { + if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && (IsRailwayStation(ti->tile) || IsRailWaypoint(ti->tile)) && HasStationReservation(ti->tile)) { const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); DrawGroundSprite(GetRailStationAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH); } } - if (IsRailwayStation(ti->tile) && HasCatenaryDrawn(GetRailType(ti->tile)) && IsStationTileElectrifiable(ti->tile)) DrawCatenary(ti); + if ((IsRailwayStation(ti->tile) || IsRailWaypoint(ti->tile)) && HasCatenaryDrawn(GetRailType(ti->tile)) && IsStationTileElectrifiable(ti->tile)) DrawCatenary(ti); if (HasBit(roadtypes, ROADTYPE_TRAM)) { Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; @@ -2318,6 +2298,11 @@ static void DrawTile_Station(TileInfo *t DrawTramCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y); } + if (IsRailWaypoint(ti->tile)) { + /* Don't offset the waypoint graphics; they're always the same. */ + total_offset = 0; + } + const DrawTileSeqStruct *dtss; foreach_draw_tile_seq(dtss, t->seq) { SpriteID image = dtss->image.sprite; @@ -2408,7 +2393,7 @@ static void GetTileDesc_Station(TileInde } } } - td->build_date = Station::GetByTile(tile)->build_date; + td->build_date = BaseStation::GetByTile(tile)->build_date; const StationSpec *spec = GetStationSpec(tile); @@ -2425,15 +2410,16 @@ static void GetTileDesc_Station(TileInde StringID str; switch (GetStationType(tile)) { default: NOT_REACHED(); - case STATION_RAIL: str = STR_STATION_DESCRIPTION_RAILROAD_STATION; break; + case STATION_RAIL: str = STR_STATION_DESCRIPTION_RAILROAD_STATION; break; case STATION_AIRPORT: str = (IsHangar(tile) ? STR_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_STATION_DESCRIPTION_AIRPORT); break; - case STATION_TRUCK: str = STR_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break; - case STATION_BUS: str = STR_STATION_DESCRIPTION_BUS_STATION; break; - case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break; - case STATION_DOCK: str = STR_STATION_DESCRIPTION_SHIP_DOCK; break; - case STATION_BUOY: str = STR_STATION_DESCRIPTION_BUOY; break; + case STATION_TRUCK: str = STR_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break; + case STATION_BUS: str = STR_STATION_DESCRIPTION_BUS_STATION; break; + case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break; + case STATION_DOCK: str = STR_STATION_DESCRIPTION_SHIP_DOCK; break; + case STATION_BUOY: str = STR_STATION_DESCRIPTION_BUOY; break; + case STATION_WAYPOINT: str = STR_LANDINFO_WAYPOINT; break; } td->str = str; } @@ -2445,7 +2431,7 @@ static TrackStatus GetTileTrackStatus_St switch (mode) { case TRANSPORT_RAIL: - if (IsRailwayStation(tile) && !IsStationTileBlocked(tile)) { + if ((IsRailwayStation(tile) || IsRailWaypoint(tile)) && !IsStationTileBlocked(tile)) { trackbits = TrackToTrackBits(GetRailStationTrack(tile)); } break; @@ -2551,10 +2537,14 @@ static void AnimateTile_Station(TileInde static bool ClickTile_Station(TileIndex tile) { - if (IsHangar(tile)) { + const BaseStation *st = BaseStation::GetByTile(tile); + + if (st->facilities & FACIL_WAYPOINT) { + ShowWaypointWindow(Waypoint::From(st)); + } else if (IsHangar(tile)) { ShowDepotWindow(tile, VEH_AIRCRAFT); } else { - ShowStationViewWindow(GetStationIndex(tile)); + ShowStationViewWindow(st->index); } return true; } @@ -2650,15 +2640,15 @@ static VehicleEnterTileStatus VehicleEnt * @param st the station receiving the tick. * @return true if the station is still valid (wasn't deleted) */ -static bool StationHandleBigTick(Station *st) +static bool StationHandleBigTick(BaseStation *st) { - UpdateStationAcceptance(st, true); - - if (st->facilities == 0 && ++st->delete_ctr >= 8) { + if ((st->facilities & ~FACIL_WAYPOINT) == 0 && ++st->delete_ctr >= 8) { delete st; return false; } + if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true); + return true; } @@ -2778,23 +2768,23 @@ static void UpdateStationRating(Station } /* called for every station each tick */ -static void StationHandleSmallTick(Station *st) +static void StationHandleSmallTick(BaseStation *st) { - if (st->facilities == 0) return; + if ((st->facilities & FACIL_WAYPOINT) != 0 || st->facilities == 0) return; byte b = st->delete_ctr + 1; if (b >= 185) b = 0; st->delete_ctr = b; - if (b == 0) UpdateStationRating(st); + if (b == 0) UpdateStationRating(Station::From(st)); } void OnTick_Station() { if (_game_mode == GM_EDITOR) return; - Station *st; - FOR_ALL_STATIONS(st) { + BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { StationHandleSmallTick(st); /* Run 250 tick interval trigger for station animation. @@ -2884,7 +2874,7 @@ CommandCost CmdRenameStation(TileIndex t } /** - * Find all (non-buoy) stations around a rectangular producer (industry, house, headquarter, ...) + * Find all stations around a rectangular producer (industry, house, headquarter, ...) * * @param tile North tile of producer * @param w_prod X extent of producer @@ -2903,8 +2893,7 @@ void FindStationsAroundTiles(TileIndex t if (cur_tile == INVALID_TILE || !IsTileType(cur_tile, MP_STATION)) continue; Station *st = Station::GetByTile(cur_tile); - - if (st->IsBuoy()) continue; // bouys don't accept cargo + if (st == NULL) continue; if (_settings_game.station.modified_catchment) { int rad = st->GetCatchmentRadius(); @@ -3120,12 +3109,13 @@ static CommandCost ClearTile_Station(Til if (flags & DC_AUTO) { switch (GetStationType(tile)) { default: break; - case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD); - case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST); - case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); - case STATION_BUS: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); - case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY); - case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST); + case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD); + case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED); + case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST); + case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); + case STATION_BUS: return_cmd_error(HasTileRoadType(tile, ROADTYPE_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); + case STATION_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY); + case STATION_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_FIRST); case STATION_OILRIG: SetDParam(0, STR_INDUSTRY_NAME_OIL_RIG); return_cmd_error(STR_OBJECT_IN_THE_WAY); @@ -3133,8 +3123,9 @@ static CommandCost ClearTile_Station(Til } switch (GetStationType(tile)) { - case STATION_RAIL: return RemoveRailroadStation(tile, flags); - case STATION_AIRPORT: return RemoveAirport(tile, flags); + case STATION_RAIL: return RemoveRailroadStation(tile, flags); + case STATION_WAYPOINT: return RemoveTrainWaypoint(tile, flags, false); + case STATION_AIRPORT: return RemoveAirport(tile, flags); case STATION_TRUCK: if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); @@ -3143,8 +3134,8 @@ static CommandCost ClearTile_Station(Til if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); return RemoveRoadStop(tile, flags); - case STATION_BUOY: return RemoveBuoy(tile, flags); - case STATION_DOCK: return RemoveDock(tile, flags); + case STATION_BUOY: return RemoveBuoy(tile, flags); + case STATION_DOCK: return RemoveDock(tile, flags); default: break; } @@ -3159,6 +3150,7 @@ static CommandCost TerraformTile_Station */ if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) { switch (GetStationType(tile)) { + case STATION_WAYPOINT: case STATION_RAIL: { DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile)); if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break; diff --git a/src/station_gui.cpp b/src/station_gui.cpp --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -143,7 +143,7 @@ protected: const Station *st; FOR_ALL_STATIONS(st) { - if (st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy() && HasStationInUse(st->index, owner))) { + if (st->owner == owner || (st->owner == OWNER_NONE && HasStationInUse(st->index, owner))) { if (this->facilities & st->facilities) { // only stations with selected facilities int num_waiting_cargo = 0; for (CargoID j = 0; j < NUM_CARGO; j++) { @@ -378,7 +378,7 @@ public: /* Do not do the complex check HasStationInUse here, it may be even false * when the order had been removed and the station list hasn't been removed yet */ - assert(st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy())); + assert(st->owner == owner || st->owner == OWNER_NONE); SetDParam(0, st->index); SetDParam(1, st->facilities); @@ -409,7 +409,7 @@ public: const Station *st = this->stations[id_v]; /* do not check HasStationInUse - it is slow and may be invalid */ - assert(st->owner == (Owner)this->window_number || (st->owner == OWNER_NONE && !st->IsBuoy())); + assert(st->owner == (Owner)this->window_number || st->owner == OWNER_NONE); if (_ctrl_pressed) { ShowExtraViewPortWindow(st->xy); diff --git a/src/station_map.h b/src/station_map.h --- a/src/station_map.h +++ b/src/station_map.h @@ -88,6 +88,28 @@ static inline bool IsRailwayStationTile( return IsTileType(t, MP_STATION) && IsRailwayStation(t); } +/** + * Is this station tile a rail waypoint? + * @param t the tile to get the information from + * @pre IsTileType(t, MP_STATION) + * @return true if and only if the tile is a rail waypoint + */ +static inline bool IsRailWaypoint(TileIndex t) +{ + return GetStationType(t) == STATION_WAYPOINT; +} + +/** + * Is this tile a station tile and a rail waypoint? + * @param t the tile to get the information from + * @return true if and only if the tile is a rail waypoint + */ +static inline bool IsRailWaypointTile(TileIndex t) +{ + return IsTileType(t, MP_STATION) && IsRailWaypoint(t); +} + + static inline bool IsAirport(TileIndex t) { return GetStationType(t) == STATION_AIRPORT; @@ -186,7 +208,7 @@ static inline bool IsHangarTile(TileInde static inline Axis GetRailStationAxis(TileIndex t) { - assert(IsRailwayStation(t)); + assert(IsRailwayStation(t) || IsRailWaypoint(t)); return HasBit(GetStationGfx(t), 0) ? AXIS_Y : AXIS_X; } @@ -214,31 +236,31 @@ static inline bool IsCompatibleTrainStat /** * Get the reservation state of the rail station - * @pre IsRailwayStationTile(t) + * @pre IsRailwayStation(t) || IsRailWaypoint(t) * @param t the station tile * @return reservation state */ static inline bool HasStationReservation(TileIndex t) { - assert(IsRailwayStationTile(t)); + assert(IsRailwayStation(t) || IsRailWaypoint(t)); return HasBit(_m[t].m6, 2); } /** * Set the reservation state of the rail station - * @pre IsRailwayStationTile(t) + * @pre IsRailwayStation(t) || IsRailWaypoint(t) * @param t the station tile * @param b the reservation state */ static inline void SetRailwayStationReservation(TileIndex t, bool b) { - assert(IsRailwayStationTile(t)); + assert(IsRailwayStation(t) || IsRailWaypoint(t)); SB(_m[t].m6, 2, 1, b ? 1 : 0); } /** * Get the reserved track bits for a waypoint - * @pre IsRailwayStationTile(t) + * @pre IsRailwayStation(t) || IsRailWaypoint(t) * @param t the tile * @return reserved track bits */ @@ -325,6 +347,13 @@ static inline void MakeRailStation(TileI SetRailwayStationReservation(t, false); } +static inline void MakeRailWaypoint(TileIndex t, Owner o, StationID sid, Axis a, byte section, RailType rt) +{ + MakeStation(t, o, sid, STATION_WAYPOINT, section + a); + SetRailType(t, rt); + SetRailwayStationReservation(t, false); +} + static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopType rst, RoadTypes rt, DiagDirection d) { MakeStation(t, o, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), d); diff --git a/src/station_type.h b/src/station_type.h --- a/src/station_type.h +++ b/src/station_type.h @@ -57,9 +57,8 @@ enum StationHadVehicleOfType { HVOT_TRUCK = 1 << 3, ///< Station has seen a truck HVOT_AIRCRAFT = 1 << 4, ///< Station has seen an aircraft HVOT_SHIP = 1 << 5, ///< Station has seen a ship - /* This bit is used to mark stations. No, it does not belong here, but what - * can we do? ;-) */ - HVOT_BUOY = 1 << 6 + + HVOT_WAYPOINT = 1 << 6, ///< Station is a waypoint (NewGRF only!) }; DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType); typedef SimpleTinyEnumT StationHadVehicleOfTypeByte; diff --git a/src/strings.cpp b/src/strings.cpp --- a/src/strings.cpp +++ b/src/strings.cpp @@ -863,8 +863,8 @@ static char *FormatString(char *buff, co int64 temp[2]; temp[0] = wp->town->index; temp[1] = wp->town_cn + 1; - StringID str = wp->town_cn == 0 ? STR_WAYPOINTNAME_CITY : STR_WAYPOINTNAME_CITY_SERIAL; - + StringID str = ((wp->string_id == STR_SV_STNAME_BUOY) ? STR_BUOYNAME_CITY : STR_WAYPOINTNAME_CITY); + if (wp->town_cn != 0) str++; buff = GetStringWithArgs(buff, str, temp, last); } break; diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -635,10 +635,10 @@ static void ResetLandscapeConfirmationCa _generating_world = false; /* Delete all station signs */ - Station *st; - FOR_ALL_STATIONS(st) { + BaseStation *st; + FOR_ALL_BASE_STATIONS(st) { /* There can be buoys, remove them */ - if (st->IsBuoy() && IsBuoyTile(st->xy)) DoCommand(st->xy, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); + if (IsBuoyTile(st->xy)) DoCommand(st->xy, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR); if (st->facilities == 0) delete st; } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -482,7 +482,7 @@ static int GetTrainAcceleration(Train *v assert(max_speed == GetTrainCurveSpeedLimit(v)); // safety check, will be removed later int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h - if (IsTileType(v->tile, MP_STATION) && v->IsFrontEngine()) { + if (IsRailwayStationTile(v->tile) && v->IsFrontEngine()) { StationID sid = GetStationIndex(v->tile); if (v->current_order.ShouldStopAtStation(v, sid)) { int station_ahead; @@ -4443,12 +4443,10 @@ static bool TrainLocoHandler(Train *v, b OrderType order_type = v->current_order.GetType(); /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */ - if ((order_type == OT_GOTO_WAYPOINT && - v->dest_tile == v->tile) || - (order_type == OT_GOTO_STATION && + if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && IsTileType(v->tile, MP_STATION) && - v->current_order.GetDestination() == GetStationIndex(v->tile))) { + v->current_order.GetDestination() == GetStationIndex(v->tile)) { ProcessOrders(v); } } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -788,8 +788,6 @@ static void DrawSmallOrderList(const Veh sel--; if (order->IsType(OT_GOTO_STATION)) { - if (v->type == VEH_SHIP && Station::Get(order->GetDestination())->IsBuoy()) continue; - SetDParam(0, order->GetDestination()); DrawString(left, right, y, STR_ORDER_STATION_SMALL); @@ -1950,7 +1948,7 @@ struct VehicleViewWindow : Window { case OT_GOTO_WAYPOINT: { assert(v->type == VEH_TRAIN || v->type == VEH_SHIP); SetDParam(0, v->current_order.GetDestination()); - str = (v->type == VEH_TRAIN ? STR_HEADING_FOR_WAYPOINT : STR_HEADING_FOR_STATION) + _settings_client.gui.vehicle_speed; + str = STR_HEADING_FOR_WAYPOINT + _settings_client.gui.vehicle_speed; SetDParam(1, v->GetDisplaySpeed()); break; } diff --git a/src/viewport.cpp b/src/viewport.cpp --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1218,7 +1218,7 @@ static void ViewportAddSigns(DrawPixelIn static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width) { - AddStringToDraw(wp->sign.left + 1, wp->sign.top + 1, str, wp->index, 0, (wp->delete_ctr != 0 ? 0xE : _company_colours[wp->owner]), width); + AddStringToDraw(wp->sign.left + 1, wp->sign.top + 1, str, wp->index, 0, (wp->owner == OWNER_NONE || (wp->facilities & ~FACIL_WAYPOINT) == 0) ? 0xE : _company_colours[wp->owner], width); } diff --git a/src/waypoint.cpp b/src/waypoint.cpp --- a/src/waypoint.cpp +++ b/src/waypoint.cpp @@ -12,23 +12,6 @@ #include "window_func.h" #include "newgrf_station.h" #include "order_func.h" -#include "core/pool_func.hpp" - -WaypointPool _waypoint_pool("Waypoint"); -INSTANTIATE_POOL_METHODS(Waypoint) - -/** - * Daily loop for waypoints - */ -void WaypointsDailyLoop() -{ - Waypoint *wp; - - /* Check if we need to delete a waypoint */ - FOR_ALL_WAYPOINTS(wp) { - if (wp->delete_ctr != 0 && --wp->delete_ctr == 0) delete wp; - } -} /** * Draw a waypoint @@ -67,8 +50,3 @@ Waypoint::~Waypoint() this->sign.MarkDirty(); } - -void InitializeWaypoints() -{ - _waypoint_pool.CleanPool(); -} diff --git a/src/waypoint.h b/src/waypoint.h --- a/src/waypoint.h +++ b/src/waypoint.h @@ -14,10 +14,7 @@ #include "date_type.h" #include "core/pool_type.hpp" -typedef Pool WaypointPool; -extern WaypointPool _waypoint_pool; - -struct Waypoint : WaypointPool::PoolItem<&_waypoint_pool>, SpecializedStation { +struct Waypoint : SpecializedStation { uint16 town_cn; ///< The Nth waypoint for this town (consecutive number) Waypoint(TileIndex tile = INVALID_TILE) : SpecializedStation(tile) { } @@ -27,29 +24,19 @@ struct Waypoint : WaypointPool::PoolItem /* virtual */ FORCEINLINE bool TileBelongsToRailStation(TileIndex tile) const { - return this->delete_ctr == 0 && this->xy == tile; + return IsRailWaypointTile(tile) && GetStationIndex(tile) == this->index; } /* virtual */ uint32 GetNewGRFVariable(const struct ResolverObject *object, byte variable, byte parameter, bool *available) const; /* virtual */ void GetTileArea(TileArea *ta, StationType type) const; - - /** - * Fetch a waypoint by tile - * @param tile Tile of waypoint - * @return Waypoint - */ - static FORCEINLINE Waypoint *GetByTile(TileIndex tile) - { - return Waypoint::Get(GetWaypointIndex(tile)); - } }; -#define FOR_ALL_WAYPOINTS_FROM(var, start) FOR_ALL_ITEMS_FROM(Waypoint, waypoint_index, var, start) -#define FOR_ALL_WAYPOINTS(var) FOR_ALL_WAYPOINTS_FROM(var, 0) +#define FOR_ALL_WAYPOINTS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Waypoint, var) CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justremove); void ShowWaypointWindow(const Waypoint *wp); void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype); +void MakeDefaultWaypointName(Waypoint *wp); #endif /* WAYPOINT_H */ diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -39,7 +39,7 @@ void Waypoint::UpdateVirtCoord() * Set the default name for a waypoint * @param wp Waypoint to work on */ -static void MakeDefaultWaypointName(Waypoint *wp) +void MakeDefaultWaypointName(Waypoint *wp) { uint32 used = 0; // bitmap of used waypoint numbers, sliding window with 'next' as base uint32 next = 0; // first waypoint number in the bitmap @@ -64,7 +64,7 @@ static void MakeDefaultWaypointName(Wayp /* check only valid waypoints... */ if (lwp != NULL && wp != lwp) { /* only waypoints with 'generic' name within the same city */ - if (lwp->name == NULL && lwp->town == wp->town) { + if (lwp->name == NULL && lwp->town == wp->town && lwp->string_id == wp->string_id) { /* if lwp->town_cn < next, uint will overflow to '+inf' */ uint i = (uint)lwp->town_cn - next; @@ -104,7 +104,7 @@ static Waypoint *FindDeletedWaypointClos uint thres = 8; FOR_ALL_WAYPOINTS(wp) { - if (wp->delete_ctr != 0 && wp->owner == _current_company) { + if ((wp->facilities & ~FACIL_WAYPOINT) == 0 && wp->owner == _current_company) { uint cur_dist = DistanceManhattan(tile, wp->xy); if (cur_dist < thres) { @@ -163,10 +163,6 @@ CommandCost CmdBuildTrainWaypoint(TileIn if (flags & DC_EXEC) { if (wp == NULL) { wp = new Waypoint(tile); - - wp->town = NULL; - wp->name = NULL; - wp->town_cn = 0; } else { /* Move existing (recently deleted) waypoint to the new location */ @@ -186,15 +182,16 @@ CommandCost CmdBuildTrainWaypoint(TileIn wp->owner = owner; bool reserved = HasBit(GetRailReservationTrackBits(tile), AxisToTrack(axis)); - MakeRailWaypoint(tile, owner, axis, GetRailType(tile), wp->index); - SetDepotReservation(tile, reserved); + MakeRailWaypoint(tile, owner, wp->index, axis, 0, GetRailType(tile)); + SetRailwayStationReservation(tile, reserved); MarkTileDirtyByTile(tile); - AllocateSpecToStation(GetCustomStationSpec(STAT_CLASS_WAYP, p1), wp, true); + SetCustomStationSpecIndex(tile, AllocateSpecToStation(GetCustomStationSpec(STAT_CLASS_WAYP, p1), wp, true)); wp->delete_ctr = 0; wp->facilities |= FACIL_TRAIN; wp->build_date = _date; + wp->string_id = STR_SV_STNAME_WAYPOINT; if (wp->town == NULL) MakeDefaultWaypointName(wp); @@ -224,22 +221,22 @@ CommandCost RemoveTrainWaypoint(TileInde } if (flags & DC_EXEC) { - Track track = GetRailWaypointTrack(tile); + Track track = GetRailStationTrack(tile); wp = Waypoint::GetByTile(tile); - wp->delete_ctr = 30; // let it live for this many days before we do the actual deletion. wp->sign.MarkDirty(); wp->facilities &= ~FACIL_TRAIN; Train *v = NULL; + uint specindex = GetCustomStationSpecIndex(tile); if (justremove) { - TrackBits tracks = GetRailWaypointBits(tile); - bool reserved = HasDepotReservation(tile); + TrackBits tracks = GetRailStationTrackBits(tile); + bool reserved = HasStationReservation(tile); MakeRailNormal(tile, wp->owner, tracks, GetRailType(tile)); if (reserved) SetTrackReservation(tile, tracks); MarkTileDirtyByTile(tile); } else { - if (HasDepotReservation(tile)) { + if (HasStationReservation(tile)) { v = GetTrainForReservation(tile, track); if (v != NULL) FreeTrainTrackReservation(v); } @@ -249,7 +246,7 @@ CommandCost RemoveTrainWaypoint(TileInde YapfNotifyTrackLayoutChange(tile, track); if (v != NULL) TryPathReserve(v, true); - DeallocateSpecFromStation(wp, wp->num_specs > 0 ? 1 : 0); + DeallocateSpecFromStation(wp, specindex); } return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot); @@ -290,7 +287,7 @@ static bool IsUniqueWaypointName(const c CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Waypoint *wp = Waypoint::GetIfValid(p1); - if (wp == NULL || !CheckOwnership(wp->owner)) return CMD_ERROR; + if (wp == NULL || !(CheckOwnership(wp->owner) || wp->owner == OWNER_NONE)) return CMD_ERROR; bool reset = StrEmpty(text); diff --git a/src/waypoint_gui.cpp b/src/waypoint_gui.cpp --- a/src/waypoint_gui.cpp +++ b/src/waypoint_gui.cpp @@ -37,7 +37,7 @@ public: WaypointWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number) { this->wp = Waypoint::Get(this->window_number); - this->vt = (wp->facilities & FACIL_TRAIN) ? VEH_TRAIN : VEH_SHIP; + this->vt = (wp->string_id == STR_SV_STNAME_WAYPOINT) ? VEH_TRAIN : VEH_SHIP; if (this->wp->owner != OWNER_NONE) this->owner = this->wp->owner; diff --git a/src/yapf/yapf_costrail.hpp b/src/yapf/yapf_costrail.hpp --- a/src/yapf/yapf_costrail.hpp +++ b/src/yapf/yapf_costrail.hpp @@ -406,7 +406,7 @@ no_entry_cost: // jump here at the begin /* We will end in this pass (station is possible target) */ end_segment_reason |= ESRB_STATION; - } else if (cur.tile_type == MP_RAILWAY && IsRailWaypoint(cur.tile)) { + } else if (cur.tile_type == MP_STATION && IsRailWaypoint(cur.tile)) { /* Waypoint is also a good reason to finish. */ end_segment_reason |= ESRB_WAYPOINT; } else if (TrackFollower::DoTrackMasking() && cur.tile_type == MP_RAILWAY) { diff --git a/src/yapf/yapf_destrail.hpp b/src/yapf/yapf_destrail.hpp --- a/src/yapf/yapf_destrail.hpp +++ b/src/yapf/yapf_destrail.hpp @@ -134,22 +134,11 @@ public: m_destTrackdirs = INVALID_TRACKDIR_BIT; break; - case OT_GOTO_WAYPOINT: { - Waypoint *wp = Waypoint::Get(v->current_order.GetDestination()); - if (wp == NULL) { - /* Invalid waypoint in orders! */ - DEBUG(yapf, 0, "Invalid waypoint in orders == 0x%04X (train %d, company %d)", v->current_order.GetDestination(), v->unitnumber, (CompanyID)v->owner); - break; - } - m_destTile = wp->xy; - if (m_destTile != v->dest_tile) { - /* Something is wrong with orders! */ - DEBUG(yapf, 0, "Invalid v->dest_tile == 0x%04X (train %d, company %d)", v->dest_tile, v->unitnumber, (CompanyID)v->owner); - } + case OT_GOTO_WAYPOINT: + m_destTile = Waypoint::Get(v->current_order.GetDestination())->xy; m_dest_station_id = INVALID_STATION; - m_destTrackdirs = TrackToTrackdirBits(AxisToTrack(GetWaypointAxis(wp->xy))); + m_destTrackdirs = IsRailWaypointTile(m_destTile) ? TrackToTrackdirBits(GetRailStationTrack(m_destTile)) : INVALID_TRACKDIR_BIT; break; - } default: m_destTile = v->dest_tile;