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