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