OpenTTD
roadstop.cpp
Go to the documentation of this file.
1 /* $Id: roadstop.cpp 26482 2014-04-23 20:13:33Z rubidium $ */
2 
3 /*
4  * This file is part of OpenTTD.
5  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8  */
9 
12 #include "stdafx.h"
13 #include "roadveh.h"
14 #include "core/pool_func.hpp"
15 #include "roadstop_base.h"
16 #include "station_base.h"
17 #include "vehicle_func.h"
18 
19 #include "safeguards.h"
20 
22 RoadStopPool _roadstop_pool("RoadStop");
24 
25 
29 {
30  /* When we are the head we need to free the entries */
31  if (HasBit(this->status, RSSFB_BASE_ENTRY)) {
32  delete this->east;
33  delete this->west;
34  }
35 
36  if (CleaningPool()) return;
37 }
38 
45 {
46  for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) {
47  /* The vehicle cannot go to this roadstop (different roadtype) */
48  if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue;
49  /* The vehicle is articulated and can therefore not go to a standard road stop. */
50  if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue;
51 
52  /* The vehicle can actually go to this road stop. So, return it! */
53  return rs;
54  }
55 
56  return NULL;
57 }
58 
65 {
66  assert(this->east == NULL && this->west == NULL);
67 
68  RoadStopType rst = GetRoadStopType(this->xy);
69  DiagDirection dir = GetRoadStopDir(this->xy);
70  /* Use absolute so we always go towards the northern tile */
71  TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
72 
73  /* Information about the tile north of us */
74  TileIndex north_tile = this->xy - offset;
75  bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
76  RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL;
77 
78  /* Information about the tile south of us */
79  TileIndex south_tile = this->xy + offset;
80  bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
81  RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL;
82 
83  /* Amount of road stops that will be added to the 'northern' head */
84  int added = 1;
85  if (north && rs_north->east != NULL) { // (east != NULL) == (west != NULL)
86  /* There is a more northern one, so this can join them */
87  this->east = rs_north->east;
88  this->west = rs_north->west;
89 
90  if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL)
91  /* There more southern tiles too, they must 'join' us too */
92  ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
93  this->east->occupied += rs_south->east->occupied;
94  this->west->occupied += rs_south->west->occupied;
95 
96  /* Free the now unneeded entry structs */
97  delete rs_south->east;
98  delete rs_south->west;
99 
100  /* Make all 'children' of the southern tile take the new master */
101  for (; IsDriveThroughRoadStopContinuation(this->xy, south_tile); south_tile += offset) {
102  rs_south = RoadStop::GetByTile(south_tile, rst);
103  if (rs_south->east == NULL) break;
104  rs_south->east = rs_north->east;
105  rs_south->west = rs_north->west;
106  added++;
107  }
108  }
109  } else if (south && rs_south->east != NULL) { // (east != NULL) == (west != NULL)
110  /* There is one to the south, but not to the north... so we become 'parent' */
111  this->east = rs_south->east;
112  this->west = rs_south->west;
114  ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
115  } else {
116  /* We are the only... so we are automatically the master */
117  this->east = new Entry();
118  this->west = new Entry();
120  }
121 
122  /* Now update the lengths */
123  added *= TILE_SIZE;
124  this->east->length += added;
125  this->west->length += added;
126 }
127 
133 {
134  assert(this->east != NULL && this->west != NULL);
135 
136  RoadStopType rst = GetRoadStopType(this->xy);
137  DiagDirection dir = GetRoadStopDir(this->xy);
138  /* Use absolute so we always go towards the northern tile */
139  TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
140 
141  /* Information about the tile north of us */
142  TileIndex north_tile = this->xy - offset;
143  bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
144  RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL;
145 
146  /* Information about the tile south of us */
147  TileIndex south_tile = this->xy + offset;
148  bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
149  RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL;
150 
151  /* Must only be cleared after we determined which neighbours are
152  * part of our little entry 'queue' */
153  DoClearSquare(this->xy);
154 
155  if (north) {
156  /* There is a tile to the north, so we can't clear ourselves. */
157  if (south) {
158  /* There are more southern tiles too, they must be split;
159  * first make the new southern 'base' */
160  SetBit(rs_south->status, RSSFB_BASE_ENTRY);
161  rs_south->east = new Entry();
162  rs_south->west = new Entry();
163 
164  /* Keep track of the base because we need it later on */
165  RoadStop *rs_south_base = rs_south;
166  TileIndex base_tile = south_tile;
167 
168  /* Make all (even more) southern stops part of the new entry queue */
169  for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) {
170  rs_south = RoadStop::GetByTile(south_tile, rst);
171  rs_south->east = rs_south_base->east;
172  rs_south->west = rs_south_base->west;
173  }
174 
175  /* Find the other end; the northern most tile */
176  for (; IsDriveThroughRoadStopContinuation(base_tile, north_tile); north_tile -= offset) {
177  rs_north = RoadStop::GetByTile(north_tile, rst);
178  }
179 
180  /* We have to rebuild the entries because we cannot easily determine
181  * how full each part is. So instead of keeping and maintaining a list
182  * of vehicles and using that to 'rebuild' the occupied state we just
183  * rebuild it from scratch as that removes lots of maintenance code
184  * for the vehicle list and it's faster in real games as long as you
185  * do not keep split and merge road stop every tick by the millions. */
186  rs_south_base->east->Rebuild(rs_south_base);
187  rs_south_base->west->Rebuild(rs_south_base);
188 
189  assert(HasBit(rs_north->status, RSSFB_BASE_ENTRY));
190  rs_north->east->Rebuild(rs_north);
191  rs_north->west->Rebuild(rs_north);
192  } else {
193  /* Only we left, so simple update the length. */
194  rs_north->east->length -= TILE_SIZE;
195  rs_north->west->length -= TILE_SIZE;
196  }
197  } else if (south) {
198  /* There is only something to the south. Hand over the base entry */
199  SetBit(rs_south->status, RSSFB_BASE_ENTRY);
200  rs_south->east->length -= TILE_SIZE;
201  rs_south->west->length -= TILE_SIZE;
202  } else {
203  /* We were the last */
204  delete this->east;
205  delete this->west;
206  }
207 
208  /* Make sure we don't get used for something 'incorrect' */
210  this->east = NULL;
211  this->west = NULL;
212 }
213 
219 {
220  if (IsStandardRoadStopTile(rv->tile)) {
221  /* Vehicle is leaving a road stop tile, mark bay as free */
223  this->SetEntranceBusy(false);
224  } else {
225  /* Otherwise just leave the drive through's entry cache. */
226  this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
227  }
228 }
229 
236 {
237  if (IsStandardRoadStopTile(this->xy)) {
238  /* For normal (non drive-through) road stops
239  * Check if station is busy or if there are no free bays or whether it is a articulated vehicle. */
240  if (this->IsEntranceBusy() || !this->HasFreeBay() || rv->HasArticulatedPart()) return false;
241 
243 
244  /* Allocate a bay and update the road state */
245  uint bay_nr = this->AllocateBay();
246  SB(rv->state, RVS_USING_SECOND_BAY, 1, bay_nr);
247 
248  /* Mark the station entrance as busy */
249  this->SetEntranceBusy(true);
250  return true;
251  }
252 
253  /* Vehicles entering a drive-through stop from the 'normal' side use first bay (bay 0). */
254  this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
255 
256  /* Indicate a drive-through stop */
258  return true;
259 }
260 
269 {
270  const Station *st = Station::GetByTile(tile);
271 
272  for (RoadStop *rs = st->GetPrimaryRoadStop(type);; rs = rs->next) {
273  if (rs->xy == tile) return rs;
274  assert(rs->next != NULL);
275  }
276 }
277 
283 {
284  this->occupied -= rv->gcache.cached_total_length;
285  assert(this->occupied >= 0);
286 }
287 
293 {
294  /* we cannot assert on this->occupied < this->length because of the
295  * remote possibility that RVs are running through each other when
296  * trying to prevention an infinite jam. */
297  this->occupied += rv->gcache.cached_total_length;
298 }
299 
308 {
309  return IsTileType(next, MP_STATION) &&
310  GetStationIndex(next) == GetStationIndex(rs) &&
311  GetStationType(next) == GetStationType(rs) &&
312  GetRoadStopDir(next) == GetRoadStopDir(rs) &&
314 }
315 
316 typedef std::list<const RoadVehicle *> RVList;
317 
322 };
323 
331 {
333  /* Not a RV or not in the right direction or crashed :( */
334  if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return NULL;
335 
337  /* Don't add ones not in a road stop */
338  if (rv->state < RVSB_IN_ROAD_STOP) return NULL;
339 
340  /* Do not add duplicates! */
341  for (RVList::iterator it = rserh->vehicles.begin(); it != rserh->vehicles.end(); it++) {
342  if (rv == *it) return NULL;
343  }
344 
345  rserh->vehicles.push_back(rv);
346  return NULL;
347 }
348 
354 void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
355 {
356  assert(HasBit(rs->status, RSSFB_BASE_ENTRY));
357 
358  DiagDirection dir = GetRoadStopDir(rs->xy);
359  if (side == -1) side = (rs->east == this);
360 
362  rserh.dir = side ? dir : ReverseDiagDir(dir);
363 
364  this->length = 0;
365  TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
366  for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
367  this->length += TILE_SIZE;
369  }
370 
371  this->occupied = 0;
372  for (RVList::iterator it = rserh.vehicles.begin(); it != rserh.vehicles.end(); it++) {
373  this->occupied += (*it)->gcache.cached_total_length;
374  }
375 }
376 
377 
383 {
384  if (!HasBit(rs->status, RSSFB_BASE_ENTRY)) return;
385 
386  /* The tile 'before' the road stop must not be part of this 'line' */
388 
389  Entry temp;
390  temp.Rebuild(rs, rs->east == this);
391  if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED();
392 }
Road vehicle states.
byte state
Definition: roadveh.h:89
byte status
Current status of the Stop,.
Definition: roadstop_base.h:70
bool IsEntranceBusy() const
Checks whether the entrance of the road stop is occupied by a vehicle.
uint AllocateBay()
Allocates a bay.
static DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
DirectionByte direction
facing
Definition: vehicle_base.h:271
Base class for roadstops.
static RoadStopType GetRoadStopType(TileIndex t)
Get the road stop type of this tile.
Definition: station_map.h:57
int32 TileIndexDiff
An offset value between to tiles.
Definition: map_func.h:156
The vehicle is in a drive-through road stop.
Definition: roadveh.h:47
static T SetBit(T &x, const uint8 y)
Set a bit in a variable.
void Leave(RoadVehicle *rv)
Leave the road stop.
Definition: roadstop.cpp:218
TileIndex xy
Position on the map.
Definition: roadstop_base.h:69
void MakeDriveThrough()
Join this road stop to another &#39;base&#39; road stop if possible; fill all necessary data to become an act...
Definition: roadstop.cpp:64
Functions related to vehicles.
Vehicle data structure.
Definition: vehicle_base.h:212
void FreeBay(uint nr)
Frees the given bay.
void Enter(const RoadVehicle *rv)
Enter the road stop.
Definition: roadstop.cpp:292
static bool IsStandardRoadStopTile(TileIndex t)
Is tile t a standard (non-drive through) road stop station?
Definition: station_map.h:224
static bool IsDriveThroughStopTile(TileIndex t)
Is tile t a drive through road stop station?
Definition: station_map.h:234
byte vehstatus
Status.
Definition: vehicle_base.h:317
RoadStop * GetNextRoadStop(const struct RoadVehicle *v) const
Get the next road stop accessible by this vehicle.
Definition: roadstop.cpp:44
static RoadVehicle * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
static StationType GetStationType(TileIndex t)
Get the station type of this tile.
Definition: station_map.h:45
static const uint TILE_SIZE
Tile size in world coordinates.
Definition: tile_type.h:15
RoadStopType
Types of RoadStops.
Definition: station_type.h:47
static T SB(T &x, const uint8 s, const uint8 n, const U d)
Set n bits in x starting at bit s to d.
Buses, trucks and trams belong to this class.
Definition: roadveh.h:88
Helper for finding RVs in a road stop.
Definition: roadstop.cpp:319
Some methods of Pool are placed here in order to reduce compilation time and binary size...
Vehicle is crashed.
Definition: vehicle_base.h:39
static TileIndexDiff TileOffsByDiagDir(DiagDirection dir)
Convert a DiagDirection to a TileIndexDiff.
Definition: map_func.h:343
virtual bool IsPrimaryVehicle() const
Whether this is the primary vehicle in the chain.
Definition: vehicle_base.h:434
static bool IsTileType(TileIndex tile, TileType type)
Checks if a tile is a give tiletype.
Definition: tile_map.h:143
The vehicle is in a road stop.
Definition: roadveh.h:46
void ClearDriveThrough()
Prepare for removal of this stop; update other neighbouring stops if needed.
Definition: roadstop.cpp:132
RVList vehicles
The list of vehicles to possibly add to.
Definition: roadstop.cpp:320
static DiagDirection GetRoadStopDir(TileIndex t)
Gets the direction the road stop entrance points towards.
Definition: station_map.h:258
static DiagDirection ReverseDiagDir(DiagDirection d)
Returns the reverse direction of the given DiagDirection.
void CheckIntegrity(const RoadStop *rs) const
Check the integrity of the data in this struct.
Definition: roadstop.cpp:382
Definition of base types and functions in a cross-platform compatible way.
Entry * east
The vehicles that entered from the east.
void SetEntranceBusy(bool busy)
Makes an entrance occupied or free.
A number of safeguards to prevent using unsafe methods.
struct RoadStop * next
Next stop of the given type at this station.
Definition: roadstop_base.h:71
Only used while in a road stop.
Definition: roadveh.h:43
void FindVehicleOnPos(TileIndex tile, void *data, VehicleFromPosProc *proc)
Find a vehicle from a specific location.
Definition: vehicle.cpp:497
TileIndex tile
Current tile index.
Definition: vehicle_base.h:230
bool HasArticulatedPart() const
Check if an engine has an articulated part.
Definition: vehicle_base.h:900
DiagDirection
Enumeration for diagonal directions.
Road vehicle type.
Definition: vehicle_type.h:25
int length
The length of the stop in tile &#39;units&#39;.
Definition: roadstop_base.h:36
Entry * west
The vehicles that entered from the west.
Base class for all pools.
Definition: pool_type.hpp:83
Container for each entry point of a drive through road stop.
Definition: roadstop_base.h:34
bool Enter(RoadVehicle *rv)
Enter the road stop.
Definition: roadstop.cpp:235
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don&#39;t get linker errors.
Definition: pool_func.hpp:224
bool HasFreeBay() const
Checks whether there is a free bay in this road stop.
Definition: roadstop_base.h:85
static StationID GetStationIndex(TileIndex t)
Get StationID from a tile.
Definition: station_map.h:29
static T ClrBit(T &x, const uint8 y)
Clears a bit in a variable.
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:80
static T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition: math_func.hpp:83
uint16 cached_total_length
Length of the whole vehicle (valid only for the first engine).
int occupied
The amount of occupied stop in tile &#39;units&#39;.
Definition: roadstop_base.h:37
A tile of a station.
Definition: tile_type.h:48
static Station * GetByTile(TileIndex tile)
Get the station belonging to a specific tile.
Vehicle * FindVehiclesInRoadStop(Vehicle *v, void *data)
Add road vehicles to the station&#39;s list if needed.
Definition: roadstop.cpp:330
const Entry * GetEntry(DiagDirection dir) const
Get the drive through road stop entry struct for the given direction.
The vehicle is in a road stop.
Definition: roadveh.h:50
No roadtypes.
Definition: road_type.h:37
A Stop for a Road Vehicle.
Definition: roadstop_base.h:24
static bool IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next)
Checks whether the &#39;next&#39; tile is still part of the road same drive through stop &#39;rs&#39; in the same dir...
Definition: roadstop.cpp:307
std::list< const RoadVehicle * > RVList
A list of road vehicles.
Definition: roadstop.cpp:316
static RoadTypes GetRoadTypes(TileIndex t)
Get the present road types of a tile.
Definition: road_map.h:166
static bool HasBit(const T x, const uint8 y)
Checks if a bit in a value is set.
void Leave(const RoadVehicle *rv)
Leave the road stop.
Definition: roadstop.cpp:282
Non-zero when the entries on this road stop are the primary, i.e. the ones to delete.
Definition: roadstop_base.h:29
RoadStopPool _roadstop_pool("RoadStop")
The pool of roadstops.
DiagDirection dir
The direction the vehicle has to face to be added.
Definition: roadstop.cpp:321
Base classes/functions for stations.
void Rebuild(const RoadStop *rs, int side=-1)
Rebuild, from scratch, the vehicles and other metadata on this stop.
Definition: roadstop.cpp:354
VehicleTypeByte type
Type of vehicle.
Definition: vehicle_type.h:54
Station data structure.
Definition: station_base.h:446
static RoadStop * GetByTile(TileIndex tile, RoadStopType type)
Find a roadstop at given tile.
Definition: roadstop.cpp:268
GroundVehicleCache gcache
Cache of often calculated values.