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