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