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