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