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