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