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