(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.
replace/41b28d7194a279bdc17475d4fbe2ea6ec885a466
rubidium 15 years ago
parent 2646a99d29
commit 68ead6b84f

@ -3,12 +3,12 @@
/** @file ai_buoylist.cpp Implementation of AIBuoyList and friends. */ /** @file ai_buoylist.cpp Implementation of AIBuoyList and friends. */
#include "ai_buoylist.hpp" #include "ai_buoylist.hpp"
#include "../../station_base.h" #include "../../waypoint.h"
AIBuoyList::AIBuoyList() AIBuoyList::AIBuoyList()
{ {
Station *st; Waypoint *wp;
FOR_ALL_STATIONS(st) { FOR_ALL_WAYPOINTS(wp) {
if (st->IsBuoy()) this->AddItem(st->xy); if (wp->facilities & FACIL_DOCK) this->AddItem(wp->xy);
} }
} }

@ -25,18 +25,14 @@ static OrderType GetOrderTypeByTile(TileIndex t)
switch (::GetTileType(t)) { switch (::GetTileType(t)) {
default: break; default: break;
case MP_STATION: case MP_STATION:
if (IsBuoy(t) || IsRailWaypoint(t)) return OT_GOTO_WAYPOINT;
if (IsHangar(t)) return OT_GOTO_DEPOT; if (IsHangar(t)) return OT_GOTO_DEPOT;
if (IsBuoy(t)) return OT_GOTO_WAYPOINT;
return OT_GOTO_STATION; return OT_GOTO_STATION;
break; break;
case MP_WATER: if (::IsShipDepot(t)) return OT_GOTO_DEPOT; 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_ROAD: if (::GetRoadTileType(t) == ROAD_TILE_DEPOT) return OT_GOTO_DEPOT; break;
case MP_RAILWAY: case MP_RAILWAY:
switch (::GetRailTileType(t)) { if (IsRailDepot(t)) return OT_GOTO_DEPOT;
case RAIL_TILE_DEPOT: return OT_GOTO_DEPOT;
case RAIL_TILE_WAYPOINT: return OT_GOTO_WAYPOINT;
default: break;
}
break; break;
} }
@ -359,7 +355,7 @@ static const Order *ResolveOrder(VehicleID vehicle_id, AIOrder::OrderPosition or
break; break;
case OT_GOTO_WAYPOINT: case OT_GOTO_WAYPOINT:
order.MakeGoToWaypoint(::Vehicle::Get(vehicle_id)->type == VEH_TRAIN ? ::GetWaypointIndex(destination) : ::GetStationIndex(destination)); order.MakeGoToWaypoint(::GetStationIndex(destination));
break; break;
default: default:

@ -45,7 +45,7 @@
{ {
if (!::IsValidTile(tile)) return false; if (!::IsValidTile(tile)) return false;
return ::IsTileType(tile, MP_RAILWAY) && ::IsRailWaypointTile(tile); return ::IsRailWaypointTile(tile);
} }
/* static */ bool AIRail::IsRailTypeAvailable(RailType rail_type) /* static */ bool AIRail::IsRailTypeAvailable(RailType rail_type)
@ -200,8 +200,7 @@
{ {
if (!IsRailTile(tile)) return RAILTRACK_INVALID; if (!IsRailTile(tile)) return RAILTRACK_INVALID;
if (IsRailWaypointTile(tile)) return ::GetRailWaypointBits(tile); if (IsRailStationTile(tile) || IsRailWaypointTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile));
if (IsRailStationTile(tile)) return ::TrackToTrackBits(::GetRailStationTrack(tile));
if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile); if (IsLevelCrossingTile(tile)) return ::GetCrossingRailBits(tile);
if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE; if (IsRailDepotTile(tile)) return ::TRACK_BIT_NONE;
return ::GetTrackBits(tile); return ::GetTrackBits(tile);

@ -22,7 +22,7 @@
{ {
if (!AIRail::IsRailWaypointTile(tile)) return WAYPOINT_INVALID; if (!AIRail::IsRailWaypointTile(tile)) return WAYPOINT_INVALID;
return ::GetWaypointIndex(tile); return ::GetStationIndex(tile);
} }
/* static */ char *AIWaypoint::GetName(WaypointID waypoint_id) /* static */ char *AIWaypoint::GetName(WaypointID waypoint_id)

@ -13,7 +13,7 @@ AIWaypointList::AIWaypointList()
{ {
const Waypoint *wp; const Waypoint *wp;
FOR_ALL_WAYPOINTS(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);
} }
} }

@ -154,7 +154,6 @@ Date ConvertYMDToDate(Year year, Month month, Day day)
/** Functions used by the IncreaseDate function */ /** Functions used by the IncreaseDate function */
extern void WaypointsDailyLoop();
extern void EnginesDailyLoop(); extern void EnginesDailyLoop();
extern void DisasterDailyLoop(); extern void DisasterDailyLoop();
extern void IndustryDailyLoop(); extern void IndustryDailyLoop();
@ -222,7 +221,6 @@ void IncreaseDate()
#endif /* ENABLE_NETWORK */ #endif /* ENABLE_NETWORK */
DisasterDailyLoop(); DisasterDailyLoop();
WaypointsDailyLoop();
IndustryDailyLoop(); IndustryDailyLoop();
if (_game_mode != GM_MENU) { if (_game_mode != GM_MENU) {

@ -81,8 +81,6 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
switch (GetRailTileType(t)) { switch (GetRailTileType(t)) {
case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS: case RAIL_TILE_NORMAL: case RAIL_TILE_SIGNALS:
return GetTrackBits(t); return GetTrackBits(t);
case RAIL_TILE_WAYPOINT:
return GetRailWaypointBits(t);
default: default:
return TRACK_BIT_NONE; return TRACK_BIT_NONE;
} }
@ -101,7 +99,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
return GetCrossingRailBits(t); return GetCrossingRailBits(t);
case MP_STATION: 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 (!HasCatenary(GetRailType(t))) return TRACK_BIT_NONE;
if (!IsStationTileElectrifiable(t)) return TRACK_BIT_NONE; if (!IsStationTileElectrifiable(t)) return TRACK_BIT_NONE;
return TrackToTrackBits(GetRailStationTrack(t)); return TrackToTrackBits(GetRailStationTrack(t));

@ -1185,8 +1185,10 @@ STR_HEADING_FOR_WAYPOINT_VEL :{LTBLUE}Heading
STR_GO_TO_WAYPOINT :Go via {WAYPOINT} STR_GO_TO_WAYPOINT :Go via {WAYPOINT}
STR_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT} STR_GO_NON_STOP_TO_WAYPOINT :Go non-stop via {WAYPOINT}
STR_WAYPOINTNAME_CITY :Waypoint {TOWN} STR_WAYPOINTNAME_CITY :{TOWN} Waypoint
STR_WAYPOINTNAME_CITY_SERIAL :Waypoint {TOWN} #{COMMA} STR_WAYPOINTNAME_CITY_SERIAL :{TOWN} Waypoint #{COMMA}
STR_BUOYNAME_CITY :{TOWN} Buoy
STR_BUOYNAME_CITY_SERIAL :{TOWN} Buoy #{COMMA}
STR_LANDINFO_WAYPOINT :Waypoint STR_LANDINFO_WAYPOINT :Waypoint
STR_WAYPOINT :{WHITE}Waypoint STR_WAYPOINT :{WHITE}Waypoint
@ -2077,15 +2079,9 @@ STR_SV_STNAME_AIRPORT :{STRING1} Airpo
STR_SV_STNAME_OILFIELD :{STRING1} Oilfield STR_SV_STNAME_OILFIELD :{STRING1} Oilfield
STR_SV_STNAME_MINES :{STRING1} Mines STR_SV_STNAME_MINES :{STRING1} Mines
STR_SV_STNAME_DOCKS :{STRING1} Docks STR_SV_STNAME_DOCKS :{STRING1} Docks
STR_SV_STNAME_BUOY_1 :{STRING1} Buoy 1 STR_SV_STNAME_BUOY :{STRING2}
STR_SV_STNAME_BUOY_2 :{STRING1} Buoy 2 STR_SV_STNAME_WAYPOINT :{STRING2}
STR_SV_STNAME_BUOY_3 :{STRING1} Buoy 3 ##id 0x6020
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_ANNEXE :{STRING1} Annexe STR_SV_STNAME_ANNEXE :{STRING1} Annexe
STR_SV_STNAME_SIDINGS :{STRING1} Sidings STR_SV_STNAME_SIDINGS :{STRING1} Sidings
STR_SV_STNAME_BRANCH :{STRING1} Branch STR_SV_STNAME_BRANCH :{STRING1} Branch

@ -31,7 +31,6 @@ extern TileIndex _cur_tileloop_tile;
extern void MakeNewgameSettingsLive(); extern void MakeNewgameSettingsLive();
void InitializeVehicles(); void InitializeVehicles();
void InitializeWaypoints();
void InitializeDepots(); void InitializeDepots();
void InitializeEngineRenews(); void InitializeEngineRenews();
void InitializeOrders(); void InitializeOrders();
@ -79,7 +78,6 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date)
InitializeEngineRenews(); InitializeEngineRenews();
InitializeVehicles(); InitializeVehicles();
InitializeWaypoints();
InitializeDepots(); InitializeDepots();
InitializeOrders(); InitializeOrders();
InitializeGroup(); InitializeGroup();

