00001
00002
00005 #include "stdafx.h"
00006 #include "landscape.h"
00007 #include "roadveh.h"
00008 #include "station_map.h"
00009 #include "command_func.h"
00010 #include "news_func.h"
00011 #include "pathfind.h"
00012 #include "npf.h"
00013 #include "company_func.h"
00014 #include "vehicle_gui.h"
00015 #include "articulated_vehicles.h"
00016 #include "newgrf_engine.h"
00017 #include "newgrf_sound.h"
00018 #include "yapf/yapf.h"
00019 #include "strings_func.h"
00020 #include "tunnelbridge_map.h"
00021 #include "functions.h"
00022 #include "window_func.h"
00023 #include "date_func.h"
00024 #include "vehicle_func.h"
00025 #include "sound_func.h"
00026 #include "variables.h"
00027 #include "autoreplace_gui.h"
00028 #include "gfx_func.h"
00029 #include "ai/ai.hpp"
00030 #include "depot_base.h"
00031 #include "effectvehicle_func.h"
00032 #include "settings_type.h"
00033
00034 #include "table/strings.h"
00035 #include "table/sprites.h"
00036
00037 static const uint16 _roadveh_images[63] = {
00038 0xCD4, 0xCDC, 0xCE4, 0xCEC, 0xCF4, 0xCFC, 0xD0C, 0xD14,
00039 0xD24, 0xD1C, 0xD2C, 0xD04, 0xD1C, 0xD24, 0xD6C, 0xD74,
00040 0xD7C, 0xC14, 0xC1C, 0xC24, 0xC2C, 0xC34, 0xC3C, 0xC4C,
00041 0xC54, 0xC64, 0xC5C, 0xC6C, 0xC44, 0xC5C, 0xC64, 0xCAC,
00042 0xCB4, 0xCBC, 0xD94, 0xD9C, 0xDA4, 0xDAC, 0xDB4, 0xDBC,
00043 0xDCC, 0xDD4, 0xDE4, 0xDDC, 0xDEC, 0xDC4, 0xDDC, 0xDE4,
00044 0xE2C, 0xE34, 0xE3C, 0xC14, 0xC1C, 0xC2C, 0xC3C, 0xC4C,
00045 0xC5C, 0xC64, 0xC6C, 0xC74, 0xC84, 0xC94, 0xCA4
00046 };
00047
00048 static const uint16 _roadveh_full_adder[63] = {
00049 0, 88, 0, 0, 0, 0, 48, 48,
00050 48, 48, 0, 0, 64, 64, 0, 16,
00051 16, 0, 88, 0, 0, 0, 0, 48,
00052 48, 48, 48, 0, 0, 64, 64, 0,
00053 16, 16, 0, 88, 0, 0, 0, 0,
00054 48, 48, 48, 48, 0, 0, 64, 64,
00055 0, 16, 16, 0, 8, 8, 8, 8,
00056 0, 0, 0, 8, 8, 8, 8
00057 };
00058
00060 static const TrackdirBits _road_enter_dir_to_reachable_trackdirs[DIAGDIR_END] = {
00061 TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_X_NE,
00062 TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_Y_SE,
00063 TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_RIGHT_S,
00064 TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_Y_NW
00065 };
00066
00067 static const Trackdir _road_reverse_table[DIAGDIR_END] = {
00068 TRACKDIR_RVREV_NE, TRACKDIR_RVREV_SE, TRACKDIR_RVREV_SW, TRACKDIR_RVREV_NW
00069 };
00070
00073 static const TrackdirBits _road_exit_dir_to_incoming_trackdirs[DIAGDIR_END] = {
00074 TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_LEFT_S,
00075 TRACKDIR_BIT_LEFT_N | TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_Y_NW,
00076 TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_X_NE,
00077 TRACKDIR_BIT_RIGHT_S | TRACKDIR_BIT_LOWER_E | TRACKDIR_BIT_Y_SE
00078 };
00079
00081 static const Trackdir _roadveh_depot_exit_trackdir[DIAGDIR_END] = {
00082 TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW
00083 };
00084
00085 static SpriteID GetRoadVehIcon(EngineID engine)
00086 {
00087 uint8 spritenum = RoadVehInfo(engine)->image_index;
00088
00089 if (is_custom_sprite(spritenum)) {
00090 SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
00091 if (sprite != 0) return sprite;
00092
00093 spritenum = GetEngine(engine)->image_index;
00094 }
00095
00096 return 6 + _roadveh_images[spritenum];
00097 }
00098
00099 SpriteID RoadVehicle::GetImage(Direction direction) const
00100 {
00101 uint8 spritenum = this->spritenum;
00102 SpriteID sprite;
00103
00104 if (is_custom_sprite(spritenum)) {
00105 sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
00106 if (sprite != 0) return sprite;
00107
00108 spritenum = GetEngine(this->engine_type)->image_index;
00109 }
00110
00111 sprite = direction + _roadveh_images[spritenum];
00112
00113 if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
00114
00115 return sprite;
00116 }
00117
00118 void DrawRoadVehEngine(int x, int y, EngineID engine, SpriteID pal)
00119 {
00120 DrawSprite(GetRoadVehIcon(engine), pal, x, y);
00121 }
00122
00123 byte GetRoadVehLength(const Vehicle *v)
00124 {
00125 byte length = 8;
00126
00127 uint16 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
00128 if (veh_len != CALLBACK_FAILED) {
00129 length -= Clamp(veh_len, 0, 7);
00130 }
00131
00132 return length;
00133 }
00134
00135 void RoadVehUpdateCache(Vehicle *v)
00136 {
00137 assert(v->type == VEH_ROAD);
00138 assert(IsRoadVehFront(v));
00139
00140 v->InvalidateNewGRFCacheOfChain();
00141
00142 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00143
00144 assert(u->First() == v);
00145
00146
00147 u->u.road.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
00148
00149
00150 u->u.road.cached_veh_length = GetRoadVehLength(u);
00151
00152
00153 u->colourmap = PAL_NONE;
00154 }
00155 }
00156
00163 CommandCost CmdBuildRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00164 {
00165 Vehicle *v;
00166 UnitID unit_num;
00167
00168 if (!IsEngineBuildable(p1, VEH_ROAD, _current_company)) return_cmd_error(STR_ROAD_VEHICLE_NOT_AVAILABLE);
00169
00170 const Engine *e = GetEngine(p1);
00171
00172 if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
00173
00174 CommandCost cost(EXPENSES_NEW_VEHICLES, e->GetCost());
00175 if (flags & DC_QUERY_COST) return cost;
00176
00177
00178
00179 if (!IsRoadDepotTile(tile)) return CMD_ERROR;
00180 if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
00181
00182 if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(EngInfo(p1)->misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_DEPOT_WRONG_DEPOT_TYPE);
00183
00184 uint num_vehicles = 1 + CountArticulatedParts(p1, false);
00185
00186
00187 Vehicle **vl = AllocaM(Vehicle*, num_vehicles + 1);
00188 memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
00189
00190 if (!Vehicle::AllocateList(vl, num_vehicles)) {
00191 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00192 }
00193
00194 v = vl[0];
00195
00196
00197 unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_ROAD);
00198 if (unit_num > _settings_game.vehicle.max_roadveh)
00199 return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
00200
00201 if (flags & DC_EXEC) {
00202 int x;
00203 int y;
00204
00205 const RoadVehicleInfo *rvi = RoadVehInfo(p1);
00206
00207 v = new (v) RoadVehicle();
00208 v->unitnumber = unit_num;
00209 v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
00210 v->owner = _current_company;
00211
00212 v->tile = tile;
00213 x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
00214 y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
00215 v->x_pos = x;
00216 v->y_pos = y;
00217 v->z_pos = GetSlopeZ(x, y);
00218
00219 v->running_ticks = 0;
00220
00221 v->u.road.state = RVSB_IN_DEPOT;
00222 v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00223
00224 v->spritenum = rvi->image_index;
00225 v->cargo_type = e->GetDefaultCargoType();
00226 v->cargo_subtype = 0;
00227 v->cargo_cap = rvi->capacity;
00228
00229 v->value = cost.GetCost();
00230
00231
00232
00233
00234
00235
00236
00237 v->last_station_visited = INVALID_STATION;
00238 v->max_speed = rvi->max_speed;
00239 v->engine_type = (EngineID)p1;
00240
00241 v->reliability = e->reliability;
00242 v->reliability_spd_dec = e->reliability_spd_dec;
00243 v->max_age = e->lifelength * DAYS_IN_LEAP_YEAR;
00244 _new_vehicle_id = v->index;
00245
00246 v->name = NULL;
00247
00248 v->service_interval = _settings_game.vehicle.servint_roadveh;
00249
00250 v->date_of_last_service = _date;
00251 v->build_year = _cur_year;
00252
00253 v->cur_image = 0xC15;
00254 v->random_bits = VehicleRandomBits();
00255 SetRoadVehFront(v);
00256
00257 v->u.road.roadtype = HasBit(EngInfo(v->engine_type)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
00258 v->u.road.compatible_roadtypes = RoadTypeToRoadTypes(v->u.road.roadtype);
00259 v->u.road.cached_veh_length = 8;
00260
00261 v->vehicle_flags = 0;
00262 if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00263
00264 v->cargo_cap = rvi->capacity;
00265
00266 AddArticulatedParts(vl, VEH_ROAD);
00267 v->InvalidateNewGRFCacheOfChain();
00268
00269
00270 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00271 u->u.road.cached_veh_length = GetRoadVehLength(u);
00272
00273 if (u->cargo_cap != 0) u->cargo_cap = GetVehicleProperty(u, 0x0F, u->cargo_cap);
00274 v->InvalidateNewGRFCache();
00275 u->InvalidateNewGRFCache();
00276 }
00277
00278 VehicleMove(v, false);
00279
00280 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00281 InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
00282 InvalidateWindow(WC_COMPANY, v->owner);
00283 if (IsLocalCompany()) {
00284 InvalidateAutoreplaceWindow(v->engine_type, v->group_id);
00285 }
00286
00287 GetCompany(_current_company)->num_engines[p1]++;
00288
00289 CheckConsistencyOfArticulatedVehicle(v);
00290 }
00291
00292 return cost;
00293 }
00294
00295 void ClearSlot(Vehicle *v)
00296 {
00297 RoadStop *rs = v->u.road.slot;
00298 if (v->u.road.slot == NULL) return;
00299
00300 v->u.road.slot = NULL;
00301 v->u.road.slot_age = 0;
00302
00303 assert(rs->num_vehicles != 0);
00304 rs->num_vehicles--;
00305
00306 DEBUG(ms, 3, "Clearing slot at 0x%X", rs->xy);
00307 }
00308
00309 bool RoadVehicle::IsStoppedInDepot() const
00310 {
00311 TileIndex tile = this->tile;
00312
00313 if (!IsRoadDepotTile(tile)) return false;
00314 if (IsRoadVehFront(this) && !(this->vehstatus & VS_STOPPED)) return false;
00315
00316 for (const Vehicle *v = this; v != NULL; v = v->Next()) {
00317 if (v->u.road.state != RVSB_IN_DEPOT || v->tile != tile) return false;
00318 }
00319 return true;
00320 }
00321
00328 CommandCost CmdSellRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00329 {
00330 Vehicle *v;
00331
00332 if (!IsValidVehicleID(p1)) return CMD_ERROR;
00333
00334 v = GetVehicle(p1);
00335
00336 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
00337
00338 if (HASBITS(v->vehstatus, VS_CRASHED)) return_cmd_error(STR_CAN_T_SELL_DESTROYED_VEHICLE);
00339
00340 if (!v->IsStoppedInDepot()) {
00341 return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
00342 }
00343
00344 CommandCost ret(EXPENSES_NEW_VEHICLES, -v->value);
00345
00346 if (flags & DC_EXEC) {
00347 delete v;
00348 }
00349
00350 return ret;
00351 }
00352
00353 struct RoadFindDepotData {
00354 uint best_length;
00355 TileIndex tile;
00356 OwnerByte owner;
00357 };
00358
00359 static const DiagDirection _road_pf_directions[] = {
00360 DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR,
00361 DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE, INVALID_DIAGDIR, INVALID_DIAGDIR
00362 };
00363
00364 static bool EnumRoadSignalFindDepot(TileIndex tile, void *data, Trackdir trackdir, uint length)
00365 {
00366 RoadFindDepotData *rfdd = (RoadFindDepotData*)data;
00367
00368 tile += TileOffsByDiagDir(_road_pf_directions[trackdir]);
00369
00370 if (IsRoadDepotTile(tile) &&
00371 IsTileOwner(tile, rfdd->owner) &&
00372 length < rfdd->best_length) {
00373 rfdd->best_length = length;
00374 rfdd->tile = tile;
00375 }
00376 return false;
00377 }
00378
00379 static const Depot *FindClosestRoadDepot(const Vehicle *v)
00380 {
00381 switch (_settings_game.pf.pathfinder_for_roadvehs) {
00382 case VPF_YAPF:
00383 return YapfFindNearestRoadDepot(v);
00384
00385 case VPF_NPF: {
00386
00387 Trackdir trackdir = GetVehicleTrackdir(v);
00388
00389 NPFFoundTargetData ftd = NPFRouteToDepotBreadthFirstTwoWay(v->tile, trackdir, false, v->tile, ReverseTrackdir(trackdir), false, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES, 0);
00390
00391 if (ftd.best_bird_dist == 0) return GetDepotByTile(ftd.node.tile);
00392 } break;
00393
00394 default:
00395 case VPF_OPF: {
00396 RoadFindDepotData rfdd;
00397
00398 rfdd.owner = v->owner;
00399 rfdd.best_length = UINT_MAX;
00400
00401
00402 for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
00403 FollowTrack(v->tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, d, EnumRoadSignalFindDepot, NULL, &rfdd);
00404 }
00405
00406 if (rfdd.best_length != UINT_MAX) return GetDepotByTile(rfdd.tile);
00407 } break;
00408 }
00409
00410 return NULL;
00411 }
00412
00413 bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
00414 {
00415 const Depot *depot = FindClosestRoadDepot(this);
00416
00417 if (depot == NULL) return false;
00418
00419 if (location != NULL) *location = depot->xy;
00420 if (destination != NULL) *destination = depot->index;
00421
00422 return true;
00423 }
00424
00433 CommandCost CmdSendRoadVehToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00434 {
00435 if (p2 & DEPOT_MASS_SEND) {
00436
00437 if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
00438 return SendAllVehiclesToDepot(VEH_ROAD, flags, p2 & DEPOT_SERVICE, _current_company, (p2 & VLW_MASK), p1);
00439 }
00440
00441 if (!IsValidVehicleID(p1)) return CMD_ERROR;
00442
00443 Vehicle *v = GetVehicle(p1);
00444
00445 if (v->type != VEH_ROAD) return CMD_ERROR;
00446
00447 return v->SendToDepot(flags, (DepotCommand)(p2 & DEPOT_COMMAND_MASK));
00448 }
00449
00456 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00457 {
00458 Vehicle *v;
00459
00460 if (!IsValidVehicleID(p1)) return CMD_ERROR;
00461
00462 v = GetVehicle(p1);
00463
00464 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
00465
00466 if (v->vehstatus & VS_STOPPED ||
00467 v->vehstatus & VS_CRASHED ||
00468 v->breakdown_ctr != 0 ||
00469 v->u.road.overtaking != 0 ||
00470 v->u.road.state == RVSB_WORMHOLE ||
00471 v->IsInDepot() ||
00472 v->cur_speed < 5) {
00473 return CMD_ERROR;
00474 }
00475
00476 if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
00477
00478 if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
00479
00480 if (flags & DC_EXEC) v->u.road.reverse_ctr = 180;
00481
00482 return CommandCost();
00483 }
00484
00485
00486 void RoadVehicle::MarkDirty()
00487 {
00488 for (Vehicle *v = this; v != NULL; v = v->Next()) {
00489 v->UpdateViewport(false, false);
00490 }
00491 }
00492
00493 void RoadVehicle::UpdateDeltaXY(Direction direction)
00494 {
00495 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
00496 static const uint32 _delta_xy_table[8] = {
00497 MKIT(3, 3, -1, -1),
00498 MKIT(3, 7, -1, -3),
00499 MKIT(3, 3, -1, -1),
00500 MKIT(7, 3, -3, -1),
00501 MKIT(3, 3, -1, -1),
00502 MKIT(3, 7, -1, -3),
00503 MKIT(3, 3, -1, -1),
00504 MKIT(7, 3, -3, -1),
00505 };
00506 #undef MKIT
00507
00508 uint32 x = _delta_xy_table[direction];
00509 this->x_offs = GB(x, 0, 8);
00510 this->y_offs = GB(x, 8, 8);
00511 this->x_extent = GB(x, 16, 8);
00512 this->y_extent = GB(x, 24, 8);
00513 this->z_extent = 6;
00514 }
00515
00516 static void ClearCrashedStation(Vehicle *v)
00517 {
00518 RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
00519
00520
00521 rs->SetEntranceBusy(false);
00522
00523
00524 rs->FreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY));
00525 }
00526
00527 static void DeleteLastRoadVeh(Vehicle *v)
00528 {
00529 Vehicle *u = v;
00530 for (; v->Next() != NULL; v = v->Next()) u = v;
00531 u->SetNext(NULL);
00532
00533 if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
00534
00535 delete v;
00536 }
00537
00538 static byte SetRoadVehPosition(Vehicle *v, int x, int y, bool turned)
00539 {
00540 byte new_z, old_z;
00541
00542
00543 v->x_pos = x;
00544 v->y_pos = y;
00545 new_z = GetSlopeZ(x, y);
00546
00547 old_z = v->z_pos;
00548 v->z_pos = new_z;
00549
00550 v->UpdateViewport(true, turned);
00551 return old_z;
00552 }
00553
00554 static void RoadVehSetRandomDirection(Vehicle *v)
00555 {
00556 static const DirDiff delta[] = {
00557 DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
00558 };
00559
00560 do {
00561 uint32 r = Random();
00562
00563 v->direction = ChangeDir(v->direction, delta[r & 3]);
00564 SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
00565 } while ((v = v->Next()) != NULL);
00566 }
00567
00568 static void RoadVehIsCrashed(Vehicle *v)
00569 {
00570 v->u.road.crashed_ctr++;
00571 if (v->u.road.crashed_ctr == 2) {
00572 CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00573 } else if (v->u.road.crashed_ctr <= 45) {
00574 if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
00575 } else if (v->u.road.crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
00576 DeleteLastRoadVeh(v);
00577 }
00578 }
00579
00580 static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
00581 {
00582 const Vehicle *u = (Vehicle*)data;
00583
00584 return
00585 v->type == VEH_TRAIN &&
00586 abs(v->z_pos - u->z_pos) <= 6 &&
00587 abs(v->x_pos - u->x_pos) <= 4 &&
00588 abs(v->y_pos - u->y_pos) <= 4 ?
00589 v : NULL;
00590 }
00591
00592 static void RoadVehCrash(Vehicle *v)
00593 {
00594 uint16 pass = 1;
00595
00596 v->u.road.crashed_ctr++;
00597
00598 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00599 if (IsCargoInClass(u->cargo_type, CC_PASSENGERS)) pass += u->cargo.Count();
00600
00601 u->vehstatus |= VS_CRASHED;
00602
00603 MarkSingleVehicleDirty(u);
00604 }
00605
00606 ClearSlot(v);
00607
00608 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00609
00610 AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
00611
00612 SetDParam(0, pass);
00613 AddNewsItem(
00614 (pass == 1) ?
00615 STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE,
00616 NS_ACCIDENT_VEHICLE,
00617 v->index,
00618 0
00619 );
00620
00621 ModifyStationRatingAround(v->tile, v->owner, -160, 22);
00622 SndPlayVehicleFx(SND_12_EXPLOSION, v);
00623 }
00624
00625 static bool RoadVehCheckTrainCrash(Vehicle *v)
00626 {
00627 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00628 if (u->u.road.state == RVSB_WORMHOLE) continue;
00629
00630 TileIndex tile = u->tile;
00631
00632 if (!IsLevelCrossingTile(tile)) continue;
00633
00634 if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
00635 RoadVehCrash(v);
00636 return true;
00637 }
00638 }
00639
00640 return false;
00641 }
00642
00643 static void HandleBrokenRoadVeh(Vehicle *v)
00644 {
00645 if (v->breakdown_ctr != 1) {
00646 v->breakdown_ctr = 1;
00647 v->cur_speed = 0;
00648
00649 if (v->breakdowns_since_last_service != 255)
00650 v->breakdowns_since_last_service++;
00651
00652 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
00653 InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
00654
00655 if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
00656 SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
00657 SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
00658 }
00659
00660 if (!(v->vehstatus & VS_HIDDEN)) {
00661 Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
00662 if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2;
00663 }
00664 }
00665
00666 if ((v->tick_counter & 1) == 0) {
00667 if (--v->breakdown_delay == 0) {
00668 v->breakdown_ctr = 0;
00669 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
00670 }
00671 }
00672 }
00673
00674 TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
00675 {
00676 if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
00677
00678 TileIndex dest;
00679 if (YapfFindNearestRoadVehicleCompatibleStop(this, station, &dest)) {
00680 return dest;
00681 } else {
00682
00683 this->cur_order_index++;
00684 return 0;
00685 }
00686 }
00687
00688 static void StartRoadVehSound(const Vehicle *v)
00689 {
00690 if (!PlayVehicleSound(v, VSE_START)) {
00691 SoundFx s = RoadVehInfo(v->engine_type)->sfx;
00692 if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
00693 s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
00694 SndPlayVehicleFx(s, v);
00695 }
00696 }
00697
00698 struct RoadVehFindData {
00699 int x;
00700 int y;
00701 const Vehicle *veh;
00702 Vehicle *best;
00703 uint best_diff;
00704 Direction dir;
00705 };
00706
00707 static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
00708 {
00709 static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
00710 static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
00711
00712 RoadVehFindData *rvf = (RoadVehFindData*)data;
00713
00714 short x_diff = v->x_pos - rvf->x;
00715 short y_diff = v->y_pos - rvf->y;
00716
00717 if (v->type == VEH_ROAD &&
00718 !v->IsInDepot() &&
00719 abs(v->z_pos - rvf->veh->z_pos) < 6 &&
00720 v->direction == rvf->dir &&
00721 rvf->veh->First() != v->First() &&
00722 (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
00723 (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
00724 (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
00725 (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
00726 uint diff = abs(x_diff) + abs(y_diff);
00727
00728 if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
00729 rvf->best = v;
00730 rvf->best_diff = diff;
00731 }
00732 }
00733
00734 return NULL;
00735 }
00736
00737 static Vehicle *RoadVehFindCloseTo(Vehicle *v, int x, int y, Direction dir)
00738 {
00739 RoadVehFindData rvf;
00740 Vehicle *front = v->First();
00741
00742 if (front->u.road.reverse_ctr != 0) return NULL;
00743
00744 rvf.x = x;
00745 rvf.y = y;
00746 rvf.dir = dir;
00747 rvf.veh = v;
00748 rvf.best_diff = UINT_MAX;
00749
00750 if (front->u.road.state == RVSB_WORMHOLE) {
00751 FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
00752 FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
00753 } else {
00754 FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
00755 }
00756
00757
00758
00759
00760
00761 if (rvf.best_diff == UINT_MAX) {
00762 front->u.road.blocked_ctr = 0;
00763 return NULL;
00764 }
00765
00766 if (++front->u.road.blocked_ctr > 1480) return NULL;
00767
00768 return rvf.best;
00769 }
00770
00771 static void RoadVehArrivesAt(const Vehicle *v, Station *st)
00772 {
00773 if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
00774
00775 if (!(st->had_vehicle_of_type & HVOT_BUS)) {
00776 st->had_vehicle_of_type |= HVOT_BUS;
00777 SetDParam(0, st->index);
00778 AddNewsItem(
00779 v->u.road.roadtype == ROADTYPE_ROAD ? STR_902F_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_PASSENGER_TRAM,
00780 (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00781 v->index,
00782 st->index
00783 );
00784 AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00785 }
00786 } else {
00787
00788 if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
00789 st->had_vehicle_of_type |= HVOT_TRUCK;
00790 SetDParam(0, st->index);
00791 AddNewsItem(
00792 v->u.road.roadtype == ROADTYPE_ROAD ? STR_9030_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_CARGO_TRAM,
00793 (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00794 v->index,
00795 st->index
00796 );
00797 AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00798 }
00799 }
00800 }
00801
00802 static int RoadVehAccelerate(Vehicle *v)
00803 {
00804 uint oldspeed = v->cur_speed;
00805 uint accel = 256 + (v->u.road.overtaking != 0 ? 256 : 0);
00806 uint spd = v->subspeed + accel;
00807
00808 v->subspeed = (uint8)spd;
00809
00810 int tempmax = v->max_speed;
00811 if (v->cur_speed > v->max_speed) {
00812 tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
00813 }
00814
00815 v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
00816
00817
00818 if (v->u.road.state == RVSB_WORMHOLE && !(v->vehstatus & VS_HIDDEN)) {
00819 v->cur_speed = min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
00820 }
00821
00822
00823 if (oldspeed != v->cur_speed) {
00824 if (_settings_client.gui.vehicle_speed) {
00825 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00826 }
00827 }
00828
00829
00830 int scaled_spd = spd * 3 >> 2;
00831
00832 scaled_spd += v->progress;
00833 v->progress = 0;
00834 return scaled_spd;
00835 }
00836
00837 static Direction RoadVehGetNewDirection(const Vehicle *v, int x, int y)
00838 {
00839 static const Direction _roadveh_new_dir[] = {
00840 DIR_N , DIR_NW, DIR_W , INVALID_DIR,
00841 DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
00842 DIR_E , DIR_SE, DIR_S
00843 };
00844
00845 x = x - v->x_pos + 1;
00846 y = y - v->y_pos + 1;
00847
00848 if ((uint)x > 2 || (uint)y > 2) return v->direction;
00849 return _roadveh_new_dir[y * 4 + x];
00850 }
00851
00852 static Direction RoadVehGetSlidingDirection(const Vehicle *v, int x, int y)
00853 {
00854 Direction new_dir = RoadVehGetNewDirection(v, x, y);
00855 Direction old_dir = v->direction;
00856 DirDiff delta;
00857
00858 if (new_dir == old_dir) return old_dir;
00859 delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
00860 return ChangeDir(old_dir, delta);
00861 }
00862
00863 struct OvertakeData {
00864 const Vehicle *u;
00865 const Vehicle *v;
00866 TileIndex tile;
00867 Trackdir trackdir;
00868 };
00869
00870 static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
00871 {
00872 const OvertakeData *od = (OvertakeData*)data;
00873
00874 return
00875 v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v ?
00876 v : NULL;
00877 }
00878
00885 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
00886 {
00887 TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->u.road.compatible_roadtypes);
00888 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
00889 TrackdirBits red_signals = TrackStatusToRedSignals(ts);
00890 TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00891
00892
00893 if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00894
00895
00896 return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
00897 }
00898
00899 static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u)
00900 {
00901 OvertakeData od;
00902
00903 od.v = v;
00904 od.u = u;
00905
00906 if (u->max_speed >= v->max_speed &&
00907 !(u->vehstatus & VS_STOPPED) &&
00908 u->cur_speed != 0) {
00909 return;
00910 }
00911
00912
00913 if (v->u.road.roadtype == ROADTYPE_TRAM) return;
00914
00915
00916 if (IsTileType(v->tile, MP_STATION)) return;
00917
00918
00919 if (RoadVehHasArticPart(v)) return;
00920
00921
00922 if (v->direction != u->direction || !(v->direction & 1)) return;
00923
00924
00925 if (v->u.road.state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->u.road.state & RVSB_TRACKDIR_MASK))) return;
00926
00927 od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
00928
00929
00930
00931
00932
00933
00934
00935 od.tile = v->tile;
00936 if (CheckRoadBlockedForOvertaking(&od)) return;
00937
00938 od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
00939 if (CheckRoadBlockedForOvertaking(&od)) return;
00940
00941 if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) {
00942 v->u.road.overtaking_ctr = 0x11;
00943 v->u.road.overtaking = 0x10;
00944 } else {
00945
00946 v->u.road.overtaking_ctr = 0;
00947 v->u.road.overtaking = 0x10;
00948 }
00949 }
00950
00951 static void RoadZPosAffectSpeed(Vehicle *v, byte old_z)
00952 {
00953 if (old_z == v->z_pos) return;
00954
00955 if (old_z < v->z_pos) {
00956 v->cur_speed = v->cur_speed * 232 / 256;
00957 } else {
00958 uint16 spd = v->cur_speed + 2;
00959 if (spd <= v->max_speed) v->cur_speed = spd;
00960 }
00961 }
00962
00963 static int PickRandomBit(uint bits)
00964 {
00965 uint i;
00966 uint num = RandomRange(CountBits(bits));
00967
00968 for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
00969 return i;
00970 }
00971
00972 struct FindRoadToChooseData {
00973 TileIndex dest;
00974 uint maxtracklen;
00975 uint mindist;
00976 };
00977
00978 static bool EnumRoadTrackFindDist(TileIndex tile, void *data, Trackdir trackdir, uint length)
00979 {
00980 FindRoadToChooseData *frd = (FindRoadToChooseData*)data;
00981 uint dist = DistanceManhattan(tile, frd->dest);
00982
00983 if (dist <= frd->mindist) {
00984 if (dist != frd->mindist || length < frd->maxtracklen) {
00985 frd->maxtracklen = length;
00986 }
00987 frd->mindist = dist;
00988 }
00989 return false;
00990 }
00991
00992 static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes)
00993 {
00994
00995 void *perf = NpfBeginInterval();
00996 NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, ignore_start_tile, target, type, sub_type, owner, railtypes);
00997 int t = NpfEndInterval(perf);
00998 DEBUG(yapf, 4, "[NPFR] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
00999 return ret;
01000 }
01001
01010 static Trackdir RoadFindPathToDest(Vehicle *v, TileIndex tile, DiagDirection enterdir)
01011 {
01012 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
01013
01014 TileIndex desttile;
01015 FindRoadToChooseData frd;
01016 Trackdir best_track;
01017
01018 TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes);
01019 TrackdirBits red_signals = TrackStatusToRedSignals(ts);
01020 TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
01021
01022 if (IsTileType(tile, MP_ROAD)) {
01023 if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->u.road.compatible_roadtypes) == 0)) {
01024
01025 trackdirs = TRACKDIR_BIT_NONE;
01026 }
01027 } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
01028
01029
01030 if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || RoadVehHasArticPart(v)) {
01031
01032 trackdirs = TRACKDIR_BIT_NONE;
01033 } else {
01034
01035 RoadStopType rstype = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK;
01036
01037 if (GetRoadStopType(tile) != rstype) {
01038
01039 trackdirs = TRACKDIR_BIT_NONE;
01040 } else {
01041
01042 if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) &&
01043 !GetRoadStopByTile(tile, rstype)->HasFreeBay()) {
01044
01045 trackdirs = TRACKDIR_BIT_NONE;
01046 }
01047 }
01048 }
01049 }
01050
01051
01052
01053
01054
01055
01056 trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
01057 if (trackdirs == TRACKDIR_BIT_NONE) {
01058
01059 return_track(_road_reverse_table[enterdir]);
01060 }
01061
01062 if (v->u.road.reverse_ctr != 0) {
01063 bool reverse = true;
01064 if (v->u.road.roadtype == ROADTYPE_TRAM) {
01065
01066
01067 RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM);
01068 RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
01069 reverse = ((rb & straight) == straight) ||
01070 (rb == DiagDirToRoadBits(enterdir));
01071 }
01072 if (reverse) {
01073 v->u.road.reverse_ctr = 0;
01074 if (v->tile != tile) {
01075 return_track(_road_reverse_table[enterdir]);
01076 }
01077 }
01078 }
01079
01080 desttile = v->dest_tile;
01081 if (desttile == 0) {
01082
01083 return_track(PickRandomBit(trackdirs));
01084 }
01085
01086
01087 if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) {
01088 return_track(FindFirstBit2x64(trackdirs));
01089 }
01090
01091 switch (_settings_game.pf.pathfinder_for_roadvehs) {
01092 case VPF_YAPF: {
01093 Trackdir trackdir = YapfChooseRoadTrack(v, tile, enterdir);
01094 if (trackdir != INVALID_TRACKDIR) return_track(trackdir);
01095 return_track(PickRandomBit(trackdirs));
01096 } break;
01097
01098 case VPF_NPF: {
01099 NPFFindStationOrTileData fstd;
01100
01101 NPFFillWithOrderData(&fstd, v);
01102 Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
01103
01104
01105 NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES);
01106 if (ftd.best_trackdir == INVALID_TRACKDIR) {
01107
01108
01109
01110 return_track(FindFirstBit2x64(trackdirs));
01111 } else {
01112
01113
01114
01115
01116 return_track(ftd.best_trackdir);
01117 }
01118 } break;
01119
01120 default:
01121 case VPF_OPF: {
01122 DiagDirection dir;
01123
01124 if (IsTileType(desttile, MP_ROAD)) {
01125 if (IsRoadDepot(desttile)) {
01126 dir = GetRoadDepotDirection(desttile);
01127 goto do_it;
01128 }
01129 } else if (IsTileType(desttile, MP_STATION)) {
01130
01131 if (IsStandardRoadStopTile(desttile)) {
01132 dir = GetRoadStopDir(desttile);
01133 do_it:;
01134
01135
01136
01137 desttile += TileOffsByDiagDir(dir);
01138 if (desttile == tile && trackdirs & _road_exit_dir_to_incoming_trackdirs[dir]) {
01139
01140
01141
01142 return_track(FindFirstBit2x64(trackdirs & _road_exit_dir_to_incoming_trackdirs[dir]));
01143 }
01144 }
01145 }
01146
01147 frd.dest = desttile;
01148
01149 best_track = INVALID_TRACKDIR;
01150 uint best_dist = UINT_MAX;
01151 uint best_maxlen = UINT_MAX;
01152 uint bitmask = (uint)trackdirs;
01153 uint i;
01154 FOR_EACH_SET_BIT(i, bitmask) {
01155 if (best_track == INVALID_TRACKDIR) best_track = (Trackdir)i;
01156 frd.maxtracklen = UINT_MAX;
01157 frd.mindist = UINT_MAX;
01158 FollowTrack(tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, _road_pf_directions[i], EnumRoadTrackFindDist, NULL, &frd);
01159
01160 if (frd.mindist < best_dist || (frd.mindist == best_dist && frd.maxtracklen < best_maxlen)) {
01161 best_dist = frd.mindist;
01162 best_maxlen = frd.maxtracklen;
01163 best_track = (Trackdir)i;
01164 }
01165 }
01166 } break;
01167 }
01168
01169 found_best_track:;
01170
01171 if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR;
01172
01173 return best_track;
01174 }
01175
01176 static uint RoadFindPathToStop(const Vehicle *v, TileIndex tile)
01177 {
01178 if (_settings_game.pf.pathfinder_for_roadvehs == VPF_YAPF) {
01179
01180 return YapfRoadVehDistanceToTile(v, tile);
01181 }
01182
01183
01184 Trackdir trackdir = GetVehicleTrackdir(v);
01185 assert(trackdir != INVALID_TRACKDIR);
01186
01187 NPFFindStationOrTileData fstd;
01188 fstd.dest_coords = tile;
01189 fstd.station_index = INVALID_STATION;
01190
01191 uint dist = NPFRouteToStationOrTile(v->tile, trackdir, false, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES).best_path_dist;
01192
01193 if (dist != UINT_MAX) dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH;
01194
01195 return dist;
01196 }
01197
01198 struct RoadDriveEntry {
01199 byte x, y;
01200 };
01201
01202 #include "table/roadveh_movement.h"
01203
01204 static const byte _road_veh_data_1[] = {
01205 20, 20, 16, 16, 0, 0, 0, 0,
01206 19, 19, 15, 15, 0, 0, 0, 0,
01207 16, 16, 12, 12, 0, 0, 0, 0,
01208 15, 15, 11, 11
01209 };
01210
01211 static bool RoadVehLeaveDepot(Vehicle *v, bool first)
01212 {
01213
01214 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01215 if (u->u.road.state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
01216 }
01217
01218 DiagDirection dir = GetRoadDepotDirection(v->tile);
01219 v->direction = DiagDirToDir(dir);
01220
01221 Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
01222 const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
01223
01224 int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
01225 int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
01226
01227 if (first) {
01228 if (RoadVehFindCloseTo(v, x, y, v->direction) != NULL) return true;
01229
01230 VehicleServiceInDepot(v);
01231
01232 StartRoadVehSound(v);
01233
01234
01235 v->cur_speed = 0;
01236 }
01237
01238 v->vehstatus &= ~VS_HIDDEN;
01239 v->u.road.state = tdir;
01240 v->u.road.frame = RVC_DEPOT_START_FRAME;
01241
01242 SetRoadVehPosition(v, x, y, true);
01243
01244 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01245
01246 return true;
01247 }
01248
01249 static Trackdir FollowPreviousRoadVehicle(const Vehicle *v, const Vehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
01250 {
01251 if (prev->tile == v->tile && !already_reversed) {
01252
01253
01254 return _road_reverse_table[entry_dir];
01255 }
01256
01257 byte prev_state = prev->u.road.state;
01258 Trackdir dir;
01259
01260 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
01261 DiagDirection diag_dir = INVALID_DIAGDIR;
01262
01263 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01264 diag_dir = GetTunnelBridgeDirection(tile);
01265 } else if (IsRoadDepotTile(tile)) {
01266 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
01267 }
01268
01269 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
01270 dir = DiagDirToDiagTrackdir(diag_dir);
01271 } else {
01272 if (already_reversed && prev->tile != tile) {
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288 Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01289 { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E },
01290 { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }};
01291 dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01292 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01293 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01294 } else if (prev_state < TRACKDIR_END) {
01295 dir = (Trackdir)prev_state;
01296 } else {
01297 return INVALID_TRACKDIR;
01298 }
01299 }
01300
01301
01302 static const RoadBits required_roadbits[] = {
01303 ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01304 ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X, ROAD_Y
01305 };
01306 RoadBits required = required_roadbits[dir & 0x07];
01307
01308 if ((required & GetAnyRoadBits(tile, v->u.road.roadtype, true)) == ROAD_NONE) {
01309 dir = INVALID_TRACKDIR;
01310 }
01311
01312 return dir;
01313 }
01314
01322 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01323 {
01324
01325 CompanyID original_company = _current_company;
01326 _current_company = c;
01327
01328 CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01329
01330 _current_company = original_company;
01331 return CmdSucceeded(ret);
01332 }
01333
01334 static bool IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev)
01335 {
01336 if (v->u.road.overtaking != 0) {
01337 if (IsTileType(v->tile, MP_STATION)) {
01338
01339 v->u.road.overtaking = 0;
01340 } else if (++v->u.road.overtaking_ctr >= 35) {
01341
01342
01343
01344 if (v->u.road.state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->u.road.state)) {
01345 v->u.road.overtaking = 0;
01346 }
01347 }
01348 }
01349
01350
01351
01352
01353 if (v->IsInDepot()) return true;
01354
01355 if (v->u.road.state == RVSB_WORMHOLE) {
01356
01357 GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01358
01359 if (IsRoadVehFront(v)) {
01360 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01361 if (u != NULL) {
01362 v->cur_speed = u->First()->cur_speed;
01363 return false;
01364 }
01365 }
01366
01367 if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01368
01369 SetRoadVehPosition(v, gp.x, gp.y, true);
01370 return true;
01371 }
01372
01373 v->x_pos = gp.x;
01374 v->y_pos = gp.y;
01375 VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01376 return true;
01377 }
01378
01379
01380
01381
01382 RoadDriveEntry rd = _road_drive_data[v->u.road.roadtype][(
01383 (HasBit(v->u.road.state, RVS_IN_DT_ROAD_STOP) ? v->u.road.state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->u.road.state) +
01384 (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking][v->u.road.frame + 1];
01385
01386 if (rd.x & RDE_NEXT_TILE) {
01387 TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01388 Trackdir dir;
01389
01390 if (IsRoadVehFront(v)) {
01391
01392 dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01393 } else {
01394 dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01395 }
01396
01397 if (dir == INVALID_TRACKDIR) {
01398 if (!IsRoadVehFront(v)) error("Disconnecting road vehicle.");
01399 v->cur_speed = 0;
01400 return false;
01401 }
01402
01403 again:
01404 uint start_frame = RVC_DEFAULT_START_FRAME;
01405 if (IsReversingRoadTrackdir(dir)) {
01406
01407 if (v->u.road.roadtype == ROADTYPE_TRAM) {
01408
01409
01410 RoadBits needed;
01411 switch (dir) {
01412 default: NOT_REACHED();
01413 case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01414 case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01415 case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01416 case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01417 }
01418 if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01419 (IsRoadVehFront(v) && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01420 (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431 } else if (!IsRoadVehFront(v) || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443 tile = v->tile;
01444 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01445 } else {
01446
01447 v->cur_speed = 0;
01448 return false;
01449 }
01450 } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01451 v->cur_speed = 0;
01452 return false;
01453 } else {
01454 tile = v->tile;
01455 }
01456 }
01457
01458
01459 const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking];
01460
01461 int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01462 int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01463
01464 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01465 if (IsRoadVehFront(v)) {
01466 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01467 if (u != NULL) {
01468 v->cur_speed = u->First()->cur_speed;
01469 return false;
01470 }
01471 }
01472
01473 uint32 r = VehicleEnterTile(v, tile, x, y);
01474 if (HasBit(r, VETS_CANNOT_ENTER)) {
01475 if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01476 v->cur_speed = 0;
01477 return false;
01478 }
01479
01480 dir = _road_reverse_table[rd.x & 3];
01481 goto again;
01482 }
01483
01484 if (IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01485 if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01486
01487
01488 v->cur_speed = 0;
01489 return false;
01490 }
01491 if (IsRoadStop(v->tile)) {
01492 RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
01493
01494
01495
01496 if (IsStandardRoadStopTile(v->tile) || HasBit(v->u.road.state, RVS_IS_STOPPING)) {
01497 rs->FreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY));
01498 ClrBit(v->u.road.state, RVS_IS_STOPPING);
01499 }
01500 if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(false);
01501 }
01502 }
01503
01504 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01505 v->tile = tile;
01506 v->u.road.state = (byte)dir;
01507 v->u.road.frame = start_frame;
01508 }
01509 if (new_dir != v->direction) {
01510 v->direction = new_dir;
01511 v->cur_speed -= v->cur_speed >> 2;
01512 }
01513
01514 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01515 return true;
01516 }
01517
01518 if (rd.x & RDE_TURNED) {
01519
01520 Trackdir dir;
01521 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01522
01523 RoadBits tram;
01524 if (v->u.road.roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && CountBits(tram = GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true)) == 1) {
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01535 switch (rd.x & 0x3) {
01536 default: NOT_REACHED();
01537 case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01538 case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01539 case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01540 case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01541 }
01542 } else {
01543 if (IsRoadVehFront(v)) {
01544
01545 dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01546 } else {
01547 dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01548 }
01549 }
01550
01551 if (dir == INVALID_TRACKDIR) {
01552 v->cur_speed = 0;
01553 return false;
01554 }
01555
01556 const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01557
01558 int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01559 int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01560
01561 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01562 if (IsRoadVehFront(v) && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01563
01564 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01565 if (HasBit(r, VETS_CANNOT_ENTER)) {
01566 v->cur_speed = 0;
01567 return false;
01568 }
01569
01570 v->u.road.state = dir;
01571 v->u.road.frame = turn_around_start_frame;
01572
01573 if (new_dir != v->direction) {
01574 v->direction = new_dir;
01575 v->cur_speed -= v->cur_speed >> 2;
01576 }
01577
01578 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01579 return true;
01580 }
01581
01582
01583
01584
01585 if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01586 if (v->u.road.frame == v->u.road.cached_veh_length + RVC_DEPOT_START_FRAME) {
01587 RoadVehLeaveDepot(v->Next(), false);
01588 }
01589 }
01590
01591
01592 int x = (v->x_pos & ~15) + (rd.x & 15);
01593 int y = (v->y_pos & ~15) + (rd.y & 15);
01594
01595 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01596
01597 if (IsRoadVehFront(v) && !IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01598
01599
01600 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01601
01602 if (u != NULL) {
01603 u = u->First();
01604
01605 if (v->u.road.overtaking == 0) RoadVehCheckOvertake(v, u);
01606 if (v->u.road.overtaking == 0) v->cur_speed = u->cur_speed;
01607 return false;
01608 }
01609 }
01610
01611 Direction old_dir = v->direction;
01612 if (new_dir != old_dir) {
01613 v->direction = new_dir;
01614 v->cur_speed -= (v->cur_speed >> 2);
01615 if (old_dir != v->u.road.state) {
01616
01617 SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
01618
01619
01620
01621 return true;
01622 }
01623 }
01624
01625
01626
01627
01628
01629
01630 if (IsRoadVehFront(v) && ((IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01631 _road_veh_data_1[v->u.road.state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->u.road.frame) ||
01632 (IsInsideMM(v->u.road.state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01633 v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01634 v->owner == GetTileOwner(v->tile) &&
01635 GetRoadStopType(v->tile) == (IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01636 v->u.road.frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01637
01638 RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
01639 Station *st = GetStationByTile(v->tile);
01640
01641
01642
01643
01644 if (!v->current_order.IsType(OT_LEAVESTATION)) {
01645
01646
01647 if (IsDriveThroughStopTile(v->tile)) {
01648 TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01649 RoadStopType type = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK;
01650
01651
01652 if (IsDriveThroughStopTile(next_tile) && (GetRoadStopType(next_tile) == type) && GetStationIndex(v->tile) == GetStationIndex(next_tile)) {
01653 RoadStop *rs_n = GetRoadStopByTile(next_tile, type);
01654
01655 if (rs_n->IsFreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY)) && rs_n->num_vehicles < RoadStop::MAX_VEHICLES) {
01656
01657 ClearSlot(v);
01658 rs_n->num_vehicles++;
01659 v->u.road.slot = rs_n;
01660 v->dest_tile = rs_n->xy;
01661 v->u.road.slot_age = 14;
01662
01663 v->u.road.frame++;
01664 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false));
01665 return true;
01666 }
01667 }
01668 }
01669
01670 rs->SetEntranceBusy(false);
01671
01672 v->last_station_visited = st->index;
01673
01674 if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01675 RoadVehArrivesAt(v, st);
01676 v->BeginLoading();
01677 return false;
01678 }
01679 } else {
01680
01681 if (rs->IsEntranceBusy()) {
01682
01683 v->cur_speed = 0;
01684 return false;
01685 }
01686 v->current_order.Free();
01687 ClearSlot(v);
01688 }
01689
01690 if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01691
01692 if (rs == v->u.road.slot) {
01693
01694 ClearSlot(v);
01695 } else if (v->u.road.slot != NULL) {
01696
01697
01698
01699 DEBUG(ms, 0, "Vehicle %d (index %d) arrived at wrong stop", v->unitnumber, v->index);
01700 if (v->tile != v->dest_tile) {
01701 DEBUG(ms, 2, " current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
01702 }
01703 if (v->dest_tile != v->u.road.slot->xy) {
01704 DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->u.road.slot->xy, v->dest_tile);
01705 }
01706 if (!v->current_order.IsType(OT_GOTO_STATION)) {
01707 DEBUG(ms, 2, " current order type (%d) is not OT_GOTO_STATION", v->current_order.GetType());
01708 } else {
01709 if (v->current_order.GetDestination() != st->index)
01710 DEBUG(ms, 2, " current station %d is not target station in current_order.station (%d)",
01711 st->index, v->current_order.GetDestination());
01712 }
01713
01714 DEBUG(ms, 2, " force a slot clearing");
01715 ClearSlot(v);
01716 }
01717
01718 StartRoadVehSound(v);
01719 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01720 }
01721
01722
01723
01724 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01725 if (HasBit(r, VETS_CANNOT_ENTER)) {
01726 v->cur_speed = 0;
01727 return false;
01728 }
01729
01730 if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01731 v->current_order.Free();
01732 ClearSlot(v);
01733 }
01734
01735
01736
01737 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->u.road.frame++;
01738
01739 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01740 return true;
01741 }
01742
01743 static void RoadVehController(Vehicle *v)
01744 {
01745
01746 v->tick_counter++;
01747 v->current_order_time++;
01748 if (v->u.road.reverse_ctr != 0) v->u.road.reverse_ctr--;
01749
01750
01751 if (v->vehstatus & VS_CRASHED) {
01752 RoadVehIsCrashed(v);
01753 return;
01754 }
01755
01756 RoadVehCheckTrainCrash(v);
01757
01758
01759 if (v->breakdown_ctr != 0) {
01760 if (v->breakdown_ctr <= 2) {
01761 HandleBrokenRoadVeh(v);
01762 return;
01763 }
01764 if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
01765 }
01766
01767 if (v->vehstatus & VS_STOPPED) return;
01768
01769 ProcessOrders(v);
01770 v->HandleLoading();
01771
01772 if (v->current_order.IsType(OT_LOADING)) return;
01773
01774 if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return;
01775
01776
01777 int j = RoadVehAccelerate(v);
01778
01779 int adv_spd = (v->direction & 1) ? 192 : 256;
01780 while (j >= adv_spd) {
01781 j -= adv_spd;
01782
01783 Vehicle *u = v;
01784 for (Vehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01785 if (!IndividualRoadVehicleController(u, prev)) break;
01786 }
01787
01788
01789 adv_spd = (v->direction & 1) ? 192 : 256;
01790
01791
01792 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01793 }
01794
01795 for (Vehicle *u = v; u != NULL; u = u->Next()) {
01796 if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01797
01798 u->UpdateViewport(false, false);
01799 }
01800
01801 if (v->progress == 0) v->progress = j;
01802 }
01803
01804 static void AgeRoadVehCargo(Vehicle *v)
01805 {
01806 if (_age_cargo_skip_counter != 0) return;
01807 v->cargo.AgeCargo();
01808 }
01809
01810 void RoadVehicle::Tick()
01811 {
01812 AgeRoadVehCargo(this);
01813
01814 if (IsRoadVehFront(this)) {
01815 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01816 RoadVehController(this);
01817 }
01818 }
01819
01820 static void CheckIfRoadVehNeedsService(Vehicle *v)
01821 {
01822
01823 if (v->u.road.slot != NULL || _settings_game.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01824 if (v->IsInDepot()) {
01825 VehicleServiceInDepot(v);
01826 return;
01827 }
01828
01829
01830 const Depot *depot = FindClosestRoadDepot(v);
01831
01832 if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
01833 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01834 v->current_order.MakeDummy();
01835 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01836 }
01837 return;
01838 }
01839
01840 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01841 v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01842 !Chance16(1, 20)) {
01843 return;
01844 }
01845
01846 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01847 ClearSlot(v);
01848
01849 v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
01850 v->dest_tile = depot->xy;
01851 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01852 }
01853
01854 void RoadVehicle::OnNewDay()
01855 {
01856 if (!IsRoadVehFront(this)) return;
01857
01858 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01859 if (this->u.road.blocked_ctr == 0) CheckVehicleBreakdown(this);
01860
01861 AgeVehicle(this);
01862 CheckIfRoadVehNeedsService(this);
01863
01864 CheckOrders(this);
01865
01866
01867 if (this->current_order.IsType(OT_GOTO_STATION) && this->u.road.slot != NULL && this->u.road.slot_age-- == 0) {
01868 DEBUG(ms, 3, "Slot expired for vehicle %d (index %d) at stop 0x%X",
01869 this->unitnumber, this->index, this->u.road.slot->xy);
01870 ClearSlot(this);
01871 }
01872
01873
01874 if (!(this->vehstatus & VS_STOPPED) && this->current_order.IsType(OT_GOTO_STATION) && !(this->current_order.GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) && this->u.road.slot == NULL && !(this->vehstatus & VS_CRASHED)) {
01875 Station *st = GetStation(this->current_order.GetDestination());
01876 RoadStop *rs = st->GetPrimaryRoadStop(this);
01877 RoadStop *best = NULL;
01878
01879 if (rs != NULL) {
01880
01881
01882
01883
01884
01885
01886 if (DistanceManhattan(this->tile, rs->xy) < 16 || st->rect.PtInExtendedRect(TileX(this->tile), TileY(this->tile), 2)) {
01887 uint dist, badness;
01888 uint minbadness = UINT_MAX;
01889
01890 DEBUG(ms, 2, "Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%X)",
01891 this->unitnumber, this->index, st->index, st->xy
01892 );
01893
01894 for (; rs != NULL; rs = rs->GetNextRoadStop(this)) {
01895 if (rs->num_vehicles >= RoadStop::MAX_VEHICLES) {
01896 DEBUG(ms, 4, " stop 0x%X's queue is full, not treating further", rs->xy);
01897 continue;
01898 }
01899 dist = RoadFindPathToStop(this, rs->xy);
01900 if (dist == UINT_MAX) {
01901 DEBUG(ms, 4, " stop 0x%X is unreachable, not treating further", rs->xy);
01902 continue;
01903 }
01904 badness = (rs->num_vehicles + 1) * (rs->num_vehicles + 1) + dist;
01905
01906 DEBUG(ms, 4, " stop 0x%X has %d vehicle%s waiting", rs->xy, rs->num_vehicles, rs->num_vehicles == 1 ? "":"s");
01907 DEBUG(ms, 4, " distance is %u", dist);
01908 DEBUG(ms, 4, " badness %u", badness);
01909
01910 if (badness < minbadness) {
01911 best = rs;
01912 minbadness = badness;
01913 }
01914 }
01915
01916 if (best != NULL) {
01917 best->num_vehicles++;
01918 DEBUG(ms, 3, "Assigned to stop 0x%X", best->xy);
01919
01920 this->u.road.slot = best;
01921 this->dest_tile = best->xy;
01922 this->u.road.slot_age = 14;
01923 } else {
01924 DEBUG(ms, 3, "Could not find a suitable stop");
01925 }
01926 } else {
01927 DEBUG(ms, 5, "Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%X)",
01928 this->unitnumber, this->index, st->index, st->xy);
01929 }
01930 } else {
01931 DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)",
01932 this->unitnumber, this->index, st->index, st->xy);
01933 }
01934 }
01935
01936 if (this->running_ticks == 0) return;
01937
01938 CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01939
01940 this->profit_this_year -= cost.GetCost();
01941 this->running_ticks = 0;
01942
01943 SubtractMoneyFromCompanyFract(this->owner, cost);
01944
01945 InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
01946 InvalidateWindowClasses(WC_ROADVEH_LIST);
01947 }
01948
01959 CommandCost CmdRefitRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01960 {
01961 Vehicle *v;
01962 CommandCost cost(EXPENSES_ROADVEH_RUN);
01963 CargoID new_cid = GB(p2, 0, 8);
01964 byte new_subtype = GB(p2, 8, 8);
01965 bool only_this = HasBit(p2, 16);
01966 uint16 capacity = CALLBACK_FAILED;
01967 uint total_capacity = 0;
01968
01969 if (!IsValidVehicleID(p1)) return CMD_ERROR;
01970
01971 v = GetVehicle(p1);
01972
01973 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
01974 if (!v->IsStoppedInDepot()) return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
01975 if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE);
01976
01977 if (new_cid >= NUM_CARGO) return CMD_ERROR;
01978
01979 for (; v != NULL; v = (only_this ? NULL : v->Next())) {
01980
01981
01982
01983 if (!CanRefitTo(v->engine_type, new_cid)) continue;
01984
01985 const Engine *e = GetEngine(v->engine_type);
01986 if (!e->CanCarryCargo()) continue;
01987
01988 if (HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_REFIT_CAPACITY)) {
01989
01990 CargoID temp_cid = v->cargo_type;
01991 byte temp_subtype = v->cargo_subtype;
01992 v->cargo_type = new_cid;
01993 v->cargo_subtype = new_subtype;
01994
01995
01996 capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
01997
01998
01999 v->cargo_type = temp_cid;
02000 v->cargo_subtype = temp_subtype;
02001 }
02002
02003 if (capacity == CALLBACK_FAILED) {
02004
02005
02006 CargoID old_cid = e->GetDefaultCargoType();
02007
02008
02009
02010
02011 capacity = GetVehicleProperty(v, 0x0F, e->u.road.capacity);
02012 switch (old_cid) {
02013 case CT_PASSENGERS: break;
02014 case CT_MAIL:
02015 case CT_GOODS: capacity *= 2; break;
02016 default: capacity *= 4; break;
02017 }
02018 switch (new_cid) {
02019 case CT_PASSENGERS: break;
02020 case CT_MAIL:
02021 case CT_GOODS: capacity /= 2; break;
02022 default: capacity /= 4; break;
02023 }
02024 }
02025
02026 total_capacity += capacity;
02027
02028 if (new_cid != v->cargo_type) {
02029 cost.AddCost(GetRefitCost(v->engine_type));
02030 }
02031
02032 if (flags & DC_EXEC) {
02033 v->cargo_cap = capacity;
02034 v->cargo.Truncate((v->cargo_type == new_cid) ? capacity : 0);
02035 v->cargo_type = new_cid;
02036 v->cargo_subtype = new_subtype;
02037 InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
02038 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
02039 InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
02040 }
02041 }
02042
02043 if (flags & DC_EXEC) RoadVehUpdateCache(GetVehicle(p1)->First());
02044
02045 _returned_refit_capacity = total_capacity;
02046
02047 return cost;
02048 }