00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "bridge_map.h"
00008 #include "debug.h"
00009 #include "station_map.h"
00010 #include "station.h"
00011 #include "town.h"
00012 #include "news.h"
00013 #include "saveload.h"
00014 #include "player_func.h"
00015 #include "airport.h"
00016 #include "sprite.h"
00017 #include "depot.h"
00018 #include "train.h"
00019 #include "water_map.h"
00020 #include "industry_map.h"
00021 #include "newgrf_callbacks.h"
00022 #include "newgrf_station.h"
00023 #include "yapf/yapf.h"
00024 #include "cargotype.h"
00025 #include "roadveh.h"
00026 #include "station_gui.h"
00027 #include "zoom_func.h"
00028 #include "functions.h"
00029 #include "window_func.h"
00030 #include "date_func.h"
00031 #include "variables.h"
00032 #include "settings_type.h"
00033 #include "command_func.h"
00034 #include "aircraft.h"
00035
00036 #include "table/sprites.h"
00037 #include "table/strings.h"
00038
00039 Station::Station(TileIndex tile)
00040 {
00041 DEBUG(station, cDebugCtorLevel, "I+%3d", index);
00042
00043 xy = tile;
00044 airport_tile = dock_tile = train_tile = 0;
00045 bus_stops = truck_stops = NULL;
00046 had_vehicle_of_type = 0;
00047 time_since_load = 255;
00048 time_since_unload = 255;
00049 delete_ctr = 0;
00050 facilities = 0;
00051
00052 last_vehicle_type = VEH_INVALID;
00053
00054 random_bits = 0;
00055 waiting_triggers = 0;
00056 }
00057
00064 Station::~Station()
00065 {
00066 DEBUG(station, cDebugCtorLevel, "I-%3d", index);
00067
00068 free(this->name);
00069 free(this->speclist);
00070
00071 if (CleaningPool()) return;
00072
00073 while (!loading_vehicles.empty()) {
00074 loading_vehicles.front()->LeaveStation();
00075 }
00076
00077 Vehicle *v;
00078 FOR_ALL_VEHICLES(v) {
00079 if (v->type == VEH_AIRCRAFT && IsNormalAircraft(v) && v->u.air.targetairport == this->index) {
00080 v->u.air.targetairport = INVALID_STATION;
00081 }
00082 }
00083
00084 MarkDirty();
00085 RebuildStationLists();
00086 InvalidateWindowClasses(WC_STATION_LIST);
00087
00088 DeleteWindowById(WC_STATION_VIEW, index);
00089
00090
00091 RemoveOrderFromAllVehicles(OT_GOTO_STATION, index);
00092
00093
00094 DeleteSubsidyWithStation(index);
00095
00096 xy = 0;
00097
00098 for (CargoID c = 0; c < NUM_CARGO; c++) {
00099 goods[c].cargo.Truncate(0);
00100 }
00101 }
00102
00103
00109 RoadStop *Station::GetPrimaryRoadStop(const Vehicle *v) const
00110 {
00111 RoadStop *rs = this->GetPrimaryRoadStop(IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? RoadStop::BUS : RoadStop::TRUCK);
00112
00113 for (; rs != NULL; rs = rs->next) {
00114
00115 if ((GetRoadTypes(rs->xy) & v->u.road.compatible_roadtypes) == ROADTYPES_NONE) continue;
00116
00117 if (IsStandardRoadStopTile(rs->xy) && RoadVehHasArticPart(v)) continue;
00118
00119
00120 break;
00121 }
00122
00123 return rs;
00124 }
00125
00128 void Station::AddFacility(byte new_facility_bit, TileIndex facil_xy)
00129 {
00130 if (facilities == 0) {
00131 xy = facil_xy;
00132 random_bits = Random();
00133 }
00134 facilities |= new_facility_bit;
00135 owner = _current_player;
00136 build_date = _date;
00137 }
00138
00139 void Station::MarkDirty() const
00140 {
00141 if (sign.width_1 != 0) {
00142 InvalidateWindowWidget(WC_STATION_VIEW, index, SVW_CAPTION);
00143
00144
00145
00146
00147 MarkAllViewportsDirty(
00148 sign.left - 6,
00149 sign.top,
00150 sign.left + ScaleByZoom(sign.width_1 + 12, ZOOM_LVL_MAX),
00151 sign.top + ScaleByZoom(12, ZOOM_LVL_MAX));
00152 }
00153 }
00154
00155 void Station::MarkTilesDirty(bool cargo_change) const
00156 {
00157 TileIndex tile = train_tile;
00158 int w, h;
00159
00160
00161 if (tile == 0) return;
00162
00163
00164
00165 if (cargo_change) {
00166
00167
00168
00169 if (this->num_specs == 0) return;
00170 }
00171
00172 for (h = 0; h < trainst_h; h++) {
00173 for (w = 0; w < trainst_w; w++) {
00174 if (TileBelongsToRailStation(tile)) {
00175 MarkTileDirtyByTile(tile);
00176 }
00177 tile += TileDiffXY(1, 0);
00178 }
00179 tile += TileDiffXY(-w, 1);
00180 }
00181 }
00182
00183 bool Station::TileBelongsToRailStation(TileIndex tile) const
00184 {
00185 return IsTileType(tile, MP_STATION) && GetStationIndex(tile) == index && IsRailwayStation(tile);
00186 }
00187
00193 uint Station::GetPlatformLength(TileIndex tile) const
00194 {
00195 TileIndex t;
00196 TileIndexDiff delta;
00197 uint len = 0;
00198 assert(TileBelongsToRailStation(tile));
00199
00200 delta = (GetRailStationAxis(tile) == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1));
00201
00202 t = tile;
00203 do {
00204 t -= delta;
00205 len++;
00206 } while (IsCompatibleTrainStationTile(t, tile));
00207
00208 t = tile;
00209 do {
00210 t += delta;
00211 len++;
00212 } while (IsCompatibleTrainStationTile(t, tile));
00213
00214 return len - 1;
00215 }
00216
00223 uint Station::GetPlatformLength(TileIndex tile, DiagDirection dir) const
00224 {
00225 TileIndex start_tile = tile;
00226 uint length = 0;
00227 assert(IsRailwayStationTile(tile));
00228 assert(dir < DIAGDIR_END);
00229
00230 do {
00231 length ++;
00232 tile += TileOffsByDiagDir(dir);
00233 } while (IsCompatibleTrainStationTile(tile, start_tile));
00234
00235 return length;
00236 }
00237
00241 bool Station::IsBuoy() const
00242 {
00243 return (had_vehicle_of_type & HVOT_BUOY) != 0;
00244 }
00245
00246
00247
00248
00249
00250
00251 StationRect::StationRect()
00252 {
00253 MakeEmpty();
00254 }
00255
00256 void StationRect::MakeEmpty()
00257 {
00258 left = top = right = bottom = 0;
00259 }
00260
00270 bool StationRect::PtInExtendedRect(int x, int y, int distance) const
00271 {
00272 return (left - distance <= x && x <= right + distance && top - distance <= y && y <= bottom + distance);
00273 }
00274
00275 bool StationRect::IsEmpty() const
00276 {
00277 return (left == 0 || left > right || top > bottom);
00278 }
00279
00280 bool StationRect::BeforeAddTile(TileIndex tile, StationRectMode mode)
00281 {
00282 int x = TileX(tile);
00283 int y = TileY(tile);
00284 if (IsEmpty()) {
00285
00286 left = right = x;
00287 top = bottom = y;
00288
00289 } else if (!PtInExtendedRect(x, y)) {
00290
00291
00292 Rect new_rect = {min(x, left), min(y, top), max(x, right), max(y, bottom)};
00293
00294
00295 int w = new_rect.right - new_rect.left + 1;
00296 int h = new_rect.bottom - new_rect.top + 1;
00297 if (mode != ADD_FORCE && (w > _patches.station_spread || h > _patches.station_spread)) {
00298 assert(mode != ADD_TRY);
00299 _error_message = STR_306C_STATION_TOO_SPREAD_OUT;
00300 return false;
00301 }
00302
00303
00304 if (mode != ADD_TEST) {
00305
00306 *this = new_rect;
00307 }
00308 } else {
00309 ;
00310 }
00311 return true;
00312 }
00313
00314 bool StationRect::BeforeAddRect(TileIndex tile, int w, int h, StationRectMode mode)
00315 {
00316 return BeforeAddTile(tile, mode) && BeforeAddTile(TILE_ADDXY(tile, w - 1, h - 1), mode);
00317 }
00318
00319 bool StationRect::ScanForStationTiles(StationID st_id, int left_a, int top_a, int right_a, int bottom_a)
00320 {
00321 TileIndex top_left = TileXY(left_a, top_a);
00322 int width = right_a - left_a + 1;
00323 int height = bottom_a - top_a + 1;
00324
00325 BEGIN_TILE_LOOP(tile, width, height, top_left)
00326 if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st_id) return true;
00327 END_TILE_LOOP(tile, width, height, top_left);
00328
00329 return false;
00330 }
00331
00332 bool StationRect::AfterRemoveTile(Station *st, TileIndex tile)
00333 {
00334 int x = TileX(tile);
00335 int y = TileY(tile);
00336
00337
00338
00339
00340 for (;;) {
00341
00342 bool left_edge = (x == left);
00343 bool right_edge = (x == right);
00344 bool top_edge = (y == top);
00345 bool bottom_edge = (y == bottom);
00346
00347
00348 bool reduce_x = ((left_edge || right_edge) && !ScanForStationTiles(st->index, x, top, x, bottom));
00349 bool reduce_y = ((top_edge || bottom_edge) && !ScanForStationTiles(st->index, left, y, right, y));
00350 if (!(reduce_x || reduce_y)) break;
00351
00352 if (reduce_x) {
00353
00354 if (left_edge) {
00355
00356 left = x = x + 1;
00357 } else {
00358
00359 right = x = x - 1;
00360 }
00361 }
00362 if (reduce_y) {
00363
00364 if (top_edge) {
00365
00366 top = y = y + 1;
00367 } else {
00368
00369 bottom = y = y - 1;
00370 }
00371 }
00372
00373 if (left > right || top > bottom) {
00374
00375 MakeEmpty();
00376 return true;
00377 }
00378 }
00379 return false;
00380 }
00381
00382 bool StationRect::AfterRemoveRect(Station *st, TileIndex tile, int w, int h)
00383 {
00384 assert(PtInExtendedRect(TileX(tile), TileY(tile)));
00385 assert(PtInExtendedRect(TileX(tile) + w - 1, TileY(tile) + h - 1));
00386
00387 bool empty = AfterRemoveTile(st, tile);
00388 if (w != 1 || h != 1) empty = empty || AfterRemoveTile(st, TILE_ADDXY(tile, w - 1, h - 1));
00389 return empty;
00390 }
00391
00392 StationRect& StationRect::operator = (Rect src)
00393 {
00394 left = src.left;
00395 top = src.top;
00396 right = src.right;
00397 bottom = src.bottom;
00398 return *this;
00399 }
00400
00401
00402
00403
00404
00405
00407 RoadStop::RoadStop(TileIndex tile) :
00408 xy(tile),
00409 status(3),
00410 num_vehicles(0),
00411 next(NULL)
00412 {
00413 DEBUG(ms, cDebugCtorLevel, "I+ at %d[0x%x]", tile, tile);
00414 }
00415
00419 RoadStop::~RoadStop()
00420 {
00421 if (CleaningPool()) return;
00422
00423
00424 if (num_vehicles != 0) {
00425 Vehicle *v;
00426
00427 FOR_ALL_VEHICLES(v) {
00428 if (v->type == VEH_ROAD && v->u.road.slot == this) ClearSlot(v);
00429 }
00430 }
00431 assert(num_vehicles == 0);
00432
00433 DEBUG(ms, cDebugCtorLevel , "I- at %d[0x%x]", xy, xy);
00434
00435 xy = 0;
00436 }
00437
00439 bool RoadStop::HasFreeBay() const
00440 {
00441 return GB(status, 0, MAX_BAY_COUNT) != 0;
00442 }
00443
00445 bool RoadStop::IsFreeBay(uint nr) const
00446 {
00447 assert(nr < MAX_BAY_COUNT);
00448 return HasBit(status, nr);
00449 }
00450
00456 uint RoadStop::AllocateBay()
00457 {
00458 assert(HasFreeBay());
00459
00460
00461 uint bay_nr = 0;
00462 while (!HasBit(status, bay_nr)) bay_nr++;
00463
00464 ClrBit(status, bay_nr);
00465 return bay_nr;
00466 }
00467
00472 void RoadStop::AllocateDriveThroughBay(uint nr)
00473 {
00474 assert(nr < MAX_BAY_COUNT);
00475 ClrBit(status, nr);
00476 }
00477
00482 void RoadStop::FreeBay(uint nr)
00483 {
00484 assert(nr < MAX_BAY_COUNT);
00485 SetBit(status, nr);
00486 }
00487
00488
00490 bool RoadStop::IsEntranceBusy() const
00491 {
00492 return HasBit(status, 7);
00493 }
00494
00496 void RoadStop::SetEntranceBusy(bool busy)
00497 {
00498 SB(status, 7, 1, busy);
00499 }
00500
00506 RoadStop *RoadStop::GetNextRoadStop(const Vehicle *v) const
00507 {
00508 for (RoadStop *rs = this->next; rs != NULL; rs = rs->next) {
00509
00510 if ((GetRoadTypes(rs->xy) & v->u.road.compatible_roadtypes) == ROADTYPES_NONE) continue;
00511
00512 if (IsStandardRoadStopTile(rs->xy) && RoadVehHasArticPart(v)) continue;
00513
00514
00515 return rs;
00516 }
00517
00518 return NULL;
00519 }