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