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