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, 14, -1, -3),
00377 MKIT(3, 3, -1, -1),
00378 MKIT(7, 3, -3, -1),
00379 MKIT(3, 3, -1, -1),
00380 MKIT(3, 14, -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 if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
00945
00946 VehicleServiceInDepot(v);
00947
00948 StartRoadVehSound(v);
00949
00950
00951 v->cur_speed = 0;
00952 }
00953
00954 v->vehstatus &= ~VS_HIDDEN;
00955 v->state = tdir;
00956 v->frame = RVC_DEPOT_START_FRAME;
00957
00958 v->x_pos = x;
00959 v->y_pos = y;
00960 v->UpdateInclination(true, true);
00961
00962 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00963
00964 return true;
00965 }
00966
00967 static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
00968 {
00969 if (prev->tile == v->tile && !already_reversed) {
00970
00971
00972 return _road_reverse_table[entry_dir];
00973 }
00974
00975 byte prev_state = prev->state;
00976 Trackdir dir;
00977
00978 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
00979 DiagDirection diag_dir = INVALID_DIAGDIR;
00980
00981 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00982 diag_dir = GetTunnelBridgeDirection(tile);
00983 } else if (IsRoadDepotTile(tile)) {
00984 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
00985 }
00986
00987 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
00988 dir = DiagDirToDiagTrackdir(diag_dir);
00989 } else {
00990 if (already_reversed && prev->tile != tile) {
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006 static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01007 { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E },
01008 { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }};
01009 dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01010 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01011 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01012 } else if (prev_state < TRACKDIR_END) {
01013 dir = (Trackdir)prev_state;
01014 } else {
01015 return INVALID_TRACKDIR;
01016 }
01017 }
01018
01019
01020 static const RoadBits required_roadbits[] = {
01021 ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01022 ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X, ROAD_Y
01023 };
01024 RoadBits required = required_roadbits[dir & 0x07];
01025
01026 if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
01027 dir = INVALID_TRACKDIR;
01028 }
01029
01030 return dir;
01031 }
01032
01040 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01041 {
01042
01043 Backup<CompanyByte> cur_company(_current_company, c, FILE_LINE);
01044
01045 CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01046
01047 cur_company.Restore();
01048 return ret.Succeeded();
01049 }
01050
01051 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
01052 {
01053 if (v->overtaking != 0) {
01054 if (IsTileType(v->tile, MP_STATION)) {
01055
01056 v->overtaking = 0;
01057 } else if (++v->overtaking_ctr >= RV_OVERTAKE_TIMEOUT) {
01058
01059
01060
01061 if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01062 v->overtaking = 0;
01063 }
01064 }
01065 }
01066
01067
01068
01069
01070 if (v->IsInDepot()) return true;
01071
01072 if (v->state == RVSB_WORMHOLE) {
01073
01074 GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01075
01076
01077 if (!(v->vehstatus & VS_HIDDEN)) {
01078 RoadVehicle *first = v->First();
01079 first->cur_speed = min(first->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
01080 }
01081
01082 if (v->IsFrontEngine()) {
01083 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01084 if (u != NULL) {
01085 v->cur_speed = u->First()->cur_speed;
01086 return false;
01087 }
01088 }
01089
01090 if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01091
01092 v->x_pos = gp.x;
01093 v->y_pos = gp.y;
01094 v->UpdateInclination(true, true);
01095 return true;
01096 }
01097
01098 v->x_pos = gp.x;
01099 v->y_pos = gp.y;
01100 VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01101 return true;
01102 }
01103
01104
01105
01106
01107 RoadDriveEntry rd = _road_drive_data[v->roadtype][(
01108 (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
01109 (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
01110
01111 if (rd.x & RDE_NEXT_TILE) {
01112 TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01113 Trackdir dir;
01114
01115 if (v->IsFrontEngine()) {
01116
01117 dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01118 } else {
01119 dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01120 }
01121
01122 if (dir == INVALID_TRACKDIR) {
01123 if (!v->IsFrontEngine()) error("Disconnecting road vehicle.");
01124 v->cur_speed = 0;
01125 return false;
01126 }
01127
01128 again:
01129 uint start_frame = RVC_DEFAULT_START_FRAME;
01130 if (IsReversingRoadTrackdir(dir)) {
01131
01132 v->overtaking = 0;
01133
01134
01135 if (v->roadtype == ROADTYPE_TRAM) {
01136
01137
01138 RoadBits needed;
01139 switch (dir) {
01140 default: NOT_REACHED();
01141 case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01142 case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01143 case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01144 case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01145 }
01146 if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01147 (v->IsFrontEngine() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01148 (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159 } else if (!v->IsFrontEngine() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171 tile = v->tile;
01172 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01173 } else {
01174
01175 v->cur_speed = 0;
01176 return false;
01177 }
01178 } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01179 v->cur_speed = 0;
01180 return false;
01181 } else {
01182 tile = v->tile;
01183 }
01184 }
01185
01186
01187 const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
01188
01189 int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01190 int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01191
01192 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01193 if (v->IsFrontEngine()) {
01194 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01195 if (u != NULL) {
01196 v->cur_speed = u->First()->cur_speed;
01197 return false;
01198 }
01199 }
01200
01201 uint32 r = VehicleEnterTile(v, tile, x, y);
01202 if (HasBit(r, VETS_CANNOT_ENTER)) {
01203 if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01204 v->cur_speed = 0;
01205 return false;
01206 }
01207
01208 dir = _road_reverse_table[rd.x & 3];
01209 goto again;
01210 }
01211
01212 if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01213 if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01214
01215
01216 v->cur_speed = 0;
01217 return false;
01218 }
01219
01220
01221
01222
01223
01224
01225
01226
01227 if (IsDriveThroughStopTile(v->tile) &&
01228 RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01229 v->tile != tile) {
01230
01231 dir = (Trackdir)v->state;
01232 } else if (IsRoadStop(v->tile)) {
01233
01234 RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
01235 }
01236 }
01237
01238 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01239 v->tile = tile;
01240 v->state = (byte)dir;
01241 v->frame = start_frame;
01242 }
01243 if (new_dir != v->direction) {
01244 v->direction = new_dir;
01245 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01246 }
01247 v->x_pos = x;
01248 v->y_pos = y;
01249 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01250 return true;
01251 }
01252
01253 if (rd.x & RDE_TURNED) {
01254
01255 Trackdir dir;
01256 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01257
01258 if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) {
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01269 switch (rd.x & 0x3) {
01270 default: NOT_REACHED();
01271 case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01272 case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01273 case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01274 case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01275 }
01276 } else {
01277 if (v->IsFrontEngine()) {
01278
01279 dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01280 } else {
01281 dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01282 }
01283 }
01284
01285 if (dir == INVALID_TRACKDIR) {
01286 v->cur_speed = 0;
01287 return false;
01288 }
01289
01290 const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01291
01292 int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01293 int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01294
01295 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01296 if (v->IsFrontEngine() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01297
01298 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01299 if (HasBit(r, VETS_CANNOT_ENTER)) {
01300 v->cur_speed = 0;
01301 return false;
01302 }
01303
01304 v->state = dir;
01305 v->frame = turn_around_start_frame;
01306
01307 if (new_dir != v->direction) {
01308 v->direction = new_dir;
01309 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01310 }
01311
01312 v->x_pos = x;
01313 v->y_pos = y;
01314 RoadZPosAffectSpeed(v, v->UpdateInclination(true, true));
01315 return true;
01316 }
01317
01318
01319
01320
01321 if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01322 if (v->frame == v->gcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
01323 RoadVehLeaveDepot(v->Next(), false);
01324 }
01325 }
01326
01327
01328 int x = (v->x_pos & ~15) + (rd.x & 15);
01329 int y = (v->y_pos & ~15) + (rd.y & 15);
01330
01331 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01332
01333 if (v->IsFrontEngine() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01334
01335
01336 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01337
01338 if (u != NULL) {
01339 u = u->First();
01340
01341 if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01342 if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01343
01344
01345 if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01346 v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01347 v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
01348 GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
01349 Station *st = Station::GetByTile(v->tile);
01350 v->last_station_visited = st->index;
01351 RoadVehArrivesAt(v, st);
01352 v->BeginLoading();
01353 }
01354 return false;
01355 }
01356 }
01357
01358 Direction old_dir = v->direction;
01359 if (new_dir != old_dir) {
01360 v->direction = new_dir;
01361 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) v->cur_speed -= v->cur_speed >> 2;
01362 if (old_dir != v->state) {
01363
01364 v->UpdateInclination(false, true);
01365
01366
01367
01368 return true;
01369 }
01370 }
01371
01372
01373
01374
01375
01376
01377 if (v->IsFrontEngine() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01378 _road_stop_stop_frame[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
01379 (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01380 v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01381 v->owner == GetTileOwner(v->tile) &&
01382 GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01383 v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01384
01385 RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
01386 Station *st = Station::GetByTile(v->tile);
01387
01388
01389
01390
01391 if (!HasBit(v->state, RVS_ENTERED_STOP)) {
01392
01393
01394 if (IsDriveThroughStopTile(v->tile)) {
01395 TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01396
01397
01398 if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
01399 v->frame++;
01400 v->x_pos = x;
01401 v->y_pos = y;
01402 RoadZPosAffectSpeed(v, v->UpdateInclination(true, false));
01403 return true;
01404 }
01405 }
01406
01407 rs->SetEntranceBusy(false);
01408 SetBit(v->state, RVS_ENTERED_STOP);
01409
01410 v->last_station_visited = st->index;
01411
01412 if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01413 RoadVehArrivesAt(v, st);
01414 v->BeginLoading();
01415 return false;
01416 }
01417 } else {
01418
01419 if (rs->IsEntranceBusy()) {
01420
01421 v->cur_speed = 0;
01422 return false;
01423 }
01424 if (v->current_order.IsType(OT_LEAVESTATION)) v->current_order.Free();
01425 }
01426
01427 if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01428
01429 StartRoadVehSound(v);
01430 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01431 }
01432
01433
01434
01435 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01436 if (HasBit(r, VETS_CANNOT_ENTER)) {
01437 v->cur_speed = 0;
01438 return false;
01439 }
01440
01441 if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01442 v->current_order.Free();
01443 }
01444
01445
01446
01447 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
01448 v->x_pos = x;
01449 v->y_pos = y;
01450 RoadZPosAffectSpeed(v, v->UpdateInclination(false, true));
01451 return true;
01452 }
01453
01454 static bool RoadVehController(RoadVehicle *v)
01455 {
01456
01457 v->tick_counter++;
01458 v->current_order_time++;
01459 if (v->reverse_ctr != 0) v->reverse_ctr--;
01460
01461
01462 if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01463 return RoadVehIsCrashed(v);
01464 }
01465
01466
01467 if (v->HandleBreakdown()) return true;
01468 if (v->vehstatus & VS_STOPPED) return true;
01469
01470 ProcessOrders(v);
01471 v->HandleLoading();
01472
01473 if (v->current_order.IsType(OT_LOADING)) return true;
01474
01475 if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01476
01477 v->ShowVisualEffect();
01478
01479
01480 int j = v->UpdateSpeed();
01481
01482 int adv_spd = v->GetAdvanceDistance();
01483 bool blocked = false;
01484 while (j >= adv_spd) {
01485 j -= adv_spd;
01486
01487 RoadVehicle *u = v;
01488 for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01489 if (!IndividualRoadVehicleController(u, prev)) {
01490 blocked = true;
01491 break;
01492 }
01493 }
01494 if (blocked) break;
01495
01496
01497 adv_spd = v->GetAdvanceDistance();
01498
01499
01500 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01501 }
01502
01503 v->SetLastSpeed();
01504
01505 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01506 if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01507
01508 u->UpdateViewport(false, false);
01509 }
01510
01511
01512
01513
01514 if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01515
01516 return true;
01517 }
01518
01519 Money RoadVehicle::GetRunningCost() const
01520 {
01521 const Engine *e = Engine::Get(this->engine_type);
01522 if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01523
01524 uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01525 if (cost_factor == 0) return 0;
01526
01527 return GetPrice(e->u.road.running_cost_class, cost_factor, e->grf_prop.grffile);
01528 }
01529
01530 bool RoadVehicle::Tick()
01531 {
01532 if (this->IsFrontEngine()) {
01533 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01534 return RoadVehController(this);
01535 }
01536
01537 return true;
01538 }
01539
01540 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01541 {
01542
01543 if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01544 if (v->IsInDepot()) {
01545 VehicleServiceInDepot(v);
01546 return;
01547 }
01548
01549 uint max_penalty;
01550 switch (_settings_game.pf.pathfinder_for_roadvehs) {
01551 case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break;
01552 case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01553 default: NOT_REACHED();
01554 }
01555
01556 FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01557
01558 if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01559 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01560
01561
01562
01563 v->current_order.MakeDummy();
01564 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01565 }
01566 return;
01567 }
01568
01569 DepotID depot = GetDepotIndex(rfdd.tile);
01570
01571 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01572 v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01573 !Chance16(1, 20)) {
01574 return;
01575 }
01576
01577 v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01578 v->dest_tile = rfdd.tile;
01579 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01580 }
01581
01582 void RoadVehicle::OnNewDay()
01583 {
01584 if (!this->IsFrontEngine()) return;
01585
01586 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01587 if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01588
01589 AgeVehicle(this);
01590 CheckIfRoadVehNeedsService(this);
01591
01592 CheckOrders(this);
01593
01594 if (this->running_ticks == 0) return;
01595
01596 CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01597
01598 this->profit_this_year -= cost.GetCost();
01599 this->running_ticks = 0;
01600
01601 SubtractMoneyFromCompanyFract(this->owner, cost);
01602
01603 SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01604 SetWindowClassesDirty(WC_ROADVEH_LIST);
01605 }
01606
01607 Trackdir RoadVehicle::GetVehicleTrackdir() const
01608 {
01609 if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01610
01611 if (this->IsInDepot()) {
01612
01613 return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01614 }
01615
01616 if (IsStandardRoadStopTile(this->tile)) {
01617
01618 return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile));
01619 }
01620
01621
01622 if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01623
01624
01625
01626 return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01627 }