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->current_order_time++;
01508 if (v->reverse_ctr != 0) v->reverse_ctr--;
01509
01510
01511 if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01512 return RoadVehIsCrashed(v);
01513 }
01514
01515
01516 if (v->HandleBreakdown()) return true;
01517 if (v->vehstatus & VS_STOPPED) return true;
01518
01519 ProcessOrders(v);
01520 v->HandleLoading();
01521
01522 if (v->current_order.IsType(OT_LOADING)) return true;
01523
01524 if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01525
01526 v->ShowVisualEffect();
01527
01528
01529 int j = v->UpdateSpeed();
01530
01531 int adv_spd = v->GetAdvanceDistance();
01532 bool blocked = false;
01533 while (j >= adv_spd) {
01534 j -= adv_spd;
01535
01536 RoadVehicle *u = v;
01537 for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01538 if (!IndividualRoadVehicleController(u, prev)) {
01539 blocked = true;
01540 break;
01541 }
01542 }
01543 if (blocked) break;
01544
01545
01546 adv_spd = v->GetAdvanceDistance();
01547
01548
01549 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01550 }
01551
01552 v->SetLastSpeed();
01553
01554 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01555 if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01556
01557 u->UpdateViewport(false, false);
01558 }
01559
01560
01561
01562
01563 if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01564
01565 return true;
01566 }
01567
01568 Money RoadVehicle::GetRunningCost() const
01569 {
01570 const Engine *e = this->GetEngine();
01571 if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01572
01573 uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01574 if (cost_factor == 0) return 0;
01575
01576 return GetPrice(e->u.road.running_cost_class, cost_factor, e->GetGRF());
01577 }
01578
01579 bool RoadVehicle::Tick()
01580 {
01581 this->tick_counter++;
01582
01583 if (this->IsFrontEngine()) {
01584 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01585 return RoadVehController(this);
01586 }
01587
01588 return true;
01589 }
01590
01591 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01592 {
01593
01594 if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01595 if (v->IsChainInDepot()) {
01596 VehicleServiceInDepot(v);
01597 return;
01598 }
01599
01600 uint max_penalty;
01601 switch (_settings_game.pf.pathfinder_for_roadvehs) {
01602 case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break;
01603 case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01604 default: NOT_REACHED();
01605 }
01606
01607 FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01608
01609 if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01610 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01611
01612
01613
01614 v->current_order.MakeDummy();
01615 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
01616 }
01617 return;
01618 }
01619
01620 DepotID depot = GetDepotIndex(rfdd.tile);
01621
01622 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01623 v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01624 !Chance16(1, 20)) {
01625 return;
01626 }
01627
01628 SetBit(v->gv_flags, GVF_SUPPRESS_IMPLICIT_ORDERS);
01629 v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01630 v->dest_tile = rfdd.tile;
01631 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
01632 }
01633
01634 void RoadVehicle::OnNewDay()
01635 {
01636 AgeVehicle(this);
01637
01638 if (!this->IsFrontEngine()) return;
01639
01640 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01641 if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01642
01643 CheckIfRoadVehNeedsService(this);
01644
01645 CheckOrders(this);
01646
01647 if (this->running_ticks == 0) return;
01648
01649 CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01650
01651 this->profit_this_year -= cost.GetCost();
01652 this->running_ticks = 0;
01653
01654 SubtractMoneyFromCompanyFract(this->owner, cost);
01655
01656 SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01657 SetWindowClassesDirty(WC_ROADVEH_LIST);
01658 }
01659
01660 Trackdir RoadVehicle::GetVehicleTrackdir() const
01661 {
01662 if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01663
01664 if (this->IsInDepot()) {
01665
01666 return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01667 }
01668
01669 if (IsStandardRoadStopTile(this->tile)) {
01670
01671 return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile));
01672 }
01673
01674
01675 if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01676
01677
01678
01679 return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01680 }