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