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