00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "roadveh.h"
00014 #include "command_func.h"
00015 #include "news_func.h"
00016 #include "pathfinder/npf/npf_func.h"
00017 #include "station_base.h"
00018 #include "company_func.h"
00019 #include "vehicle_gui.h"
00020 #include "articulated_vehicles.h"
00021 #include "newgrf_sound.h"
00022 #include "pathfinder/yapf/yapf.h"
00023 #include "strings_func.h"
00024 #include "tunnelbridge_map.h"
00025 #include "window_func.h"
00026 #include "date_func.h"
00027 #include "vehicle_func.h"
00028 #include "sound_func.h"
00029 #include "ai/ai.hpp"
00030 #include "depot_map.h"
00031 #include "effectvehicle_func.h"
00032 #include "roadstop_base.h"
00033 #include "spritecache.h"
00034 #include "core/random_func.hpp"
00035 #include "company_base.h"
00036 #include "core/backup_type.hpp"
00037 #include "infrastructure_func.h"
00038 #include "engine_func.h"
00039
00040 #include "table/strings.h"
00041
00042 static const uint16 _roadveh_images[63] = {
00043 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
00044 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
00045 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
00046 0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
00047 0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
00048 0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
00049 0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
00050 0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
00051 };
00052
00053 static const uint16 _roadveh_full_adder[63] = {
00054 0, 88, 0, 0, 0, 0, 48, 48,
00055 48, 48, 0, 0, 64, 64, 0, 16,
00056 16, 0, 88, 0, 0, 0, 0, 48,
00057 48, 48, 48, 0, 0, 64, 64, 0,
00058 16, 16, 0, 88, 0, 0, 0, 0,
00059 48, 48, 48, 48, 0, 0, 64, 64,
00060 0, 16, 16, 0, 8, 8, 8, 8,
00061 0, 0, 0, 8, 8, 8, 8
00062 };
00063
00065 static const TrackdirBits _road_enter_dir_to_reachable_trackdirs[DIAGDIR_END] = {
00066 TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_X_NE,
00067 TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_Y_SE,
00068 TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_RIGHT_S,
00069 TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_Y_NW
00070 };
00071
00072 static const Trackdir _road_reverse_table[DIAGDIR_END] = {
00073 TRACKDIR_RVREV_NE, TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW, TRACKDIR_RVREV_NW
00074 };
00075
00077 static const Trackdir _roadveh_depot_exit_trackdir[DIAGDIR_END] = {
00078 TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW
00079 };
00080
00081
00086 bool RoadVehicle::IsBus() const
00087 {
00088 assert(this->IsFrontEngine());
00089 return IsCargoInClass(this->cargo_type, CC_PASSENGERS);
00090 }
00091
00097 int RoadVehicle::GetDisplayImageWidth(Point *offset) const
00098 {
00099 int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
00100
00101 if (offset != NULL) {
00102 offset->x = reference_width / 2;
00103 offset->y = 0;
00104 }
00105 return this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH;
00106 }
00107
00108 static SpriteID GetRoadVehIcon(EngineID engine)
00109 {
00110 const Engine *e = Engine::Get(engine);
00111 uint8 spritenum = e->u.road.image_index;
00112
00113 if (is_custom_sprite(spritenum)) {
00114 SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
00115 if (sprite != 0) return sprite;
00116
00117 spritenum = e->original_image_index;
00118 }
00119
00120 return DIR_W + _roadveh_images[spritenum];
00121 }
00122
00123 SpriteID RoadVehicle::GetImage(Direction direction) const
00124 {
00125 uint8 spritenum = this->spritenum;
00126 SpriteID sprite;
00127
00128 if (is_custom_sprite(spritenum)) {
00129 sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
00130 if (sprite != 0) return sprite;
00131
00132 spritenum = Engine::Get(this->engine_type)->original_image_index;
00133 }
00134
00135 sprite = direction + _roadveh_images[spritenum];
00136
00137 if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
00138
00139 return sprite;
00140 }
00141
00151 void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal)
00152 {
00153 SpriteID sprite = GetRoadVehIcon(engine);
00154 const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
00155 preferred_x = Clamp(preferred_x, left - real_sprite->x_offs, right - real_sprite->width - real_sprite->x_offs);
00156 DrawSprite(sprite, pal, preferred_x, y);
00157 }
00158
00164 static uint GetRoadVehLength(const RoadVehicle *v)
00165 {
00166 uint length = VEHICLE_LENGTH;
00167
00168 uint16 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
00169 if (veh_len != CALLBACK_FAILED) {
00170 length -= Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
00171 }
00172
00173 return length;
00174 }
00175
00181 void RoadVehUpdateCache(RoadVehicle *v)
00182 {
00183 assert(v->type == VEH_ROAD);
00184 assert(v->IsFrontEngine());
00185
00186 v->InvalidateNewGRFCacheOfChain();
00187
00188 v->gcache.cached_total_length = 0;
00189
00190 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00191
00192 assert(u->First() == v);
00193
00194
00195 u->gcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
00196
00197
00198 u->gcache.cached_veh_length = GetRoadVehLength(u);
00199 v->gcache.cached_total_length += u->gcache.cached_veh_length;
00200
00201
00202 v->UpdateVisualEffect();
00203
00204
00205 u->colourmap = PAL_NONE;
00206 }
00207
00208 uint max_speed = GetVehicleProperty(v, PROP_ROADVEH_SPEED, 0);
00209 v->vcache.cached_max_speed = (max_speed != 0) ? max_speed * 4 : RoadVehInfo(v->engine_type)->max_speed;
00210 }
00211
00221 CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engine *e, uint16 data, Vehicle **ret)
00222 {
00223 if (!IsEngineBuildable(e->index, VEH_ROAD, _current_company)) return_cmd_error(STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE);
00224
00225
00226 if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
00227
00228 CommandCost cost(EXPENSES_NEW_VEHICLES, e->GetCost());
00229 if (flags & DC_QUERY_COST) return cost;
00230
00231
00232
00233 if (!IsRoadDepotTile(tile)) return CMD_ERROR;
00234 if (!IsInfraUsageAllowed(VEH_ROAD, _current_company, GetTileOwner(tile))) return CMD_ERROR;
00235
00236 if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
00237
00238 if (flags & DC_EXEC) {
00239 const RoadVehicleInfo *rvi = &e->u.road;
00240
00241 RoadVehicle *v = new RoadVehicle();
00242 *ret = v;
00243 v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
00244 v->owner = _current_company;
00245
00246 v->tile = tile;
00247 int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
00248 int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
00249 v->x_pos = x;
00250 v->y_pos = y;
00251 v->z_pos = GetSlopeZ(x, y);
00252
00253 v->state = RVSB_IN_DEPOT;
00254 v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00255
00256 v->spritenum = rvi->image_index;
00257 v->cargo_type = e->GetDefaultCargoType();
00258 v->cargo_cap = rvi->capacity;
00259
00260 v->last_station_visited = INVALID_STATION;
00261 v->last_loading_station = INVALID_STATION;
00262
00263 v->engine_type = e->index;
00264 v->gcache.first_engine = INVALID_ENGINE;
00265
00266 v->reliability = e->reliability;
00267 v->reliability_spd_dec = e->reliability_spd_dec;
00268 v->breakdown_chance = 128;
00269 v->max_age = e->GetLifeLengthInDays();
00270 _new_vehicle_id = v->index;
00271
00272 v->service_interval = Company::Get(v->owner)->settings.vehicle.servint_roadveh;
00273
00274 v->date_of_last_service = _date;
00275 v->build_year = _cur_year;
00276
00277 v->cur_image = SPR_IMG_QUERY;
00278 v->random_bits = VehicleRandomBits();
00279 v->SetFrontEngine();
00280
00281 v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
00282 v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
00283 v->gcache.cached_veh_length = VEHICLE_LENGTH;
00284
00285 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00286
00287 AddArticulatedParts(v);
00288 v->InvalidateNewGRFCacheOfChain();
00289
00290
00291 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00292 u->cargo_cap = GetVehicleCapacity(u);
00293 v->InvalidateNewGRFCache();
00294 u->InvalidateNewGRFCache();
00295 }
00296 RoadVehUpdateCache(v);
00297
00298 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) v->CargoChanged();
00299
00300 VehicleMove(v, false);
00301
00302 CheckConsistencyOfArticulatedVehicle(v);
00303 }
00304
00305 return CommandCost();
00306 }
00307
00308 bool RoadVehicle::IsStoppedInDepot() const
00309 {
00310 TileIndex tile = this->tile;
00311
00312 if (!IsRoadDepotTile(tile)) return false;
00313 if (this->IsFrontEngine() && !(this->vehstatus & VS_STOPPED)) return false;
00314
00315 for (const RoadVehicle *v = this; v != NULL; v = v->Next()) {
00316 if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false;
00317 }
00318 return true;
00319 }
00320
00321 static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
00322 {
00323 if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
00324
00325 switch (_settings_game.pf.pathfinder_for_roadvehs) {
00326 case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, max_distance);
00327 case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, max_distance);
00328
00329 default: NOT_REACHED();
00330 }
00331 }
00332
00333 bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
00334 {
00335 FindDepotData rfdd = FindClosestRoadDepot(this, 0);
00336 if (rfdd.best_length == UINT_MAX) return false;
00337
00338 if (location != NULL) *location = rfdd.tile;
00339 if (destination != NULL) *destination = GetDepotIndex(rfdd.tile);
00340
00341 return true;
00342 }
00343
00353 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00354 {
00355 RoadVehicle *v = RoadVehicle::GetIfValid(p1);
00356 if (v == NULL) return CMD_ERROR;
00357
00358 CommandCost ret = CheckVehicleControlAllowed(v);
00359 if (ret.Failed()) return ret;
00360
00361 if ((v->vehstatus & VS_STOPPED) ||
00362 (v->vehstatus & VS_CRASHED) ||
00363 v->overtaking != 0 ||
00364 v->state == RVSB_WORMHOLE ||
00365 v->IsInDepot() ||
00366 v->current_order.IsType(OT_LOADING)) {
00367 return CMD_ERROR;
00368 }
00369
00370 if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
00371
00372 if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
00373
00374 if (flags & DC_EXEC) v->reverse_ctr = 180;
00375
00376 return CommandCost();
00377 }
00378
00379
00380 void RoadVehicle::MarkDirty()
00381 {
00382 for (RoadVehicle *v = this; v != NULL; v = v->Next()) {
00383 v->UpdateViewport(false, false);
00384 }
00385 this->CargoChanged();
00386 }
00387
00388 void RoadVehicle::UpdateDeltaXY(Direction direction)
00389 {
00390 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
00391 static const uint32 _delta_xy_table[8] = {
00392 MKIT(3, 3, -1, -1),
00393 MKIT(3, 7, -1, -3),
00394 MKIT(3, 3, -1, -1),
00395 MKIT(7, 3, -3, -1),
00396 MKIT(3, 3, -1, -1),
00397 MKIT(3, 7, -1, -3),
00398 MKIT(3, 3, -1, -1),
00399 MKIT(7, 3, -3, -1),
00400 };
00401 #undef MKIT
00402
00403 uint32 x = _delta_xy_table[direction];
00404 this->x_offs = GB(x, 0, 8);
00405 this->y_offs = GB(x, 8, 8);
00406 this->x_extent = GB(x, 16, 8);
00407 this->y_extent = GB(x, 24, 8);
00408 this->z_extent = 6;
00409 }
00410
00415 FORCEINLINE int RoadVehicle::GetCurrentMaxSpeed() const
00416 {
00417 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) return this->vcache.cached_max_speed;
00418
00419 int max_speed = this->vcache.cached_max_speed;
00420
00421
00422 for (const RoadVehicle *u = this; u != NULL; u = u->Next()) {
00423 if (this->state <= RVSB_TRACKDIR_MASK && IsReversingRoadTrackdir((Trackdir)this->state)) {
00424 max_speed = this->vcache.cached_max_speed / 2;
00425 break;
00426 } else if ((u->direction & 1) == 0) {
00427 max_speed = this->vcache.cached_max_speed * 3 / 4;
00428 }
00429 }
00430
00431 return max_speed;
00432 }
00433
00438 static void DeleteLastRoadVeh(RoadVehicle *v)
00439 {
00440 Vehicle *u = v;
00441 for (; v->Next() != NULL; v = v->Next()) u = v;
00442 u->SetNext(NULL);
00443
00444
00445 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00446
00447 delete v;
00448 }
00449
00450 static void RoadVehSetRandomDirection(RoadVehicle *v)
00451 {
00452 static const DirDiff delta[] = {
00453 DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
00454 };
00455
00456 do {
00457 uint32 r = Random();
00458
00459 v->direction = ChangeDir(v->direction, delta[r & 3]);
00460 v->UpdateViewport(true, true);
00461 } while ((v = v->Next()) != NULL);
00462 }
00463
00469 static bool RoadVehIsCrashed(RoadVehicle *v)
00470 {
00471 v->crashed_ctr++;
00472 if (v->crashed_ctr == 2) {
00473 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00474 } else if (v->crashed_ctr <= 45) {
00475 if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
00476 } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
00477 bool ret = v->Next() != NULL;
00478 DeleteLastRoadVeh(v);
00479 return ret;
00480 }
00481
00482 return true;
00483 }
00484
00491 static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
00492 {
00493 const Vehicle *u = (Vehicle*)data;
00494
00495 return (v->type == VEH_TRAIN &&
00496 abs(v->z_pos - u->z_pos) <= 6 &&
00497 abs(v->x_pos - u->x_pos) <= 4 &&
00498 abs(v->y_pos - u->y_pos) <= 4) ? v : NULL;
00499 }
00500
00501 uint RoadVehicle::Crash(bool flooded)
00502 {
00503 uint pass = this->GroundVehicleBase::Crash(flooded);
00504 if (this->IsFrontEngine()) {
00505 pass += 1;
00506
00507
00508 if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00509 RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
00510 }
00511 }
00512 this->crashed_ctr = flooded ? 2000 : 1;
00513 return pass;
00514 }
00515
00516 static void RoadVehCrash(RoadVehicle *v)
00517 {
00518 uint pass = v->Crash();
00519
00520 AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
00521
00522 SetDParam(0, pass);
00523 AddVehicleNewsItem(
00524 (pass == 1) ?
00525 STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
00526 NS_ACCIDENT,
00527 v->index
00528 );
00529
00530 ModifyStationRatingAround(v->tile, v->owner, -160, 22);
00531 SndPlayVehicleFx(SND_12_EXPLOSION, v);
00532 }
00533
00534 static bool RoadVehCheckTrainCrash(RoadVehicle *v)
00535 {
00536 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00537 if (u->state == RVSB_WORMHOLE) continue;
00538
00539 TileIndex tile = u->tile;
00540
00541 if (!IsLevelCrossingTile(tile)) continue;
00542
00543 if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
00544 RoadVehCrash(v);
00545 return true;
00546 }
00547 }
00548
00549 return false;
00550 }
00551
00552 TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
00553 {
00554 if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
00555
00556 const Station *st = Station::Get(station);
00557 if (!CanVehicleUseStation(this, st)) {
00558
00559 this->IncrementRealOrderIndex();
00560 return 0;
00561 }
00562
00563 return st->xy;
00564 }
00565
00566 static void StartRoadVehSound(const RoadVehicle *v)
00567 {
00568 if (!PlayVehicleSound(v, VSE_START)) {
00569 SoundID s = RoadVehInfo(v->engine_type)->sfx;
00570 if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0) {
00571 s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
00572 }
00573 SndPlayVehicleFx(s, v);
00574 }
00575 }
00576
00577 struct RoadVehFindData {
00578 int x;
00579 int y;
00580 const Vehicle *veh;
00581 Vehicle *best;
00582 uint best_diff;
00583 Direction dir;
00584 };
00585
00586 static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
00587 {
00588 static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
00589 static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
00590
00591 RoadVehFindData *rvf = (RoadVehFindData*)data;
00592
00593 short x_diff = v->x_pos - rvf->x;
00594 short y_diff = v->y_pos - rvf->y;
00595
00596 if (v->type == VEH_ROAD &&
00597 !v->IsInDepot() &&
00598 abs(v->z_pos - rvf->veh->z_pos) < 6 &&
00599 v->direction == rvf->dir &&
00600 rvf->veh->First() != v->First() &&
00601 (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
00602 (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
00603 (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
00604 (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
00605 uint diff = abs(x_diff) + abs(y_diff);
00606
00607 if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
00608 rvf->best = v;
00609 rvf->best_diff = diff;
00610 }
00611 }
00612
00613 return NULL;
00614 }
00615
00616 static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
00617 {
00618 RoadVehFindData rvf;
00619 RoadVehicle *front = v->First();
00620
00621 if (front->reverse_ctr != 0) return NULL;
00622
00623 rvf.x = x;
00624 rvf.y = y;
00625 rvf.dir = dir;
00626 rvf.veh = v;
00627 rvf.best_diff = UINT_MAX;
00628
00629 if (front->state == RVSB_WORMHOLE) {
00630 FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
00631 FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
00632 } else {
00633 FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
00634 }
00635
00636
00637
00638
00639
00640 if (rvf.best_diff == UINT_MAX) {
00641 front->blocked_ctr = 0;
00642 return NULL;
00643 }
00644
00645 if (update_blocked_ctr && ++front->blocked_ctr > 1480) return NULL;
00646
00647 return RoadVehicle::From(rvf.best);
00648 }
00649
00655 static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
00656 {
00657 if (v->IsBus()) {
00658
00659 if (!(st->had_vehicle_of_type & HVOT_BUS)) {
00660 st->had_vehicle_of_type |= HVOT_BUS;
00661 SetDParam(0, st->index);
00662 AddVehicleNewsItem(
00663 v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
00664 (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00665 v->index,
00666 st->index
00667 );
00668 AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00669 }
00670 } else {
00671
00672 if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
00673 st->had_vehicle_of_type |= HVOT_TRUCK;
00674 SetDParam(0, st->index);
00675 AddVehicleNewsItem(
00676 v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
00677 (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00678 v->index,
00679 st->index
00680 );
00681 AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00682 }
00683 }
00684 }
00685
00693 int RoadVehicle::UpdateSpeed()
00694 {
00695 switch (_settings_game.vehicle.roadveh_acceleration_model) {
00696 default: NOT_REACHED();
00697 case AM_ORIGINAL:
00698 return this->DoUpdateSpeed(this->overtaking != 0 ? 512 : 256, 0, this->GetCurrentMaxSpeed());
00699
00700 case AM_REALISTIC:
00701 return this->DoUpdateSpeed(this->GetAcceleration() + (this->overtaking != 0 ? 256 : 0), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 4, this->GetCurrentMaxSpeed());
00702 }
00703 }
00704
00705 static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
00706 {
00707 static const Direction _roadveh_new_dir[] = {
00708 DIR_N , DIR_NW, DIR_W , INVALID_DIR,
00709 DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
00710 DIR_E , DIR_SE, DIR_S
00711 };
00712
00713 x = x - v->x_pos + 1;
00714 y = y - v->y_pos + 1;
00715
00716 if ((uint)x > 2 || (uint)y > 2) return v->direction;
00717 return _roadveh_new_dir[y * 4 + x];
00718 }
00719
00720 static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y)
00721 {
00722 Direction new_dir = RoadVehGetNewDirection(v, x, y);
00723 Direction old_dir = v->direction;
00724 DirDiff delta;
00725
00726 if (new_dir == old_dir) return old_dir;
00727 delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
00728 return ChangeDir(old_dir, delta);
00729 }
00730
00731 struct OvertakeData {
00732 const RoadVehicle *u;
00733 const RoadVehicle *v;
00734 TileIndex tile;
00735 Trackdir trackdir;
00736 };
00737
00738 static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
00739 {
00740 const OvertakeData *od = (OvertakeData*)data;
00741
00742 return (v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v) ? v : NULL;
00743 }
00744
00751 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
00752 {
00753 TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes);
00754 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
00755 TrackdirBits red_signals = TrackStatusToRedSignals(ts);
00756 TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00757
00758
00759 if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00760
00761
00762 return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
00763 }
00764
00765 static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
00766 {
00767 OvertakeData od;
00768
00769 od.v = v;
00770 od.u = u;
00771
00772 if (u->vcache.cached_max_speed >= v->vcache.cached_max_speed &&
00773 !(u->vehstatus & VS_STOPPED) &&
00774 u->cur_speed != 0) {
00775 return;
00776 }
00777
00778
00779 if (v->roadtype == ROADTYPE_TRAM) return;
00780
00781
00782 if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
00783
00784
00785 if (v->HasArticulatedPart()) return;
00786
00787
00788 if (v->breakdown_ctr != 0) return;
00789
00790
00791 if (v->direction != u->direction || !(v->direction & 1)) return;
00792
00793
00794 if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return;
00795
00796 od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
00797
00798
00799
00800
00801
00802
00803
00804 od.tile = v->tile;
00805 if (CheckRoadBlockedForOvertaking(&od)) return;
00806
00807 od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
00808 if (CheckRoadBlockedForOvertaking(&od)) return;
00809
00810
00811
00812 v->overtaking_ctr = (od.u->cur_speed == 0 || (od.u->vehstatus & VS_STOPPED)) ? RV_OVERTAKE_TIMEOUT / 2 : 0;
00813 v->overtaking = RVSB_DRIVE_SIDE;
00814 }
00815
00816 static void RoadZPosAffectSpeed(RoadVehicle *v, int32 old_z)
00817 {
00818 if (old_z == v->z_pos || _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) return;
00819
00820 if (old_z < v->z_pos) {
00821 v->cur_speed = v->cur_speed * 232 / 256;
00822 } else {
00823 uint16 spd = v->cur_speed + 2;
00824 if (spd <= v->vcache.cached_max_speed) v->cur_speed = spd;
00825 }
00826 }
00827
00828 static int PickRandomBit(uint bits)
00829 {
00830 uint i;
00831 uint num = RandomRange(CountBits(bits));
00832
00833 for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
00834 return i;
00835 }
00836
00845 static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
00846 {
00847 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
00848
00849 TileIndex desttile;
00850 Trackdir best_track;
00851 bool path_found = true;
00852
00853 TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes);
00854 TrackdirBits red_signals = TrackStatusToRedSignals(ts);
00855 TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
00856
00857 if (IsTileType(tile, MP_ROAD)) {
00858 if (IsRoadDepot(tile) && (!IsInfraTileUsageAllowed(VEH_ROAD, v->owner, tile) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
00859
00860 trackdirs = TRACKDIR_BIT_NONE;
00861 }
00862 } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
00863
00864
00865 if (!IsInfraTileUsageAllowed(VEH_ROAD, v->owner, tile) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
00866
00867 trackdirs = TRACKDIR_BIT_NONE;
00868 } else {
00869
00870 RoadStopType rstype = v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK;
00871
00872 if (GetRoadStopType(tile) != rstype) {
00873
00874 trackdirs = TRACKDIR_BIT_NONE;
00875 } else {
00876
00877 if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) &&
00878 !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) {
00879
00880 trackdirs = TRACKDIR_BIT_NONE;
00881 }
00882 }
00883 }
00884 }
00885
00886
00887
00888
00889
00890
00891 trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
00892 if (trackdirs == TRACKDIR_BIT_NONE) {
00893
00894 return_track(_road_reverse_table[enterdir]);
00895 }
00896
00897 if (v->reverse_ctr != 0) {
00898 bool reverse = true;
00899 if (v->roadtype == ROADTYPE_TRAM) {
00900
00901
00902 RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM);
00903 RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
00904 reverse = ((rb & straight) == straight) ||
00905 (rb == DiagDirToRoadBits(enterdir));
00906 }
00907 if (reverse) {
00908 v->reverse_ctr = 0;
00909 if (v->tile != tile) {
00910 return_track(_road_reverse_table[enterdir]);
00911 }
00912 }
00913 }
00914
00915 desttile = v->dest_tile;
00916 if (desttile == 0) {
00917
00918 return_track(PickRandomBit(trackdirs));
00919 }
00920
00921
00922 if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) {
00923 return_track(FindFirstBit2x64(trackdirs));
00924 }
00925
00926 switch (_settings_game.pf.pathfinder_for_roadvehs) {
00927 case VPF_NPF: best_track = NPFRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break;
00928 case VPF_YAPF: best_track = YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs, path_found); break;
00929
00930 default: NOT_REACHED();
00931 }
00932 v->HandlePathfindingResult(path_found);
00933
00934 found_best_track:;
00935
00936 if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR;
00937
00938 return best_track;
00939 }
00940
00941 struct RoadDriveEntry {
00942 byte x, y;
00943 };
00944
00945 #include "table/roadveh_movement.h"
00946
00947 static bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
00948 {
00949
00950 for (const RoadVehicle *u = v; u != NULL; u = u->Next()) {
00951 if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
00952 }
00953
00954 DiagDirection dir = GetRoadDepotDirection(v->tile);
00955 v->direction = DiagDirToDir(dir);
00956
00957 Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
00958 const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
00959
00960 int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
00961 int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
00962
00963 if (first) {
00964
00965 if (v->current_order.IsType(OT_GOTO_DEPOT) && v->tile == v->dest_tile) {
00966 VehicleEnterDepot(v);
00967 return true;
00968 }
00969
00970 if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
00971
00972 VehicleServiceInDepot(v);
00973
00974 StartRoadVehSound(v);
00975
00976
00977 v->cur_speed = 0;
00978 }
00979
00980 v->vehstatus &= ~VS_HIDDEN;
00981 v->state = tdir;
00982 v->frame = RVC_DEPOT_START_FRAME;
00983
00984 v->x_pos = x;
00985 v->y_pos = y;
00986 v->UpdateInclination(true, true);
00987
00988 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00989
00990 return true;
00991 }
00992
00993 static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
00994 {
00995 if (prev->tile == v->tile && !already_reversed) {
00996
00997
00998 return _road_reverse_table[entry_dir];
00999 }
01000
01001 byte prev_state = prev->state;
01002 Trackdir dir;
01003
01004 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
01005 DiagDirection diag_dir = INVALID_DIAGDIR;
01006
01007 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01008 diag_dir = GetTunnelBridgeDirection(tile);
01009 } else if (IsRoadDepotTile(tile)) {
01010 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
01011 }
01012
01013 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
01014 dir = DiagDirToDiagTrackdir(diag_dir);
01015 } else {
01016 if (already_reversed && prev->tile != tile) {
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032 static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01033 { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E },
01034 { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }};
01035 dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01036 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01037 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01038 } else if (prev_state < TRACKDIR_END) {
01039 dir = (Trackdir)prev_state;
01040 } else {
01041 return INVALID_TRACKDIR;
01042 }
01043 }
01044
01045
01046 static const RoadBits required_roadbits[] = {
01047 ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01048 ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X, ROAD_Y
01049 };
01050 RoadBits required = required_roadbits[dir & 0x07];
01051
01052 if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
01053 dir = INVALID_TRACKDIR;
01054 }
01055
01056 return dir;
01057 }
01058
01066 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01067 {
01068
01069 Backup<CompanyByte> cur_company(_current_company, c, FILE_LINE);
01070
01071 CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01072
01073 cur_company.Restore();
01074 return ret.Succeeded();
01075 }
01076
01077 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
01078 {
01079 if (v->overtaking != 0) {
01080 if (IsTileType(v->tile, MP_STATION)) {
01081
01082 v->overtaking = 0;
01083 } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
01084
01085
01086
01087 if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01088 v->overtaking = 0;
01089 }
01090 }
01091 }
01092
01093
01094
01095
01096 if (v->IsInDepot()) return true;
01097
01098 if (v->state == RVSB_WORMHOLE) {
01099
01100 GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01101
01102
01103 if (!(v->vehstatus & VS_HIDDEN)) {
01104 RoadVehicle *first = v->First();
01105 first->cur_speed = min(first->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
01106 }
01107
01108 if (v->IsFrontEngine()) {
01109 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01110 if (u != NULL) {
01111 v->cur_speed = u->First()->cur_speed;
01112 return false;
01113 }
01114 }
01115
01116 if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01117
01118 v->x_pos = gp.x;
01119 v->y_pos = gp.y;
01120 v->UpdateInclination(true, true);
01121 return true;
01122 }
01123
01124 v->x_pos = gp.x;
01125 v->y_pos = gp.y;
01126 VehicleMove(v, v->IsDrawn());
01127 return true;
01128 }
01129
01130
01131
01132
01133 RoadDriveEntry rd = _road_drive_data[v->roadtype][(
01134 (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
01135 (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
01136
01137 if (rd.x & RDE_NEXT_TILE) {
01138 TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01139 Trackdir dir;
01140
01141 if (v->IsFrontEngine()) {
01142
01143 dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01144 } else {
01145 dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01146 }
01147
01148 if (dir == INVALID_TRACKDIR) {
01149 if (!v->IsFrontEngine()) error("Disconnecting road vehicle.");
01150 v->cur_speed = 0;
01151 return false;
01152 }
01153
01154 again:
01155 uint start_frame = RVC_DEFAULT_START_FRAME;
01156 if (IsReversingRoadTrackdir(dir)) {
01157
01158 v->overtaking = 0;
01159
01160
01161 if (v->roadtype == ROADTYPE_TRAM) {
01162
01163
01164 RoadBits needed;
01165 switch (dir) {
01166 default: NOT_REACHED();
01167 case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01168 case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01169 case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01170 case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01171 }
01172 if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01173 (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01174 (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185 } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197 tile = v->tile;
01198 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01199 } else {
01200
01201 v->cur_speed = 0;
01202 return false;
01203 }
01204 } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01205 v->cur_speed = 0;
01206 return false;
01207 } else {
01208 tile = v->tile;
01209 }
01210 }
01211
01212
01213 const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
01214
01215 int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01216 int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01217
01218 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01219 if (v->IsFrontEngine()) {
01220 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01221 if (u != NULL) {
01222 v->cur_speed = u->First()->cur_speed;
01223 return false;
01224 }
01225 }
01226
01227 uint32 r = VehicleEnterTile(v, tile, x, y);
01228 if (HasBit(r, VETS_CANNOT_ENTER)) {
01229 if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01230 v->cur_speed = 0;
01231 return false;
01232 }
01233
01234 dir = _road_reverse_table[rd.x & 3];
01235 goto again;
01236 }
01237
01238 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01239 if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01240
01241
01242 v->cur_speed = 0;
01243 return false;
01244 }
01245
01246
01247
01248
01249
01250
01251
01252
01253 if (IsDriveThroughStopTile(v->tile) &&
01254 RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01255 v->tile != tile) {
01256
01257 dir = (Trackdir)v->state;
01258 } else if (IsRoadStop(v->tile)) {
01259
01260 RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
01261 }
01262 }
01263
01264 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01265 v->tile = tile;
01266 v->state = (byte)dir;
01267 v->frame = start_frame;
01268 }
01269 if (new_dir != v->direction) {
01270 v->direction = new_dir;
01271 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01272 }
01273 v->x_pos = x;
01274 v->y_pos = y;
01275 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01276 return true;
01277 }
01278
01279 if (rd.x & RDE_TURNED) {
01280
01281 Trackdir dir;
01282 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01283
01284 if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) {
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01295 switch (rd.x & 0x3) {
01296 default: NOT_REACHED();
01297 case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01298 case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01299 case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01300 case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01301 }
01302 } else {
01303 if (v->IsFrontEngine()) {
01304
01305 dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01306 } else {
01307 dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01308 }
01309 }
01310
01311 if (dir == INVALID_TRACKDIR) {
01312 v->cur_speed = 0;
01313 return false;
01314 }
01315
01316 const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01317
01318 int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01319 int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01320
01321 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01322 if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01323
01324 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01325 if (HasBit(r, VETS_CANNOT_ENTER)) {
01326 v->cur_speed = 0;
01327 return false;
01328 }
01329
01330 v->state = dir;
01331 v->frame = turn_around_start_frame;
01332
01333 if (new_dir != v->direction) {
01334 v->direction = new_dir;
01335 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01336 }
01337
01338 v->x_pos = x;
01339 v->y_pos = y;
01340 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01341 return true;
01342 }
01343
01344
01345
01346
01347 if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01348 if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
01349 RoadVehLeaveDepot(v->Next(), false);
01350 }
01351 }
01352
01353
01354 int x = (v->x_pos & ~15) + (rd.x & 15);
01355 int y = (v->y_pos & ~15) + (rd.y & 15);
01356
01357 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01358
01359 if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01360
01361
01362 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01363
01364 if (u != NULL) {
01365 u = u->First();
01366
01367 if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01368 if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01369
01370
01371 if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01372 v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01373 IsInfraTileUsageAllowed(VEH_ROAD, v->owner, v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
01374 GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
01375 Station *st = Station::GetByTile(v->tile);
01376 v->last_station_visited = st->index;
01377 RoadVehArrivesAt(v, st);
01378 v->BeginLoading();
01379 }
01380 return false;
01381 }
01382 }
01383
01384 Direction old_dir = v->direction;
01385 if (new_dir != old_dir) {
01386 v->direction = new_dir;
01387 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01388 if (old_dir != v->state) {
01389
01390 v->UpdateInclination(false, true);
01391
01392
01393
01394 return true;
01395 }
01396 }
01397
01398
01399
01400
01401
01402
01403 if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01404 _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
01405 (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01406 v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01407 IsInfraTileUsageAllowed(VEH_ROAD, v->owner, v->tile) &&
01408 GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01409 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01410
01411 RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
01412 Station *st = Station::GetByTile(v->tile);
01413
01414
01415
01416
01417 if (!HasBit(v->state, RVS_ENTERED_STOP)) {
01418
01419
01420 if (IsDriveThroughStopTile(v->tile)) {
01421 TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01422
01423
01424 if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
01425 v->frame++;
01426 v->x_pos = x;
01427 v->y_pos = y;
01428 RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
01429 return true;
01430 }
01431 }
01432
01433 rs->SetEntranceBusy(false);
01434 SetBit(v->state, RVS_ENTERED_STOP);
01435
01436 v->last_station_visited = st->index;
01437
01438 if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01439 RoadVehArrivesAt(v, st);
01440 v->BeginLoading();
01441 return false;
01442 }
01443 } else {
01444
01445 if (rs->IsEntranceBusy()) {
01446
01447 v->cur_speed = 0;
01448 return false;
01449 }
01450 if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
01451 }
01452
01453 if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01454
01455 StartRoadVehSound(v);
01456 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01457 }
01458
01459
01460
01461 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01462 if (HasBit(r, VETS_CANNOT_ENTER)) {
01463 v->cur_speed = 0;
01464 return false;
01465 }
01466
01467 if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01468 v->current_order.Free();
01469 }
01470
01471
01472
01473 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
01474 v->x_pos = x;
01475 v->y_pos = y;
01476 RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
01477 return true;
01478 }
01479
01480 static bool RoadVehController(RoadVehicle *v)
01481 {
01482
01483 v->tick_counter++;
01484 v->current_order_time++;
01485 if (v->reverse_ctr != 0) v->reverse_ctr--;
01486
01487
01488 if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01489 return RoadVehIsCrashed(v);
01490 }
01491
01492
01493 if (v->HandleBreakdown()) return true;
01494 if (v->vehstatus & VS_STOPPED) return true;
01495
01496 ProcessOrders(v);
01497 v->HandleLoading();
01498
01499 if (v->current_order.IsType(OT_LOADING)) return true;
01500
01501 if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01502
01503 v->ShowVisualEffect();
01504
01505
01506 int j = v->UpdateSpeed();
01507
01508 int adv_spd = v->GetAdvanceDistance();
01509 bool blocked = false;
01510 while (j >= adv_spd) {
01511 j -= adv_spd;
01512
01513 RoadVehicle *u = v;
01514 for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01515 if (!IndividualRoadVehicleController(u, prev)) {
01516 blocked = true;
01517 break;
01518 }
01519 }
01520 if (blocked) break;
01521
01522
01523 adv_spd = v->GetAdvanceDistance();
01524
01525
01526 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01527 }
01528
01529 v->SetLastSpeed();
01530
01531 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01532 if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01533
01534 u->UpdateViewport(false, false);
01535 }
01536
01537
01538
01539
01540 if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01541
01542 return true;
01543 }
01544
01545 Money RoadVehicle::GetRunningCost() const
01546 {
01547 const Engine *e = Engine::Get(this->engine_type);
01548 if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01549
01550 uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01551 if (cost_factor == 0) return 0;
01552
01553 return GetPrice(e->u.road.running_cost_class, cost_factor, e->grf_prop.grffile);
01554 }
01555
01556 bool RoadVehicle::Tick()
01557 {
01558 if (this->IsFrontEngine()) {
01559 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01560 return RoadVehController(this);
01561 }
01562
01563 return true;
01564 }
01565
01566 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01567 {
01568
01569 if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01570 if (v->IsInDepot()) {
01571 VehicleServiceInDepot(v);
01572 return;
01573 }
01574
01575 uint max_penalty;
01576 switch (_settings_game.pf.pathfinder_for_roadvehs) {
01577 case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break;
01578 case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01579 default: NOT_REACHED();
01580 }
01581
01582 FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01583
01584 if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01585 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01586
01587
01588
01589 v->current_order.MakeDummy();
01590 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01591 }
01592 return;
01593 }
01594
01595 DepotID depot = GetDepotIndex(rfdd.tile);
01596
01597 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01598 v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01599 !Chance16(1, 20)) {
01600 return;
01601 }
01602
01603 SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01604 v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01605 v->dest_tile = rfdd.tile;
01606 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01607 }
01608
01609 void RoadVehicle::OnNewDay()
01610 {
01611 if (!this->IsFrontEngine()) return;
01612
01613 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01614 if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01615
01616 AgeVehicle(this);
01617 CheckIfRoadVehNeedsService(this);
01618
01619 CheckOrders(this);
01620
01621 if (this->running_ticks == 0) return;
01622
01623 CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01624
01625 this->profit_this_year -= cost.GetCost();
01626 this->running_ticks = 0;
01627
01628 SubtractMoneyFromCompanyFract(this->owner, cost);
01629
01630 SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01631 SetWindowClassesDirty(WC_ROADVEH_LIST);
01632 }
01633
01634 Trackdir RoadVehicle::GetVehicleTrackdir() const
01635 {
01636 if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01637
01638 if (this->IsInDepot()) {
01639
01640 return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01641 }
01642
01643 if (IsStandardRoadStopTile(this->tile)) {
01644
01645 return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile));
01646 }
01647
01648
01649 if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01650
01651
01652
01653 return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01654 }