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