roadstop.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "roadveh.h"
00014 #include "core/pool_func.hpp"
00015 #include "roadstop_base.h"
00016 #include "station_base.h"
00017 #include "vehicle_func.h"
00018
00019 RoadStopPool _roadstop_pool("RoadStop");
00020 INSTANTIATE_POOL_METHODS(RoadStop)
00021
00022
00025 RoadStop::~RoadStop()
00026 {
00027
00028 if (HasBit(this->status, RSSFB_BASE_ENTRY)) {
00029 delete this->east;
00030 delete this->west;
00031 }
00032
00033 if (CleaningPool()) return;
00034 }
00035
00041 RoadStop *RoadStop::GetNextRoadStop(const RoadVehicle *v) const
00042 {
00043 for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) {
00044
00045 if ((GetRoadTypes(rs->xy) & v->compatible_roadtypes) == ROADTYPES_NONE) continue;
00046
00047 if (IsStandardRoadStopTile(rs->xy) && v->HasArticulatedPart()) continue;
00048
00049
00050 return rs;
00051 }
00052
00053 return NULL;
00054 }
00055
00061 void RoadStop::MakeDriveThrough()
00062 {
00063 assert(this->east == NULL && this->west == NULL);
00064
00065 RoadStopType rst = GetRoadStopType(this->xy);
00066 DiagDirection dir = GetRoadStopDir(this->xy);
00067
00068 TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
00069
00070
00071 TileIndex north_tile = this->xy - offset;
00072 bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
00073 RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL;
00074
00075
00076 TileIndex south_tile = this->xy + offset;
00077 bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
00078 RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL;
00079
00080
00081 int added = 1;
00082 if (north && rs_north->east != NULL) {
00083
00084 this->east = rs_north->east;
00085 this->west = rs_north->west;
00086
00087 if (south && rs_south->east != NULL) {
00088
00089 ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
00090 this->east->occupied += rs_south->east->occupied;
00091 this->west->occupied += rs_south->west->occupied;
00092
00093
00094 delete rs_south->east;
00095 delete rs_south->west;
00096
00097
00098 for (; IsDriveThroughRoadStopContinuation(this->xy, south_tile); south_tile += offset) {
00099 rs_south = RoadStop::GetByTile(south_tile, rst);
00100 if (rs_south->east == NULL) break;
00101 rs_south->east = rs_north->east;
00102 rs_south->west = rs_north->west;
00103 added++;
00104 }
00105 }
00106 } else if (south && rs_south->east != NULL) {
00107
00108 this->east = rs_south->east;
00109 this->west = rs_south->west;
00110 SetBit(this->status, RSSFB_BASE_ENTRY);
00111 ClrBit(rs_south->status, RSSFB_BASE_ENTRY);
00112 } else {
00113
00114 this->east = new Entry();
00115 this->west = new Entry();
00116 SetBit(this->status, RSSFB_BASE_ENTRY);
00117 }
00118
00119
00120 added *= TILE_SIZE;
00121 this->east->length += added;
00122 this->west->length += added;
00123 }
00124
00129 void RoadStop::ClearDriveThrough()
00130 {
00131 assert(this->east != NULL && this->west != NULL);
00132
00133 RoadStopType rst = GetRoadStopType(this->xy);
00134 DiagDirection dir = GetRoadStopDir(this->xy);
00135
00136 TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
00137
00138
00139 TileIndex north_tile = this->xy - offset;
00140 bool north = IsDriveThroughRoadStopContinuation(this->xy, north_tile);
00141 RoadStop *rs_north = north ? RoadStop::GetByTile(north_tile, rst) : NULL;
00142
00143
00144 TileIndex south_tile = this->xy + offset;
00145 bool south = IsDriveThroughRoadStopContinuation(this->xy, south_tile);
00146 RoadStop *rs_south = south ? RoadStop::GetByTile(south_tile, rst) : NULL;
00147
00148
00149
00150 DoClearSquare(this->xy);
00151
00152 if (north) {
00153
00154 if (south) {
00155
00156
00157 SetBit(rs_south->status, RSSFB_BASE_ENTRY);
00158 rs_south->east = new Entry();
00159 rs_south->west = new Entry();
00160
00161
00162 RoadStop *rs_south_base = rs_south;
00163 TileIndex base_tile = south_tile;
00164
00165
00166 for (south_tile += offset; IsDriveThroughRoadStopContinuation(base_tile, south_tile); south_tile += offset) {
00167 rs_south = RoadStop::GetByTile(south_tile, rst);
00168 rs_south->east = rs_south_base->east;
00169 rs_south->west = rs_south_base->west;
00170 }
00171
00172
00173 for (; IsDriveThroughRoadStopContinuation(base_tile, north_tile); north_tile -= offset) {
00174 rs_north = RoadStop::GetByTile(north_tile, rst);
00175 }
00176
00177
00178
00179
00180
00181
00182
00183 rs_south_base->east->Rebuild(rs_south_base);
00184 rs_south_base->west->Rebuild(rs_south_base);
00185
00186 assert(HasBit(rs_north->status, RSSFB_BASE_ENTRY));
00187 rs_north->east->Rebuild(rs_north);
00188 rs_north->west->Rebuild(rs_north);
00189 } else {
00190
00191 rs_north->east->length -= TILE_SIZE;
00192 rs_north->west->length -= TILE_SIZE;
00193 }
00194 } else if (south) {
00195
00196 SetBit(rs_south->status, RSSFB_BASE_ENTRY);
00197 rs_south->east->length -= TILE_SIZE;
00198 rs_south->west->length -= TILE_SIZE;
00199 } else {
00200
00201 delete this->east;
00202 delete this->west;
00203 }
00204
00205
00206 ClrBit(this->status, RSSFB_BASE_ENTRY);
00207 this->east = NULL;
00208 this->west = NULL;
00209 }
00210
00215 void RoadStop::Leave(RoadVehicle *rv)
00216 {
00217 if (IsStandardRoadStopTile(rv->tile)) {
00218
00219 this->FreeBay(HasBit(rv->state, RVS_USING_SECOND_BAY));
00220 this->SetEntranceBusy(false);
00221 } else {
00222
00223 this->GetEntry(DirToDiagDir(rv->direction))->Leave(rv);
00224 }
00225 }
00226
00232 bool RoadStop::Enter(RoadVehicle *rv)
00233 {
00234 if (IsStandardRoadStopTile(this->xy)) {
00235
00236
00237 if (this->IsEntranceBusy() || !this->HasFreeBay() || rv->HasArticulatedPart()) return false;
00238
00239 SetBit(rv->state, RVS_IN_ROAD_STOP);
00240
00241
00242 uint bay_nr = this->AllocateBay();
00243 SB(rv->state, RVS_USING_SECOND_BAY, 1, bay_nr);
00244
00245
00246 this->SetEntranceBusy(true);
00247 return true;
00248 }
00249
00250
00251 this->GetEntry(DirToDiagDir(rv->direction))->Enter(rv);
00252
00253
00254 SetBit(rv->state, RVS_IN_DT_ROAD_STOP);
00255 return true;
00256 }
00257
00265 RoadStop *RoadStop::GetByTile(TileIndex tile, RoadStopType type)
00266 {
00267 const Station *st = Station::GetByTile(tile);
00268
00269 for (RoadStop *rs = st->GetPrimaryRoadStop(type);; rs = rs->next) {
00270 if (rs->xy == tile) return rs;
00271 assert(rs->next != NULL);
00272 }
00273 }
00274
00279 void RoadStop::Entry::Leave(const RoadVehicle *rv)
00280 {
00281 this->occupied -= rv->gcache.cached_total_length;
00282 assert(this->occupied >= 0);
00283 }
00284
00289 void RoadStop::Entry::Enter(const RoadVehicle *rv)
00290 {
00291
00292
00293
00294 this->occupied += rv->gcache.cached_total_length;
00295 }
00296
00304 bool RoadStop::IsDriveThroughRoadStopContinuation(TileIndex rs, TileIndex next)
00305 {
00306 return IsTileType(next, MP_STATION) &&
00307 GetStationIndex(next) == GetStationIndex(rs) &&
00308 GetStationType(next) == GetStationType(rs) &&
00309 GetRoadStopDir(next) == GetRoadStopDir(rs) &&
00310 IsDriveThroughStopTile(next);
00311 }
00312
00313 typedef std::list<const RoadVehicle *> RVList;
00314
00316 struct RoadStopEntryRebuilderHelper {
00317 RVList vehicles;
00318 DiagDirection dir;
00319 };
00320
00327 Vehicle *FindVehiclesInRoadStop(Vehicle *v, void *data)
00328 {
00329 RoadStopEntryRebuilderHelper *rserh = (RoadStopEntryRebuilderHelper*)data;
00330
00331 if (v->type != VEH_ROAD || DirToDiagDir(v->direction) != rserh->dir || !v->IsPrimaryVehicle() || (v->vehstatus & VS_CRASHED) != 0) return NULL;
00332
00333 RoadVehicle *rv = RoadVehicle::From(v);
00334
00335 if (rv->state < RVSB_IN_ROAD_STOP) return NULL;
00336
00337
00338 for (RVList::iterator it = rserh->vehicles.begin(); it != rserh->vehicles.end(); it++) {
00339 if (rv == *it) return NULL;
00340 }
00341
00342 rserh->vehicles.push_back(rv);
00343 return NULL;
00344 }
00345
00351 void RoadStop::Entry::Rebuild(const RoadStop *rs, int side)
00352 {
00353 assert(HasBit(rs->status, RSSFB_BASE_ENTRY));
00354
00355 DiagDirection dir = GetRoadStopDir(rs->xy);
00356 if (side == -1) side = (rs->east == this);
00357
00358 RoadStopEntryRebuilderHelper rserh;
00359 rserh.dir = side ? dir : ReverseDiagDir(dir);
00360
00361 this->length = 0;
00362 TileIndexDiff offset = abs(TileOffsByDiagDir(dir));
00363 for (TileIndex tile = rs->xy; IsDriveThroughRoadStopContinuation(rs->xy, tile); tile += offset) {
00364 this->length += TILE_SIZE;
00365 FindVehicleOnPos(tile, &rserh, FindVehiclesInRoadStop);
00366 }
00367
00368 this->occupied = 0;
00369 for (RVList::iterator it = rserh.vehicles.begin(); it != rserh.vehicles.end(); it++) {
00370 this->occupied += (*it)->gcache.cached_total_length;
00371 }
00372 }
00373
00374
00379 void RoadStop::Entry::CheckIntegrity(const RoadStop *rs) const
00380 {
00381 if (!HasBit(rs->status, RSSFB_BASE_ENTRY)) return;
00382
00383
00384 assert(!IsDriveThroughRoadStopContinuation(rs->xy, rs->xy - abs(TileOffsByDiagDir(GetRoadStopDir(rs->xy)))));
00385
00386 Entry temp;
00387 temp.Rebuild(rs, rs->east == this);
00388 if (temp.length != this->length || temp.occupied != this->occupied) NOT_REACHED();
00389 }
00390
00391
00392 void InitializeRoadStops()
00393 {
00394 _roadstop_pool.CleanPool();
00395 }