@ -272,30 +272,20 @@ uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, i
*/ */
static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis) static TileIndex FindRailStationEnd(TileIndex tile, TileIndexDiff delta, bool check_type, bool check_axis)
{ {
bool waypoint;
byte orig_type = 0; byte orig_type = 0;
Axis orig_axis = AXIS_X; Axis orig_axis = AXIS_X;
StationID sid = GetStationIndex(tile);
waypoint = IsTileType(tile, MP_RAILWAY); if (check_type) orig_type = GetCustomStationSpecIndex(tile);
if (check_axis) orig_axis = GetRailStationAxis(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);
}
while (true) { while (true) {
TileIndex new_tile = TILE_ADD(tile, delta); TileIndex new_tile = TILE_ADD(tile, delta);
if (waypoint) { if (!IsTileType(new_tile, MP_STATION) || GetStationIndex(new_tile) != sid) break;
if (!IsRailWaypointTile(new_tile)) break; if (!IsRailwayStation(new_tile) && !IsRailWaypoint(new_tile)) break;
if (check_axis && GetWaypointAxis(new_tile) != orig_axis) break; if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
} else { if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
if (!IsRailwayStationTile(new_tile)) break;
if (check_type && GetCustomStationSpecIndex(new_tile) != orig_type) break;
if (check_axis && GetRailStationAxis(new_tile) != orig_axis) break;
}
tile = new_tile; tile = new_tile;
} }
@ -311,12 +301,11 @@ static uint32 GetPlatformInfoHelper(TileIndex tile, bool check_type, bool check_
int sy = TileY(FindRailStationEnd(tile, TileDiffXY( 0, -1), 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 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; 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; tx -= sx; ex -= sx;
ty -= sy; ey -= sy; 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(TileIndex tile)
static const Direction y_dir[8] = { DIR_SE, DIR_NW, DIR_SW, DIR_NE, DIR_S, DIR_W, DIR_E, DIR_N }; 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 }; 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 */ /* Choose appropriate lookup table to use */
const Direction *dir = axis == AXIS_X ? x_dir : y_dir; const Direction *dir = axis == AXIS_X ? x_dir : y_dir;
@ -450,12 +439,7 @@ static uint32 StationGetVariable(const ResolverObject *object, byte variable, by
case 0x42: return GetTerrainType(tile) | (GetRailType(tile) << 8); case 0x42: return GetTerrainType(tile) | (GetRailType(tile) << 8);
case 0x43: return st->owner; // Station owner case 0x43: return st->owner; // Station owner
case 0x44: case 0x44: return HasStationReservation(tile) ? 7 : 4; // PBS status
if (IsRailWaypointTile(tile)) {
return HasDepotReservation(tile) ? 7 : 4;
} else {
return HasStationReservation(tile) ? 7 : 4; // PBS status
}
case 0x45: case 0x45:
if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(tile); SetBit(_svc.valid, 2); } if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(tile); SetBit(_svc.valid, 2); }
return _svc.v45; return _svc.v45;
@ -583,7 +567,7 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject *object, byte variable,
{ {
switch (variable) { switch (variable) {
case 0x48: return 0; // Accepted cargo types case 0x48: return 0; // Accepted cargo types
case 0x8A: return HVOT_TRAIN; case 0x8A: return HVOT_WAYPOINT;
case 0xF1: return 0; // airport type case 0xF1: return 0; // airport type
case 0xF2: return 0; // truck stop status case 0xF2: return 0; // truck stop status
case 0xF3: return 0; // bus stop status case 0xF3: return 0; // bus stop status
@ -944,20 +928,11 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID
const StationSpec *GetStationSpec(TileIndex t) const StationSpec *GetStationSpec(TileIndex t)
{ {
if (IsRailwayStationTile(t)) { if (!IsCustomStationSpecIndex(t)) return NULL;
if (!IsCustomStationSpecIndex(t)) return NULL;
const BaseStation *st = BaseStation::GetByTile(t); const BaseStation *st = BaseStation::GetByTile(t);
uint specindex = GetCustomStationSpecIndex(t); uint specindex = GetCustomStationSpecIndex(t);
return specindex < st->num_specs ? st->speclist[specindex].spec : NULL; 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;
} }

@ -542,18 +542,19 @@ CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
} }
case OT_GOTO_WAYPOINT: { case OT_GOTO_WAYPOINT: {
const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination());
if (wp == NULL) return CMD_ERROR;
switch (v->type) { switch (v->type) {
default: return CMD_ERROR; default: return CMD_ERROR;
case VEH_TRAIN: { case VEH_TRAIN:
const Waypoint *wp = Waypoint::GetIfValid(new_order.GetDestination()); if (!CheckOwnership(wp->owner)) return CMD_ERROR;
if (wp == NULL || !CheckOwnership(wp->owner)) return CMD_ERROR; break;
} break;
case VEH_SHIP: { case VEH_SHIP:
const Station *st = Station::GetIfValid(new_order.GetDestination()); if (!CheckOwnership(wp->owner) && wp->owner != OWNER_NONE) return CMD_ERROR;
if (st == NULL || (!CheckOwnership(st->owner) && st->owner != OWNER_NONE)) return CMD_ERROR; break;
} break;
} }
/* Order flags can be any of the following for waypoints: /* Order flags can be any of the following for waypoints:

@ -253,15 +253,8 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
break; break;
case OT_GOTO_WAYPOINT: 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(1, (order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) ? STR_GO_NON_STOP_TO_WAYPOINT : STR_GO_TO_WAYPOINT); SetDParam(2, order->GetDestination());
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);
}
break; break;
case OT_CONDITIONAL: case OT_CONDITIONAL:
@ -357,7 +350,7 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
return order; 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)); order.MakeGoToWaypoint(GetStationIndex(tile));
return order; return order;
} }
@ -775,12 +768,9 @@ public:
this->SetWidgetLoweredState(ORDER_WIDGET_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS); this->SetWidgetLoweredState(ORDER_WIDGET_NON_STOP, order->GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS);
switch (order->GetType()) { switch (order->GetType()) {
case OT_GOTO_STATION: 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_FULL_LOAD, order->GetLoadType() == OLF_FULL_LOAD_ANY); this->SetWidgetLoweredState(ORDER_WIDGET_UNLOAD, order->GetUnloadType() == OUFB_UNLOAD);
this->SetWidgetLoweredState(ORDER_WIDGET_UNLOAD, order->GetUnloadType() == OUFB_UNLOAD); break;
break;
}
/* Fall-through */
case OT_GOTO_WAYPOINT: case OT_GOTO_WAYPOINT:
this->DisableWidget(ORDER_WIDGET_FULL_LOAD_DROPDOWN); this->DisableWidget(ORDER_WIDGET_FULL_LOAD_DROPDOWN);

@ -26,7 +26,7 @@ TrackBits GetReservedTrackbits(TileIndex t)
break; break;
case MP_STATION: case MP_STATION:
if (IsRailwayStation(t)) return GetStationReservationTrackBits(t); if (IsRailwayStation(t) || IsRailWaypoint(t)) return GetStationReservationTrackBits(t);
break; break;
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:
@ -99,7 +99,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t)
break; break;
case MP_STATION: case MP_STATION:
if (IsRailwayStation(tile) && !HasStationReservation(tile)) { if ((IsRailwayStation(tile) || IsRailWaypoint(tile)) && !HasStationReservation(tile)) {
SetRailwayStationReservation(tile, true); SetRailwayStationReservation(tile, true);
MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track MarkTileDirtyByTile(tile); // some GRFs need redraw after reserving track
return true; return true;
@ -150,7 +150,7 @@ bool TryReserveRailTrack(TileIndex tile, Track t)
break; break;
case MP_STATION: case MP_STATION:
if (IsRailwayStation(tile)) { if (IsRailwayStation(tile) || IsRailWaypoint(tile)) {
SetRailwayStationReservation(tile, false); SetRailwayStationReservation(tile, false);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} }

@ -155,7 +155,7 @@ RailType GetTileRailType(TileIndex tile)
break; break;
case MP_STATION: case MP_STATION:
if (IsRailwayStationTile(tile)) return GetRailType(tile); if (IsRailwayStation(tile) || IsRailWaypoint(tile)) return GetRailType(tile);
break; break;
case MP_TUNNELBRIDGE: case MP_TUNNELBRIDGE:

@ -1281,7 +1281,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
case MP_RAILWAY: case MP_RAILWAY:
break; break;
case MP_STATION: case MP_STATION:
if (!IsRailwayStation(tile)) continue; if (!IsRailwayStation(tile) && !IsRailWaypoint(tile)) continue;
break; break;
case MP_ROAD: case MP_ROAD:
if (!IsLevelCrossing(tile)) continue; if (!IsLevelCrossing(tile)) continue;
@ -1329,14 +1329,6 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
switch (tt) { switch (tt) {
case MP_RAILWAY: case MP_RAILWAY:
switch (GetRailTileType(tile)) { 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: case RAIL_TILE_DEPOT:
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
/* notify YAPF about the track layout change */ /* notify YAPF about the track layout change */
@ -1501,9 +1493,6 @@ static CommandCost ClearTile_Track(TileIndex tile, DoCommandFlag flags)
case RAIL_TILE_DEPOT: case RAIL_TILE_DEPOT:
return RemoveTrainDepot(tile, flags); return RemoveTrainDepot(tile, flags);
case RAIL_TILE_WAYPOINT:
return RemoveTrainWaypoint(tile, flags, false);
default: default:
return CMD_ERROR; return CMD_ERROR;
} }
@ -1906,7 +1895,7 @@ static void DrawTile_Track(TileInfo *ti)
if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails); if (HasSignals(ti->tile)) DrawSignals(ti->tile, rails);
} else { } else {
/* draw depot/waypoint */ /* draw depot */
const DrawTileSprites *dts; const DrawTileSprites *dts;
const DrawTileSeqStruct *dtss; const DrawTileSeqStruct *dtss;
uint32 relocation; uint32 relocation;
@ -1914,78 +1903,37 @@ static void DrawTile_Track(TileInfo *ti)
if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED); if (ti->tileh != SLOPE_FLAT) DrawFoundation(ti, FOUNDATION_LEVELED);
if (IsRailDepot(ti->tile)) { if (IsInvisibilitySet(TO_BUILDINGS)) {
if (IsInvisibilitySet(TO_BUILDINGS)) { /* Draw rail instead of depot */
/* Draw rail instead of depot */ dts = &_depot_invisible_gfx_table[GetRailDepotDirection(ti->tile)];
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
}
}
} else { } else {
/* look for customization */ dts = &_depot_gfx_table[GetRailDepotDirection(ti->tile)];
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) { relocation = rti->total_offset;
dts = GetStationTileLayout(STATION_RAIL, gfx);
} else {
dts = &statspec->renderdata[(gfx < statspec->tiles ? gfx : 0) + GetWaypointAxis(ti->tile)];
}
if (dts != NULL && dts->seq != NULL) { image = dts->ground.sprite;
relocation = GetCustomStationRelocation(statspec, st, ti->tile); if (image != SPR_FLAT_GRASS_TILE) image += rti->total_offset;
image = dts->ground.sprite; /* adjust ground tile for desert
if (HasBit(image, SPRITE_MODIFIER_USE_OFFSET)) { * don't adjust for snow, because snow in depots looks weird */
image += GetCustomStationGroundRelocation(statspec, st, ti->tile); if (IsSnowRailGround(ti->tile) && _settings_game.game_creation.landscape == LT_TROPIC) {
image += rti->custom_ground_offset; if (image != SPR_FLAT_GRASS_TILE) {
} else { image += rti->snow_offset; // tile with tracks
image += rti->total_offset;
}
pal = dts->ground.pal;
} else {
goto default_waypoint;
}
} else { } else {
default_waypoint: image = SPR_FLAT_SNOWY_TILE; // flat ground
/* 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;
} }
} }
DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette)); DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, _drawtile_track_palette));
/* PBS debugging, draw reserved tracks darker */ /* PBS debugging, draw reserved tracks darker */
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasDepotReservation(ti->tile) && 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)) { switch (GetRailDepotDirection(ti->tile)) {
DrawGroundSprite(GetWaypointAxis(ti->tile) == AXIS_X ? rti->base_sprites.single_y : rti->base_sprites.single_x, PALETTE_CRASH); 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); if (HasCatenaryDrawn(GetRailType(ti->tile))) DrawCatenary(ti);
@ -2292,10 +2240,6 @@ static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode,
trackbits = DiagDirToDiagTrackBits(dir); trackbits = DiagDirToDiagTrackBits(dir);
break; break;
} }
case RAIL_TILE_WAYPOINT:
trackbits = GetRailWaypointBits(tile);
break;
} }
return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals); return CombineTrackStatus(TrackBitsToTrackdirBits(trackbits), red_signals);
@ -2303,11 +2247,10 @@ static TrackStatus GetTileTrackStatus_Track(TileIndex tile, TransportType mode,
static bool ClickTile_Track(TileIndex tile) static bool ClickTile_Track(TileIndex tile)
{ {
switch (GetRailTileType(tile)) { if (!IsRailDepot(tile)) return false;
case RAIL_TILE_DEPOT: ShowDepotWindow(tile, VEH_TRAIN); return true;
case RAIL_TILE_WAYPOINT: ShowWaypointWindow(Waypoint::GetByTile(tile)); return true; ShowDepotWindow(tile, VEH_TRAIN);
default: return false; return true;
}
} }
static void GetTileDesc_Track(TileIndex tile, TileDesc *td) static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
@ -2387,10 +2330,8 @@ static void GetTileDesc_Track(TileIndex tile, TileDesc *td)
td->str = STR_RAILROAD_TRAIN_DEPOT; td->str = STR_RAILROAD_TRAIN_DEPOT;
break; break;
case RAIL_TILE_WAYPOINT:
default: default:
td->str = STR_LANDINFO_WAYPOINT; NOT_REACHED();
break;
} }
} }
@ -2579,22 +2520,9 @@ static CommandCost TerraformTile_Track(TileIndex tile, DoCommandFlag flags, uint
/* allow terraforming */ /* allow terraforming */
return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price.clear_water : (Money)0); return CommandCost(EXPENSES_CONSTRUCTION, was_water ? _price.clear_water : (Money)0);
} else { } else if (_settings_game.construction.build_on_slopes && AutoslopeEnabled() &&
if (_settings_game.construction.build_on_slopes && AutoslopeEnabled()) { AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRailDepotDirection(tile))) {
switch (GetRailTileType(tile)) { return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
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();
}
}
} }
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
} }

