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