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