@ -18,7 +18,6 @@
enum RailTileType { enum RailTileType {
RAIL_TILE_NORMAL = 0, ///< Normal rail tile without signals RAIL_TILE_NORMAL = 0, ///< Normal rail tile without signals
RAIL_TILE_SIGNALS = 1, ///< Normal rail tile with 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) RAIL_TILE_DEPOT = 3, ///< Depot (one entrance)
}; };
@ -82,27 +81,6 @@ static inline void SetHasSignals(TileIndex tile, bool signals)
SB(_m[tile].m5, 6, 1, signals); SB(_m[tile].m5, 6, 1, signals);
} }
/**
* 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? * Is this rail tile a rail depot?
* @param t the tile to get the information from * @param t the tile to get the information from
@ -202,51 +180,6 @@ static inline Track GetRailDepotTrack(TileIndex t)
} }
/**
* 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 * Returns the reserved track bits of the tile
* @pre IsPlainRailTile(t) * @pre IsPlainRailTile(t)
@ -335,17 +268,6 @@ static inline void SetDepotReservation(TileIndex t, bool b)
SB(_m[t].m5, 4, 1, (byte)b); SB(_m[t].m5, 4, 1, (byte)b);
} }
/**
* 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 * Get the reserved track bits for a depot
* @pre IsRailDepot(t) * @pre IsRailDepot(t)
@ -635,17 +557,4 @@ static inline void MakeRailDepot(TileIndex t, Owner o, DiagDirection d, RailType
_me[t].m7 = 0; _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 */ #endif /* RAIL_MAP_H */

@ -606,9 +606,7 @@ bool AfterLoadGame()
switch (GetTileType(t)) { switch (GetTileType(t)) {
case MP_STATION: { case MP_STATION: {
Station *st = Station::GetByTile(t); Station *st = Station::GetByTile(t);
if (st == NULL) break;
/* Set up station spread; buoys do not have one */
if (!IsBuoy(t)) st->rect.BeforeAddTile(t, StationRect::ADD_FORCE);
switch (GetStationType(t)) { switch (GetStationType(t)) {
case STATION_TRUCK: case STATION_TRUCK:
@ -987,29 +985,11 @@ bool AfterLoadGame()
FOR_ALL_COMPANIES(c) c->settings.renew_keep_length = false; FOR_ALL_COMPANIES(c) c->settings.renew_keep_length = false;
} }
/* In version 17, ground type is moved from m2 to m4 for depots and if (CheckSavegameVersion(123)) {
* waypoints to make way for storing the index in m2. The custom graphics /* Waypoints became subclasses of stations ... */
* id which was stored in m4 is now saved as a grf/id reference in the MoveWaypointsToBaseStations();
* waypoint struct. */ /* ... and buoys were moved to waypoints. */
if (CheckSavegameVersion(17)) { MoveBuoysToWaypoints();
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();
} }
/* From version 15, we moved a semaphore bit from bit 2 to bit 3 in m4, making /* 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 /* Buoys do now store the owner of the previous water tile, which can never
* be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */ * be OWNER_NONE. So replace OWNER_NONE with OWNER_WATER. */
if (CheckSavegameVersion(46)) { if (CheckSavegameVersion(46)) {
Station *st; Waypoint *wp;
FOR_ALL_STATIONS(st) { FOR_ALL_WAYPOINTS(wp) {
if (st->IsBuoy() && IsTileOwner(st->xy, OWNER_NONE) && TileHeight(st->xy) == 0) SetTileOwner(st->xy, OWNER_WATER); 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)) { 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 /* Set all share owners to INVALID_COMPANY for
* 1) all inactive companies * 1) all inactive companies
* (when inactive companies were stored in the savegame - TTD, TTDP and some * (when inactive companies were stored in the savegame - TTD, TTDP and some
@ -1561,7 +1532,7 @@ bool AfterLoadGame()
if (IsBuoyTile(t)) { if (IsBuoyTile(t)) {
/* reset buoy owner to OWNER_NONE in the station struct /* reset buoy owner to OWNER_NONE in the station struct
* (even if it is owned by active company) */ * (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)) { } else if (IsTileType(t, MP_ROAD)) {
/* works for all RoadTileType */ /* works for all RoadTileType */
@ -1805,16 +1776,6 @@ bool AfterLoadGame()
FOR_ALL_STATIONS(st) { FOR_ALL_STATIONS(st) {
if (!Company::IsValidID(st->owner)) st->owner = OWNER_NONE; 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. */ /* Trains could now stop in a specific location. */
@ -1913,14 +1874,6 @@ bool AfterLoadGame()
} }
s->cargo_type = CT_INVALID; 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(); AfterLoadLabelMaps();
@ -1950,8 +1903,7 @@ void ReloadNewGRFData()
AfterLoadVehicles(false); AfterLoadVehicles(false);
StartupEngines(); StartupEngines();
SetCachedEngineCounts(); SetCachedEngineCounts();
/* update station and waypoint graphics */ /* update station graphics */
AfterLoadWaypoints();
AfterLoadStations(); AfterLoadStations();
/* Check and update house and town values */ /* Check and update house and town values */
UpdateHousesAndTowns(); UpdateHousesAndTowns();

@ -41,7 +41,7 @@
#include "saveload_internal.h" #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 SavegameType _savegame_type; ///< type of savegame we are loading
@ -873,6 +873,7 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad *sld)
break; break;
case SL_WRITEBYTE: return 1; // a byte is logically of size 1 case SL_WRITEBYTE: return 1; // a byte is logically of size 1
case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END)); case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
default: NOT_REACHED(); default: NOT_REACHED();
} }
return 0; return 0;
@ -934,6 +935,10 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
SlObject(ptr, GetVehicleDescription(VEH_END)); SlObject(ptr, GetVehicleDescription(VEH_END));
break; break;
case SL_ST_INCLUDE:
SlObject(ptr, GetBaseStationDescription());
break;
default: NOT_REACHED(); default: NOT_REACHED();
} }
return true; return true;

