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