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