@ -182,6 +182,7 @@ enum SaveLoadTypes {
/* non-normal save-load types */ /* non-normal save-load types */
SL_WRITEBYTE = 8, SL_WRITEBYTE = 8,
SL_VEH_INCLUDE = 9, SL_VEH_INCLUDE = 9,
SL_ST_INCLUDE = 10,
SL_END = 15 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_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_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 */ /* End marker */
#define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL} #define SLE_END() {false, SL_END, 0, 0, 0, 0, NULL}

@ -16,7 +16,10 @@ StringID RemapOldStringID(StringID s);
char *CopyFromOldName(StringID id); char *CopyFromOldName(StringID id);
void ResetOldNames(); void ResetOldNames();
void AfterLoadWaypoints(); void MoveBuoysToWaypoints();
void MoveWaypointsToBaseStations();
const SaveLoad *GetBaseStationDescription();
void AfterLoadVehicles(bool part_of_load); void AfterLoadVehicles(bool part_of_load);
void AfterLoadStations(); void AfterLoadStations();
void AfterLoadLabelMaps(); void AfterLoadLabelMaps();

@ -4,27 +4,98 @@
#include "../stdafx.h" #include "../stdafx.h"
#include "../station_base.h" #include "../station_base.h"
#include "../waypoint.h"
#include "../roadstop_base.h" #include "../roadstop_base.h"
#include "../order_base.h"
#include "../vehicle_base.h"
#include "../core/bitmath_func.hpp" #include "../core/bitmath_func.hpp"
#include "../core/alloc_func.hpp" #include "../core/alloc_func.hpp"
#include "../variables.h" #include "../variables.h"
#include "../newgrf_station.h" #include "../newgrf_station.h"
#include "saveload.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;
void AfterLoadStations() 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()
{ {
/* Update the speclists of all stations to point to the currently loaded custom stations. */ /* 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; Station *st;
FOR_ALL_STATIONS(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. */
BaseStation *st;
FOR_ALL_BASE_STATIONS(st) {
for (uint i = 0; i < st->num_specs; i++) { for (uint i = 0; i < st->num_specs; i++) {
if (st->speclist[i].grfid == 0) continue; if (st->speclist[i].grfid == 0) continue;
st->speclist[i].spec = GetCustomStationSpecByGrf(st->speclist[i].grfid, st->speclist[i].localidx, NULL); 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); StationUpdateAnimTriggers(st);
} }
@ -48,7 +119,7 @@ static const SaveLoad _roadstop_desc[] = {
SLE_END() 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_FILE_U16 | SLE_VAR_U32, 0, 5),
SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Station, xy, SLE_UINT32, 6, SL_MAX_VERSION),
SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile
@ -145,78 +216,202 @@ const SaveLoad *GetGoodsDesc()
} }
static void SaveLoad_STNS(Station *st) static void Load_STNS()
{ {
SlObject(st, _station_desc); int index;
while ((index = SlIterateArray()) != -1) {
_waiting_acceptance = 0; Station *st = new (index) Station();
uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO; SlObject(st, _old_station_desc);
for (CargoID i = 0; i < num_cargo; i++) {
GoodsEntry *ge = &st->goods[i]; _waiting_acceptance = 0;
SlObject(ge, GetGoodsDesc());
if (CheckSavegameVersion(68)) { uint num_cargo = CheckSavegameVersion(55) ? 12 : NUM_CARGO;
SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15)); for (CargoID i = 0; i < num_cargo; i++) {
if (GB(_waiting_acceptance, 0, 12) != 0) { GoodsEntry *ge = &st->goods[i];
/* Don't construct the packet with station here, because that'll fail with old savegames */ SlObject(ge, GetGoodsDesc());
CargoPacket *cp = new CargoPacket(); if (CheckSavegameVersion(68)) {
/* In old versions, enroute_from used 0xFF as INVALID_STATION */ SB(ge->acceptance_pickup, GoodsEntry::ACCEPTANCE, 1, HasBit(_waiting_acceptance, 15));
cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; if (GB(_waiting_acceptance, 0, 12) != 0) {
cp->count = GB(_waiting_acceptance, 0, 12); /* Don't construct the packet with station here, because that'll fail with old savegames */
cp->days_in_transit = _cargo_days; CargoPacket *cp = new CargoPacket();
cp->feeder_share = _cargo_feeder_share; /* In old versions, enroute_from used 0xFF as INVALID_STATION */
cp->source_xy = _cargo_source_xy; cp->source = (CheckSavegameVersion(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source;
cp->days_in_transit = _cargo_days; cp->count = GB(_waiting_acceptance, 0, 12);
cp->feeder_share = _cargo_feeder_share; cp->days_in_transit = _cargo_days;
SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1); cp->feeder_share = _cargo_feeder_share;
ge->cargo.Append(cp); 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) { if (st->num_specs != 0) {
/* Allocate speclist memory when loading a game */ /* Allocate speclist memory when loading a game */
if (st->speclist == NULL) st->speclist = CallocT<StationSpecList>(st->num_specs); st->speclist = CallocT<StationSpecList>(st->num_specs);
for (uint i = 0; i < st->num_specs; i++) { for (uint i = 0; i < st->num_specs; i++) {
SlObject(&st->speclist[i], _station_speclist_desc); SlObject(&st->speclist[i], _station_speclist_desc);
}
} }
} }
} }
static void Save_STNS() void Ptrs_STNS()
{ {
/* Don't run when savegame version is higher than or equal to 123. */
if (!CheckSavegameVersion(123)) return;
Station *st; Station *st;
/* Write the stations */
FOR_ALL_STATIONS(st) { FOR_ALL_STATIONS(st) {
if (!CheckSavegameVersion(68)) {
for (CargoID i = 0; i < NUM_CARGO; i++) {
GoodsEntry *ge = &st->goods[i];
SlObject(ge, GetGoodsDesc());
}
}
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); SlSetArrayIndex(st->index);
SlAutolength((AutolengthProc*)SaveLoad_STNS, st); SlAutolength((AutolengthProc*)RealSave_STNN, st);
} }
} }
static void Load_STNS() static void Load_STNN()
{ {
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
Station *st = new (index) Station(); bool waypoint = (SlReadByte() & FACIL_WAYPOINT) != 0;
SaveLoad_STNS(st); 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<StationSpecList>(bst->num_specs);
for (uint i = 0; i < bst->num_specs; i++) {
SlObject(&bst->speclist[i], _station_speclist_desc);
}
}
} }
} }
void Ptrs_STNS() static void Ptrs_STNN()
{ {
/* Don't run when savegame version lower than 123. */
if (CheckSavegameVersion(123)) return;
Station *st; Station *st;
FOR_ALL_STATIONS(st) { FOR_ALL_STATIONS(st) {
if (!CheckSavegameVersion(68)) { for (CargoID i = 0; i < NUM_CARGO; i++) {
for (CargoID i = 0; i < NUM_CARGO; i++) { GoodsEntry *ge = &st->goods[i];
GoodsEntry *ge = &st->goods[i]; SlObject(ge, GetGoodsDesc());
SlObject(ge, GetGoodsDesc());
}
} }
SlObject(st, _station_desc); SlObject(st, _station_desc);
} }
}
Waypoint *wp;
FOR_ALL_WAYPOINTS(wp) {
SlObject(wp, _waypoint_desc);
}
}
static void Save_ROADSTOP() static void Save_ROADSTOP()
{ {
@ -248,6 +443,7 @@ static void Ptrs_ROADSTOP()
} }
extern const ChunkHandler _station_chunk_handlers[] = { 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}, { 'ROAD', Save_ROADSTOP, Load_ROADSTOP, Ptrs_ROADSTOP, CH_ARRAY | CH_LAST},
}; };

