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