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