@ -5,120 +5,187 @@
#include "../stdafx.h" #include "../stdafx.h"
#include "../waypoint.h" #include "../waypoint.h"
#include "../newgrf_station.h" #include "../newgrf_station.h"
#include "../vehicle_base.h"
#include "../town.h" #include "../town.h"
#include "../station_map.h"
#include "table/strings.h" #include "table/strings.h"
#include "saveload.h" #include "saveload.h"
#include "saveload_internal.h" #include "saveload_internal.h"
/** 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;
size_t new_index;
};
/** Temporary array with old waypoints. */
static SmallVector<OldWaypoint, 16> _old_waypoints;
/** /**
* Update waypoint graphics id against saved GRFID/localidx. * Update the waypoint orders to get the new waypoint ID.
* This is to ensure the chosen graphics are correct if GRF files are changed. * @param o the order 'list' to check.
*/ */
void AfterLoadWaypoints() static void UpdateWaypointOrder(Order *o)
{ {
Waypoint *wp; if (!o->IsType(OT_GOTO_WAYPOINT)) return;
FOR_ALL_WAYPOINTS(wp) { for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) {
if (wp->num_specs == 0) continue; if (wp->index != o->GetDestination()) continue;
for (uint i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) { o->SetDestination(wp->new_index);
const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i); return;
if (statspec != NULL && statspec->grffile->grfid == wp->speclist[1].grfid && statspec->localidx == wp->speclist[1].localidx) { }
wp->speclist[1].spec = statspec; }
break;
/**
* 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;
}
} }
} }
} }
}
static uint16 _waypoint_town_index; /* All saveload conversions have been done. Create the new waypoints! */
static StringID _waypoint_string_id; for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) {
static StationSpecList _waypoint_spec; Waypoint *new_wp = new Waypoint(wp->xy);
new_wp->town = wp->town;
static const SaveLoad _waypoint_desc[] = { new_wp->town_cn = wp->town_cn;
SLE_CONDVAR(Waypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), new_wp->name = wp->name;
SLE_CONDVAR(Waypoint, xy, SLE_UINT32, 6, SL_MAX_VERSION), new_wp->delete_ctr = 0; // Just reset delete counter for once.
SLEG_CONDVAR(_waypoint_town_index, SLE_UINT16, 12, 121), new_wp->build_date = wp->build_date;
SLE_CONDREF(Waypoint, town, REF_TOWN, 122, SL_MAX_VERSION), new_wp->owner = wp->owner;
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),
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),
SLE_END() new_wp->string_id = STR_SV_STNAME_WAYPOINT;
};
static void Save_WAYP() TileIndex t = wp->xy;
{ if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp->index) {
Waypoint *wp; /* The tile might've been reserved! */
bool reserved = !CheckSavegameVersion(100) && HasBit(_m[t].m5, 4);
/* 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);
FOR_ALL_WAYPOINTS(wp) { SetRailwayStationReservation(t, reserved);
if (wp->num_specs == 0) {
_waypoint_spec.grfid = 0; if (wp->spec != NULL) {
} else { SetCustomStationSpecIndex(t, AllocateSpecToStation(wp->spec, new_wp, true));
_waypoint_spec = wp->speclist[1]; }
} }
SlSetArrayIndex(wp->index); wp->new_index = new_wp->index;
SlObject(wp, _waypoint_desc);
} }
/* 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);
}
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 Load_WAYP() static void Load_WAYP()
{ {
/* Precaution for when loading failed and it didn't get cleared */
_old_waypoints.Clear();
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
_waypoint_string_id = 0; OldWaypoint *wp = _old_waypoints.Append();
_waypoint_town_index = 0; memset(wp, 0, sizeof(*wp));
_waypoint_spec.grfid = 0;
Waypoint *wp = new (index) Waypoint();
SlObject(wp, _waypoint_desc);
wp->facilities |= FACIL_TRAIN; wp->index = index;
SlObject(wp, _old_waypoint_desc);
if (_waypoint_spec.grfid != 0) {
wp->num_specs = 2;
wp->speclist = CallocT<StationSpecList>(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;
} }
} }
static void Ptrs_WAYP() 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)) { 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); wp->town = ClosestTownFromTile(wp->xy, UINT_MAX);
} else if (CheckSavegameVersion(122)) { } else if (CheckSavegameVersion(122)) {
/* Only for versions 12 .. 122 */ /* Only for versions 12 .. 122 */
wp->town = Town::Get((size_t)wp->town); wp->town = Town::Get(wp->town_index);
} }
if (CheckSavegameVersion(84)) { if (CheckSavegameVersion(84)) {
wp->name = CopyFromOldName(sid); wp->name = CopyFromOldName(wp->string_id);
} }
} }
} }
extern const ChunkHandler _waypoint_chunk_handlers[] = { 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},
}; };

@ -288,14 +288,6 @@ static SigFlags ExploreSegment(Owner owner)
} }
} }
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 = GetTrackBits(tile); // trackbits of tile
TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir]); // only incidating trackbits

@ -50,12 +50,6 @@ Station::Station(TileIndex tile) :
/* this->random_bits is set in Station::AddFacility() */ /* 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. * Clean up a station by clearing vehicle orders and invalidating windows.
* Aircraft-Hangar orders need special treatment here, as the hangars are * Aircraft-Hangar orders need special treatment here, as the hangars are

@ -21,7 +21,7 @@
#include "station_map.h" #include "station_map.h"
#include <list> #include <list>
typedef Pool<Station, StationID, 32, 64000> StationPool; typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
extern StationPool _station_pool; extern StationPool _station_pool;
static const byte INITIAL_STATION_RATING = 175; static const byte INITIAL_STATION_RATING = 175;
@ -85,7 +85,7 @@ struct TileArea {
}; };
/** Base class for all station-ish types */ /** Base class for all station-ish types */
struct BaseStation { struct BaseStation : StationPool::PoolItem<&_station_pool> {
TileIndex xy; ///< Base tile of the station TileIndex xy; ///< Base tile of the station
ViewportSign sign; ///< NOSAVE: Dimensions of sign 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. 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. * @param tile The tile to get the base station from.
* @return the station associated with that tile. * @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 * Class defining several overloaded accessors so we don't
* have to cast base stations that often * have to cast base stations that often
@ -175,6 +180,44 @@ struct SpecializedStation : public BaseStation {
return (st->facilities & FACIL_WAYPOINT) == EXPECTED_FACIL; return (st->facilities & FACIL_WAYPOINT) == EXPECTED_FACIL;
} }
/**
* 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. * Converts a BaseStation to SpecializedStation with type checking.
* @param st BaseStation pointer * @param st BaseStation pointer
@ -198,11 +241,13 @@ struct SpecializedStation : public BaseStation {
} }
}; };
#define FOR_ALL_BASE_STATIONS_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, station_index, var, 0) if (name::IsExpected(var))
typedef SmallVector<Industry *, 2> IndustryVector; typedef SmallVector<Industry *, 2> IndustryVector;
/** Station data structure */ /** Station data structure */
struct Station : StationPool::PoolItem<&_station_pool>, SpecializedStation<Station, false> { struct Station : SpecializedStation<Station, false> {
public: public:
RoadStop *GetPrimaryRoadStop(RoadStopType type) const RoadStop *GetPrimaryRoadStop(RoadStopType type) const
{ {
@ -274,24 +319,9 @@ public:
/* virtual */ void GetTileArea(TileArea *ta, StationType type) const; /* 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); 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_BASE_STATIONS_OF_TYPE(Station, var)
#define FOR_ALL_STATIONS(var) FOR_ALL_STATIONS_FROM(var, 0)
#endif /* STATION_BASE_H */ #endif /* STATION_BASE_H */

@ -197,7 +197,6 @@ enum StationNaming {
STATIONNAMING_AIRPORT, STATIONNAMING_AIRPORT,
STATIONNAMING_OILRIG, STATIONNAMING_OILRIG,
STATIONNAMING_DOCK, STATIONNAMING_DOCK,
STATIONNAMING_BUOY,
STATIONNAMING_HELIPORT, STATIONNAMING_HELIPORT,
}; };
@ -239,7 +238,6 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT 1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT
1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG 1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG
1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK 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 1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT
}; };
@ -266,24 +264,22 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
} }
} }
if (name_class != STATIONNAMING_BUOY) { TileIndex indtile = tile;
TileIndex indtile = tile; StationNameInformation sni = { free_names, indtypes };
StationNameInformation sni = { free_names, indtypes }; if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) {
if (CircularTileSearch(&indtile, 7, FindNearIndustryName, &sni)) { /* An industry has been found nearby */
/* An industry has been found nearby */ IndustryType indtype = GetIndustryType(indtile);
IndustryType indtype = GetIndustryType(indtile); const IndustrySpec *indsp = GetIndustrySpec(indtype);
const IndustrySpec *indsp = GetIndustrySpec(indtype); /* STR_NULL means it only disables oil rig/mines */
/* STR_NULL means it only disables oil rig/mines */ if (indsp->station_name != STR_NULL) {
if (indsp->station_name != STR_NULL) { st->indtype = indtype;
st->indtype = indtype; return STR_SV_STNAME_FALLBACK;
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 */ /* check default names */
uint32 tmp = free_names & _gen_station_name_bits[name_class]; uint32 tmp = free_names & _gen_station_name_bits[name_class];
if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp); if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp);
@ -540,9 +536,6 @@ CargoArray GetAcceptanceAroundTiles(TileIndex tile, int w, int h, int rad)
*/ */
static void UpdateStationAcceptance(Station *st, bool show_msg) static void UpdateStationAcceptance(Station *st, bool show_msg)
{ {
/* Don't update acceptance for a buoy */
if (st->IsBuoy()) return;
/* old accepted goods types */ /* old accepted goods types */
uint old_acc = GetAcceptanceMask(st); uint old_acc = GetAcceptanceMask(st);
@ -1963,31 +1956,23 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return_cmd_error(STR_ERROR_SITE_UNSUITABLE); if (GetTileSlope(tile, NULL) != SLOPE_FLAT) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
/* allocate and initialize new station */ /* 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) { if (flags & DC_EXEC) {
Station *st = new Station(tile); Waypoint *st = new Waypoint(tile);
st->town = ClosestTownFromTile(tile, UINT_MAX); st->string_id = STR_SV_STNAME_BUOY;
st->string_id = GenerateStationName(st, tile, STATIONNAMING_BUOY);
if (Company::IsValidID(_current_company)) {
SetBit(st->town->have_ratings, _current_company);
}
st->dock_tile = tile;
st->facilities |= FACIL_DOCK; 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->owner = OWNER_NONE;
st->build_date = _date; st->build_date = _date;
if (st->town == NULL) MakeDefaultWaypointName(st);
MakeBuoy(tile, st->index, GetWaterClass(tile)); MakeBuoy(tile, st->index, GetWaterClass(tile));
st->UpdateVirtCoord(); st->UpdateVirtCoord();
UpdateStationAcceptance(st, false);
st->RecomputeIndustriesNear();
InvalidateWindowData(WC_STATION_LIST, st->owner, 0); InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS); InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
} }
@ -2008,7 +1993,7 @@ bool HasStationInUse(StationID station, CompanyID company)
if (company == INVALID_COMPANY || v->owner == company) { if (company == INVALID_COMPANY || v->owner == company) {
const Order *order; const Order *order;
FOR_VEHICLE_ORDERS(v, 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; return true;
} }
} }
@ -2028,18 +2013,14 @@ static CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags)
/* XXX: strange stuff, allow clearing as invalid company when clearing landscape */ /* 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); 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); 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... */ /* 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_BANKRUPT) && !EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
if (flags & DC_EXEC) { 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->facilities &= ~FACIL_DOCK;
st->had_vehicle_of_type &= ~HVOT_BUOY;
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS); InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
@ -2050,8 +2031,7 @@ static CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags)
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
st->UpdateVirtCoord(); st->UpdateVirtCoord();
st->RecomputeIndustriesNear(); st->delete_ctr = 0;
DeleteStationIfEmpty(st);
} }
return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_truck_station); return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_truck_station);
@ -2227,7 +2207,7 @@ static void DrawTile_Station(TileInfo *ti)
int32 total_offset; int32 total_offset;
int32 custom_ground_offset; int32 custom_ground_offset;
if (IsRailwayStation(ti->tile)) { if (IsRailwayStation(ti->tile) || IsRailWaypoint(ti->tile)) {
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile)); const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
roadtypes = ROADTYPES_NONE; roadtypes = ROADTYPES_NONE;
total_offset = rti->total_offset; total_offset = rti->total_offset;
@ -2238,7 +2218,7 @@ static void DrawTile_Station(TileInfo *ti)
custom_ground_offset = 0; custom_ground_offset = 0;
} }
uint32 relocation = 0; uint32 relocation = 0;
const Station *st = NULL; const BaseStation *st = NULL;
const StationSpec *statspec = NULL; const StationSpec *statspec = NULL;
Owner owner = GetTileOwner(ti->tile); Owner owner = GetTileOwner(ti->tile);
@ -2256,7 +2236,7 @@ static void DrawTile_Station(TileInfo *ti)
if (IsCustomStationSpecIndex(ti->tile)) { if (IsCustomStationSpecIndex(ti->tile)) {
/* look for customization */ /* look for customization */
st = Station::GetByTile(ti->tile); st = BaseStation::GetByTile(ti->tile);
statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec; statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec;
if (statspec != NULL) { if (statspec != NULL) {
@ -2304,13 +2284,13 @@ static void DrawTile_Station(TileInfo *ti)
DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette)); DrawGroundSprite(image, GroundSpritePaletteTransform(image, pal, palette));
/* PBS debugging, draw reserved tracks darker */ /* 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)); 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); 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)) { if (HasBit(roadtypes, ROADTYPE_TRAM)) {
Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y; Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
@ -2318,6 +2298,11 @@ static void DrawTile_Station(TileInfo *ti)
DrawTramCatenary(ti, axis == AXIS_X ? ROAD_X : ROAD_Y); 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; const DrawTileSeqStruct *dtss;
foreach_draw_tile_seq(dtss, t->seq) { foreach_draw_tile_seq(dtss, t->seq) {
SpriteID image = dtss->image.sprite; SpriteID image = dtss->image.sprite;
@ -2408,7 +2393,7 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
} }
} }
} }
td->build_date = Station::GetByTile(tile)->build_date; td->build_date = BaseStation::GetByTile(tile)->build_date;
const StationSpec *spec = GetStationSpec(tile); const StationSpec *spec = GetStationSpec(tile);
@ -2425,15 +2410,16 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
StringID str; StringID str;
switch (GetStationType(tile)) { switch (GetStationType(tile)) {
default: NOT_REACHED(); 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: case STATION_AIRPORT:
str = (IsHangar(tile) ? STR_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_STATION_DESCRIPTION_AIRPORT); str = (IsHangar(tile) ? STR_STATION_DESCRIPTION_AIRCRAFT_HANGAR : STR_STATION_DESCRIPTION_AIRPORT);
break; break;
case STATION_TRUCK: str = STR_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break; case STATION_TRUCK: str = STR_STATION_DESCRIPTION_TRUCK_LOADING_AREA; break;
case STATION_BUS: str = STR_STATION_DESCRIPTION_BUS_STATION; break; case STATION_BUS: str = STR_STATION_DESCRIPTION_BUS_STATION; break;
case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break; case STATION_OILRIG: str = STR_INDUSTRY_NAME_OIL_RIG; break;
case STATION_DOCK: str = STR_STATION_DESCRIPTION_SHIP_DOCK; break; case STATION_DOCK: str = STR_STATION_DESCRIPTION_SHIP_DOCK; break;
case STATION_BUOY: str = STR_STATION_DESCRIPTION_BUOY; break; case STATION_BUOY: str = STR_STATION_DESCRIPTION_BUOY; break;
case STATION_WAYPOINT: str = STR_LANDINFO_WAYPOINT; break;
} }
td->str = str; td->str = str;
} }
@ -2445,7 +2431,7 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode
switch (mode) { switch (mode) {
case TRANSPORT_RAIL: case TRANSPORT_RAIL:
if (IsRailwayStation(tile) && !IsStationTileBlocked(tile)) { if ((IsRailwayStation(tile) || IsRailWaypoint(tile)) && !IsStationTileBlocked(tile)) {
trackbits = TrackToTrackBits(GetRailStationTrack(tile)); trackbits = TrackToTrackBits(GetRailStationTrack(tile));
} }
break; break;
@ -2551,10 +2537,14 @@ static void AnimateTile_Station(TileIndex tile)
static bool ClickTile_Station(TileIndex tile) 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); ShowDepotWindow(tile, VEH_AIRCRAFT);
} else { } else {
ShowStationViewWindow(GetStationIndex(tile)); ShowStationViewWindow(st->index);
} }
return true; return true;
} }
@ -2650,15 +2640,15 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
* @param st the station receiving the tick. * @param st the station receiving the tick.
* @return true if the station is still valid (wasn't deleted) * @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 & ~FACIL_WAYPOINT) == 0 && ++st->delete_ctr >= 8) {
if (st->facilities == 0 && ++st->delete_ctr >= 8) {
delete st; delete st;
return false; return false;
} }
if ((st->facilities & FACIL_WAYPOINT) == 0) UpdateStationAcceptance(Station::From(st), true);
return true; return true;
} }
@ -2778,23 +2768,23 @@ static void UpdateStationRating(Station *st)
} }
/* called for every station each tick */ /* 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; byte b = st->delete_ctr + 1;
if (b >= 185) b = 0; if (b >= 185) b = 0;
st->delete_ctr = b; st->delete_ctr = b;
if (b == 0) UpdateStationRating(st); if (b == 0) UpdateStationRating(Station::From(st));
} }
void OnTick_Station() void OnTick_Station()
{ {
if (_game_mode == GM_EDITOR) return; if (_game_mode == GM_EDITOR) return;
Station *st; BaseStation *st;
FOR_ALL_STATIONS(st) { FOR_ALL_BASE_STATIONS(st) {
StationHandleSmallTick(st); StationHandleSmallTick(st);
/* Run 250 tick interval trigger for station animation. /* Run 250 tick interval trigger for station animation.
@ -2884,7 +2874,7 @@ CommandCost CmdRenameStation(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
} }
/** /**
* 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 tile North tile of producer
* @param w_prod X extent of producer * @param w_prod X extent of producer
@ -2903,8 +2893,7 @@ void FindStationsAroundTiles(TileIndex tile, int w_prod, int h_prod, StationList
if (cur_tile == INVALID_TILE || !IsTileType(cur_tile, MP_STATION)) continue; if (cur_tile == INVALID_TILE || !IsTileType(cur_tile, MP_STATION)) continue;
Station *st = Station::GetByTile(cur_tile); Station *st = Station::GetByTile(cur_tile);
if (st == NULL) continue;
if (st->IsBuoy()) continue; // bouys don't accept cargo
if (_settings_game.station.modified_catchment) { if (_settings_game.station.modified_catchment) {
int rad = st->GetCatchmentRadius(); int rad = st->GetCatchmentRadius();
@ -3120,12 +3109,13 @@ static CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
if (flags & DC_AUTO) { if (flags & DC_AUTO) {
switch (GetStationType(tile)) { switch (GetStationType(tile)) {
default: break; default: break;
case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD); 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_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
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_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_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_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_BUOY: return_cmd_error(STR_ERROR_BUOY_IN_THE_WAY); 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_DOCK: return_cmd_error(STR_ERROR_MUST_DEMOLISH_DOCK_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: case STATION_OILRIG:
SetDParam(0, STR_INDUSTRY_NAME_OIL_RIG); SetDParam(0, STR_INDUSTRY_NAME_OIL_RIG);
return_cmd_error(STR_OBJECT_IN_THE_WAY); return_cmd_error(STR_OBJECT_IN_THE_WAY);
@ -3133,8 +3123,9 @@ static CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
} }
switch (GetStationType(tile)) { switch (GetStationType(tile)) {
case STATION_RAIL: return RemoveRailroadStation(tile, flags); case STATION_RAIL: return RemoveRailroadStation(tile, flags);
case STATION_AIRPORT: return RemoveAirport(tile, flags); case STATION_WAYPOINT: return RemoveTrainWaypoint(tile, flags, false);
case STATION_AIRPORT: return RemoveAirport(tile, flags);
case STATION_TRUCK: case STATION_TRUCK:
if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags))
return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST); return_cmd_error(STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
@ -3143,8 +3134,8 @@ static CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags))
return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST); return_cmd_error(STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
return RemoveRoadStop(tile, flags); return RemoveRoadStop(tile, flags);
case STATION_BUOY: return RemoveBuoy(tile, flags); case STATION_BUOY: return RemoveBuoy(tile, flags);
case STATION_DOCK: return RemoveDock(tile, flags); case STATION_DOCK: return RemoveDock(tile, flags);
default: break; default: break;
} }
@ -3159,6 +3150,7 @@ static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, ui
*/ */
if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) { if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new))) {
switch (GetStationType(tile)) { switch (GetStationType(tile)) {
case STATION_WAYPOINT:
case STATION_RAIL: { case STATION_RAIL: {
DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile)); DiagDirection direction = AxisToDiagDir(GetRailStationAxis(tile));
if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break; if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;

@ -143,7 +143,7 @@ protected:
const Station *st; const Station *st;
FOR_ALL_STATIONS(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 if (this->facilities & st->facilities) { // only stations with selected facilities
int num_waiting_cargo = 0; int num_waiting_cargo = 0;
for (CargoID j = 0; j < NUM_CARGO; j++) { 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 /* 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 */ * 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(0, st->index);
SetDParam(1, st->facilities); SetDParam(1, st->facilities);
@ -409,7 +409,7 @@ public:
const Station *st = this->stations[id_v]; const Station *st = this->stations[id_v];
/* do not check HasStationInUse - it is slow and may be invalid */ /* 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) { if (_ctrl_pressed) {
ShowExtraViewPortWindow(st->xy); ShowExtraViewPortWindow(st->xy);

@ -88,6 +88,28 @@ static inline bool IsRailwayStationTile(TileIndex t)
return IsTileType(t, MP_STATION) && IsRailwayStation(t); 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) static inline bool IsAirport(TileIndex t)
{ {
return GetStationType(t) == STATION_AIRPORT; return GetStationType(t) == STATION_AIRPORT;
@ -186,7 +208,7 @@ static inline bool IsHangarTile(TileIndex t)
static inline Axis GetRailStationAxis(TileIndex t) static inline Axis GetRailStationAxis(TileIndex t)
{ {
assert(IsRailwayStation(t)); assert(IsRailwayStation(t) || IsRailWaypoint(t));
return HasBit(GetStationGfx(t), 0) ? AXIS_Y : AXIS_X; return HasBit(GetStationGfx(t), 0) ? AXIS_Y : AXIS_X;
} }
@ -214,31 +236,31 @@ static inline bool IsCompatibleTrainStationTile(TileIndex t1, TileIndex t2)
/** /**
* Get the reservation state of the rail station * Get the reservation state of the rail station
* @pre IsRailwayStationTile(t) * @pre IsRailwayStation(t) || IsRailWaypoint(t)
* @param t the station tile * @param t the station tile
* @return reservation state * @return reservation state
*/ */
static inline bool HasStationReservation(TileIndex t) static inline bool HasStationReservation(TileIndex t)
{ {
assert(IsRailwayStationTile(t)); assert(IsRailwayStation(t) || IsRailWaypoint(t));
return HasBit(_m[t].m6, 2); return HasBit(_m[t].m6, 2);
} }
/** /**
* Set the reservation state of the rail station * Set the reservation state of the rail station
* @pre IsRailwayStationTile(t) * @pre IsRailwayStation(t) || IsRailWaypoint(t)
* @param t the station tile * @param t the station tile
* @param b the reservation state * @param b the reservation state
*/ */
static inline void SetRailwayStationReservation(TileIndex t, bool b) 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); SB(_m[t].m6, 2, 1, b ? 1 : 0);
} }
/** /**
* Get the reserved track bits for a waypoint * Get the reserved track bits for a waypoint
* @pre IsRailwayStationTile(t) * @pre IsRailwayStation(t) || IsRailWaypoint(t)
* @param t the tile * @param t the tile
* @return reserved track bits * @return reserved track bits
*/ */
@ -325,6 +347,13 @@ static inline void MakeRailStation(TileIndex t, Owner o, StationID sid, Axis a,
SetRailwayStationReservation(t, false); 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) 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); MakeStation(t, o, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), d);

@ -57,9 +57,8 @@ enum StationHadVehicleOfType {
HVOT_TRUCK = 1 << 3, ///< Station has seen a truck HVOT_TRUCK = 1 << 3, ///< Station has seen a truck
HVOT_AIRCRAFT = 1 << 4, ///< Station has seen an aircraft HVOT_AIRCRAFT = 1 << 4, ///< Station has seen an aircraft
HVOT_SHIP = 1 << 5, ///< Station has seen a ship 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_WAYPOINT = 1 << 6, ///< Station is a waypoint (NewGRF only!)
HVOT_BUOY = 1 << 6
}; };
DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType); DECLARE_ENUM_AS_BIT_SET(StationHadVehicleOfType);
typedef SimpleTinyEnumT<StationHadVehicleOfType, byte> StationHadVehicleOfTypeByte; typedef SimpleTinyEnumT<StationHadVehicleOfType, byte> StationHadVehicleOfTypeByte;

@ -863,8 +863,8 @@ static char *FormatString(char *buff, const char *str, int64 *argv, uint casei,
int64 temp[2]; int64 temp[2];
temp[0] = wp->town->index; temp[0] = wp->town->index;
temp[1] = wp->town_cn + 1; 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); buff = GetStringWithArgs(buff, str, temp, last);
} }
break; break;

@ -635,10 +635,10 @@ static void ResetLandscapeConfirmationCallback(Window *w, bool confirmed)
_generating_world = false; _generating_world = false;
/* Delete all station signs */ /* Delete all station signs */
Station *st; BaseStation *st;
FOR_ALL_STATIONS(st) { FOR_ALL_BASE_STATIONS(st) {
/* There can be buoys, remove them */ /* 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; if (st->facilities == 0) delete st;
} }

@ -482,7 +482,7 @@ static int GetTrainAcceleration(Train *v, bool mode)
assert(max_speed == GetTrainCurveSpeedLimit(v)); // safety check, will be removed later assert(max_speed == GetTrainCurveSpeedLimit(v)); // safety check, will be removed later
int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h 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); StationID sid = GetStationIndex(v->tile);
if (v->current_order.ShouldStopAtStation(v, sid)) { if (v->current_order.ShouldStopAtStation(v, sid)) {
int station_ahead; int station_ahead;
@ -4443,12 +4443,10 @@ static bool TrainLocoHandler(Train *v, bool mode)
OrderType order_type = v->current_order.GetType(); OrderType order_type = v->current_order.GetType();
/* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */ /* Do not skip waypoints (incl. 'via' stations) when passing through at full speed. */
if ((order_type == OT_GOTO_WAYPOINT && if ((order_type == OT_GOTO_WAYPOINT || order_type == OT_GOTO_STATION) &&
v->dest_tile == v->tile) ||
(order_type == OT_GOTO_STATION &&
(v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && (v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) &&
IsTileType(v->tile, MP_STATION) && IsTileType(v->tile, MP_STATION) &&
v->current_order.GetDestination() == GetStationIndex(v->tile))) { v->current_order.GetDestination() == GetStationIndex(v->tile)) {
ProcessOrders(v); ProcessOrders(v);
} }
} }

@ -788,8 +788,6 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y)
sel--; sel--;
if (order->IsType(OT_GOTO_STATION)) { if (order->IsType(OT_GOTO_STATION)) {
if (v->type == VEH_SHIP && Station::Get(order->GetDestination())->IsBuoy()) continue;
SetDParam(0, order->GetDestination()); SetDParam(0, order->GetDestination());
DrawString(left, right, y, STR_ORDER_STATION_SMALL); DrawString(left, right, y, STR_ORDER_STATION_SMALL);
@ -1950,7 +1948,7 @@ struct VehicleViewWindow : Window {
case OT_GOTO_WAYPOINT: { case OT_GOTO_WAYPOINT: {
assert(v->type == VEH_TRAIN || v->type == VEH_SHIP); assert(v->type == VEH_TRAIN || v->type == VEH_SHIP);
SetDParam(0, v->current_order.GetDestination()); 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()); SetDParam(1, v->GetDisplaySpeed());
break; break;
} }

@ -1218,7 +1218,7 @@ static void ViewportAddSigns(DrawPixelInfo *dpi)
static void AddWaypoint(const Waypoint *wp, StringID str, uint16 width) 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);
} }

@ -12,23 +12,6 @@
#include "window_func.h" #include "window_func.h"
#include "newgrf_station.h" #include "newgrf_station.h"
#include "order_func.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 * Draw a waypoint
@ -67,8 +50,3 @@ Waypoint::~Waypoint()
this->sign.MarkDirty(); this->sign.MarkDirty();
} }
void InitializeWaypoints()
{
_waypoint_pool.CleanPool();
}

@ -14,10 +14,7 @@
#include "date_type.h" #include "date_type.h"
#include "core/pool_type.hpp" #include "core/pool_type.hpp"
typedef Pool<Waypoint, WaypointID, 32, 64000> WaypointPool; struct Waypoint : SpecializedStation<Waypoint, true> {
extern WaypointPool _waypoint_pool;
struct Waypoint : WaypointPool::PoolItem<&_waypoint_pool>, SpecializedStation<Waypoint, true> {
uint16 town_cn; ///< The Nth waypoint for this town (consecutive number) uint16 town_cn; ///< The Nth waypoint for this town (consecutive number)
Waypoint(TileIndex tile = INVALID_TILE) : SpecializedStation<Waypoint, true>(tile) { } Waypoint(TileIndex tile = INVALID_TILE) : SpecializedStation<Waypoint, true>(tile) { }
@ -27,29 +24,19 @@ struct Waypoint : WaypointPool::PoolItem<&_waypoint_pool>, SpecializedStation<Wa
/* virtual */ FORCEINLINE bool TileBelongsToRailStation(TileIndex tile) const /* 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 */ uint32 GetNewGRFVariable(const struct ResolverObject *object, byte variable, byte parameter, bool *available) const;
/* virtual */ void GetTileArea(TileArea *ta, StationType type) 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_BASE_STATIONS_OF_TYPE(Waypoint, var)
#define FOR_ALL_WAYPOINTS(var) FOR_ALL_WAYPOINTS_FROM(var, 0)
CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justremove); CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justremove);
void ShowWaypointWindow(const Waypoint *wp); void ShowWaypointWindow(const Waypoint *wp);
void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype); void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype);
void MakeDefaultWaypointName(Waypoint *wp);
#endif /* WAYPOINT_H */ #endif /* WAYPOINT_H */

@ -39,7 +39,7 @@ void Waypoint::UpdateVirtCoord()
* Set the default name for a waypoint * Set the default name for a waypoint
* @param wp Waypoint to work on * @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 used = 0; // bitmap of used waypoint numbers, sliding window with 'next' as base
uint32 next = 0; // first waypoint number in the bitmap uint32 next = 0; // first waypoint number in the bitmap
@ -64,7 +64,7 @@ static void MakeDefaultWaypointName(Waypoint *wp)
/* check only valid waypoints... */ /* check only valid waypoints... */
if (lwp != NULL && wp != lwp) { if (lwp != NULL && wp != lwp) {
/* only waypoints with 'generic' name within the same city */ /* 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' */ /* if lwp->town_cn < next, uint will overflow to '+inf' */
uint i = (uint)lwp->town_cn - next; uint i = (uint)lwp->town_cn - next;
@ -104,7 +104,7 @@ static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
uint thres = 8; uint thres = 8;
FOR_ALL_WAYPOINTS(wp) { 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); uint cur_dist = DistanceManhattan(tile, wp->xy);
if (cur_dist < thres) { if (cur_dist < thres) {
@ -163,10 +163,6 @@ CommandCost CmdBuildTrainWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
if (wp == NULL) { if (wp == NULL) {
wp = new Waypoint(tile); wp = new Waypoint(tile);
wp->town = NULL;
wp->name = NULL;
wp->town_cn = 0;
} else { } else {
/* Move existing (recently deleted) waypoint to the new location */ /* Move existing (recently deleted) waypoint to the new location */
@ -186,15 +182,16 @@ CommandCost CmdBuildTrainWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1
wp->owner = owner; wp->owner = owner;
bool reserved = HasBit(GetRailReservationTrackBits(tile), AxisToTrack(axis)); bool reserved = HasBit(GetRailReservationTrackBits(tile), AxisToTrack(axis));
MakeRailWaypoint(tile, owner, axis, GetRailType(tile), wp->index); MakeRailWaypoint(tile, owner, wp->index, axis, 0, GetRailType(tile));
SetDepotReservation(tile, reserved); SetRailwayStationReservation(tile, reserved);
MarkTileDirtyByTile(tile); 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->delete_ctr = 0;
wp->facilities |= FACIL_TRAIN; wp->facilities |= FACIL_TRAIN;
wp->build_date = _date; wp->build_date = _date;
wp->string_id = STR_SV_STNAME_WAYPOINT;
if (wp->town == NULL) MakeDefaultWaypointName(wp); if (wp->town == NULL) MakeDefaultWaypointName(wp);
@ -224,22 +221,22 @@ CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justre
} }
if (flags & DC_EXEC) { if (flags & DC_EXEC) {
Track track = GetRailWaypointTrack(tile); Track track = GetRailStationTrack(tile);
wp = Waypoint::GetByTile(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->sign.MarkDirty();
wp->facilities &= ~FACIL_TRAIN; wp->facilities &= ~FACIL_TRAIN;
Train *v = NULL; Train *v = NULL;
uint specindex = GetCustomStationSpecIndex(tile);
if (justremove) { if (justremove) {
TrackBits tracks = GetRailWaypointBits(tile); TrackBits tracks = GetRailStationTrackBits(tile);
bool reserved = HasDepotReservation(tile); bool reserved = HasStationReservation(tile);
MakeRailNormal(tile, wp->owner, tracks, GetRailType(tile)); MakeRailNormal(tile, wp->owner, tracks, GetRailType(tile));
if (reserved) SetTrackReservation(tile, tracks); if (reserved) SetTrackReservation(tile, tracks);
MarkTileDirtyByTile(tile); MarkTileDirtyByTile(tile);
} else { } else {
if (HasDepotReservation(tile)) { if (HasStationReservation(tile)) {
v = GetTrainForReservation(tile, track); v = GetTrainForReservation(tile, track);
if (v != NULL) FreeTrainTrackReservation(v); if (v != NULL) FreeTrainTrackReservation(v);
} }
@ -249,7 +246,7 @@ CommandCost RemoveTrainWaypoint(TileIndex tile, DoCommandFlag flags, bool justre
YapfNotifyTrackLayoutChange(tile, track); YapfNotifyTrackLayoutChange(tile, track);
if (v != NULL) TryPathReserve(v, true); 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); return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
@ -290,7 +287,7 @@ static bool IsUniqueWaypointName(const char *name)
CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) CommandCost CmdRenameWaypoint(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{ {
Waypoint *wp = Waypoint::GetIfValid(p1); 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); bool reset = StrEmpty(text);

@ -37,7 +37,7 @@ public:
WaypointWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number) WaypointWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{ {
this->wp = Waypoint::Get(this->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; if (this->wp->owner != OWNER_NONE) this->owner = this->wp->owner;

@ -406,7 +406,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th
/* We will end in this pass (station is possible target) */ /* We will end in this pass (station is possible target) */
end_segment_reason |= ESRB_STATION; 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. */ /* Waypoint is also a good reason to finish. */
end_segment_reason |= ESRB_WAYPOINT; end_segment_reason |= ESRB_WAYPOINT;
} else if (TrackFollower::DoTrackMasking() && cur.tile_type == MP_RAILWAY) { } else if (TrackFollower::DoTrackMasking() && cur.tile_type == MP_RAILWAY) {

@ -134,22 +134,11 @@ public:
m_destTrackdirs = INVALID_TRACKDIR_BIT; m_destTrackdirs = INVALID_TRACKDIR_BIT;
break; break;
case OT_GOTO_WAYPOINT: { case OT_GOTO_WAYPOINT:
Waypoint *wp = Waypoint::Get(v->current_order.GetDestination()); m_destTile = Waypoint::Get(v->current_order.GetDestination())->xy;
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);
}
m_dest_station_id = INVALID_STATION; 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; break;
}
default: default:
m_destTile = v->dest_tile; m_destTile = v->dest_tile;

Loading…
Cancel
Save