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 v->MarkDirty();
00655
00656 if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
00657 SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
00658 SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
00659 }
00660
00661 if (!(v->vehstatus & VS_HIDDEN)) {
00662 Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
00663 if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2;
00664 }
00665 }
00666
00667 if ((v->tick_counter & 1) == 0) {
00668 if (--v->breakdown_delay == 0) {
00669 v->breakdown_ctr = 0;
00670 InvalidateWindow(WC_VEHICLE_VIEW, v->index);
00671 v->MarkDirty();
00672 }
00673 }
00674 }
00675
00676 TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
00677 {
00678 if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
00679
00680 TileIndex dest;
00681 if (YapfFindNearestRoadVehicleCompatibleStop(this, station, &dest)) {
00682 return dest;
00683 } else {
00684
00685 this->cur_order_index++;
00686 return 0;
00687 }
00688 }
00689
00690 static void StartRoadVehSound(const Vehicle *v)
00691 {
00692 if (!PlayVehicleSound(v, VSE_START)) {
00693 SoundFx s = RoadVehInfo(v->engine_type)->sfx;
00694 if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
00695 s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
00696 SndPlayVehicleFx(s, v);
00697 }
00698 }
00699
00700 struct RoadVehFindData {
00701 int x;
00702 int y;
00703 const Vehicle *veh;
00704 Vehicle *best;
00705 uint best_diff;
00706 Direction dir;
00707 };
00708
00709 static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
00710 {
00711 static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
00712 static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
00713
00714 RoadVehFindData *rvf = (RoadVehFindData*)data;
00715
00716 short x_diff = v->x_pos - rvf->x;
00717 short y_diff = v->y_pos - rvf->y;
00718
00719 if (v->type == VEH_ROAD &&
00720 !v->IsInDepot() &&
00721 abs(v->z_pos - rvf->veh->z_pos) < 6 &&
00722 v->direction == rvf->dir &&
00723 rvf->veh->First() != v->First() &&
00724 (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
00725 (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
00726 (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
00727 (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
00728 uint diff = abs(x_diff) + abs(y_diff);
00729
00730 if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
00731 rvf->best = v;
00732 rvf->best_diff = diff;
00733 }
00734 }
00735
00736 return NULL;
00737 }
00738
00739 static Vehicle *RoadVehFindCloseTo(Vehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
00740 {
00741 RoadVehFindData rvf;
00742 Vehicle *front = v->First();
00743
00744 if (front->u.road.reverse_ctr != 0) return NULL;
00745
00746 rvf.x = x;
00747 rvf.y = y;
00748 rvf.dir = dir;
00749 rvf.veh = v;
00750 rvf.best_diff = UINT_MAX;
00751
00752 if (front->u.road.state == RVSB_WORMHOLE) {
00753 FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
00754 FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
00755 } else {
00756 FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
00757 }
00758
00759
00760
00761
00762
00763 if (rvf.best_diff == UINT_MAX) {
00764 front->u.road.blocked_ctr = 0;
00765 return NULL;
00766 }
00767
00768 if (update_blocked_ctr && ++front->u.road.blocked_ctr > 1480) return NULL;
00769
00770 return rvf.best;
00771 }
00772
00773 static void RoadVehArrivesAt(const Vehicle *v, Station *st)
00774 {
00775 if (IsCargoInClass(v->cargo_type, CC_PASSENGERS)) {
00776
00777 if (!(st->had_vehicle_of_type & HVOT_BUS)) {
00778 st->had_vehicle_of_type |= HVOT_BUS;
00779 SetDParam(0, st->index);
00780 AddNewsItem(
00781 v->u.road.roadtype == ROADTYPE_ROAD ? STR_902F_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_PASSENGER_TRAM,
00782 (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00783 v->index,
00784 st->index
00785 );
00786 AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00787 }
00788 } else {
00789
00790 if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
00791 st->had_vehicle_of_type |= HVOT_TRUCK;
00792 SetDParam(0, st->index);
00793 AddNewsItem(
00794 v->u.road.roadtype == ROADTYPE_ROAD ? STR_9030_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_CARGO_TRAM,
00795 (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00796 v->index,
00797 st->index
00798 );
00799 AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00800 }
00801 }
00802 }
00803
00804 static int RoadVehAccelerate(Vehicle *v)
00805 {
00806 uint oldspeed = v->cur_speed;
00807 uint accel = 256 + (v->u.road.overtaking != 0 ? 256 : 0);
00808 uint spd = v->subspeed + accel;
00809
00810 v->subspeed = (uint8)spd;
00811
00812 int tempmax = v->max_speed;
00813 if (v->cur_speed > v->max_speed) {
00814 tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
00815 }
00816
00817 v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
00818
00819
00820 if (v->u.road.state == RVSB_WORMHOLE && !(v->vehstatus & VS_HIDDEN)) {
00821 v->cur_speed = min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
00822 }
00823
00824
00825 if (oldspeed != v->cur_speed) {
00826 if (_settings_client.gui.vehicle_speed) {
00827 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00828 }
00829 }
00830
00831
00832 int scaled_spd = spd * 3 >> 2;
00833
00834 scaled_spd += v->progress;
00835 v->progress = 0;
00836 return scaled_spd;
00837 }
00838
00839 static Direction RoadVehGetNewDirection(const Vehicle *v, int x, int y)
00840 {
00841 static const Direction _roadveh_new_dir[] = {
00842 DIR_N , DIR_NW, DIR_W , INVALID_DIR,
00843 DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
00844 DIR_E , DIR_SE, DIR_S
00845 };
00846
00847 x = x - v->x_pos + 1;
00848 y = y - v->y_pos + 1;
00849
00850 if ((uint)x > 2 || (uint)y > 2) return v->direction;
00851 return _roadveh_new_dir[y * 4 + x];
00852 }
00853
00854 static Direction RoadVehGetSlidingDirection(const Vehicle *v, int x, int y)
00855 {
00856 Direction new_dir = RoadVehGetNewDirection(v, x, y);
00857 Direction old_dir = v->direction;
00858 DirDiff delta;
00859
00860 if (new_dir == old_dir) return old_dir;
00861 delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
00862 return ChangeDir(old_dir, delta);
00863 }
00864
00865 struct OvertakeData {
00866 const Vehicle *u;
00867 const Vehicle *v;
00868 TileIndex tile;
00869 Trackdir trackdir;
00870 };
00871
00872 static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
00873 {
00874 const OvertakeData *od = (OvertakeData*)data;
00875
00876 return
00877 v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v ?
00878 v : NULL;
00879 }
00880
00887 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
00888 {
00889 TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->u.road.compatible_roadtypes);
00890 TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
00891 TrackdirBits red_signals = TrackStatusToRedSignals(ts);
00892 TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00893
00894
00895 if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00896
00897
00898 return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
00899 }
00900
00901 static void RoadVehCheckOvertake(Vehicle *v, Vehicle *u)
00902 {
00903 OvertakeData od;
00904
00905 od.v = v;
00906 od.u = u;
00907
00908 if (u->max_speed >= v->max_speed &&
00909 !(u->vehstatus & VS_STOPPED) &&
00910 u->cur_speed != 0) {
00911 return;
00912 }
00913
00914
00915 if (v->u.road.roadtype == ROADTYPE_TRAM) return;
00916
00917
00918 if (IsTileType(v->tile, MP_STATION)) return;
00919
00920
00921 if (RoadVehHasArticPart(v)) return;
00922
00923
00924 if (v->direction != u->direction || !(v->direction & 1)) return;
00925
00926
00927 if (v->u.road.state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->u.road.state & RVSB_TRACKDIR_MASK))) return;
00928
00929 od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
00930
00931
00932
00933
00934
00935
00936
00937 od.tile = v->tile;
00938 if (CheckRoadBlockedForOvertaking(&od)) return;
00939
00940 od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
00941 if (CheckRoadBlockedForOvertaking(&od)) return;
00942
00943 if (od.u->cur_speed == 0 || od.u->vehstatus& VS_STOPPED) {
00944 v->u.road.overtaking_ctr = 0x11;
00945 v->u.road.overtaking = 0x10;
00946 } else {
00947
00948 v->u.road.overtaking_ctr = 0;
00949 v->u.road.overtaking = 0x10;
00950 }
00951 }
00952
00953 static void RoadZPosAffectSpeed(Vehicle *v, byte old_z)
00954 {
00955 if (old_z == v->z_pos) return;
00956
00957 if (old_z < v->z_pos) {
00958 v->cur_speed = v->cur_speed * 232 / 256;
00959 } else {
00960 uint16 spd = v->cur_speed + 2;
00961 if (spd <= v->max_speed) v->cur_speed = spd;
00962 }
00963 }
00964
00965 static int PickRandomBit(uint bits)
00966 {
00967 uint i;
00968 uint num = RandomRange(CountBits(bits));
00969
00970 for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
00971 return i;
00972 }
00973
00974 struct FindRoadToChooseData {
00975 TileIndex dest;
00976 uint maxtracklen;
00977 uint mindist;
00978 };
00979
00980 static bool EnumRoadTrackFindDist(TileIndex tile, void *data, Trackdir trackdir, uint length)
00981 {
00982 FindRoadToChooseData *frd = (FindRoadToChooseData*)data;
00983 uint dist = DistanceManhattan(tile, frd->dest);
00984
00985 if (dist <= frd->mindist) {
00986 if (dist != frd->mindist || length < frd->maxtracklen) {
00987 frd->maxtracklen = length;
00988 }
00989 frd->mindist = dist;
00990 }
00991 return false;
00992 }
00993
00994 static inline NPFFoundTargetData PerfNPFRouteToStationOrTile(TileIndex tile, Trackdir trackdir, bool ignore_start_tile, NPFFindStationOrTileData *target, TransportType type, uint sub_type, Owner owner, RailTypes railtypes)
00995 {
00996
00997 void *perf = NpfBeginInterval();
00998 NPFFoundTargetData ret = NPFRouteToStationOrTile(tile, trackdir, ignore_start_tile, target, type, sub_type, owner, railtypes);
00999 int t = NpfEndInterval(perf);
01000 DEBUG(yapf, 4, "[NPFR] %d us - %d rounds - %d open - %d closed -- ", t, 0, _aystar_stats_open_size, _aystar_stats_closed_size);
01001 return ret;
01002 }
01003
01012 static Trackdir RoadFindPathToDest(Vehicle *v, TileIndex tile, DiagDirection enterdir)
01013 {
01014 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
01015
01016 TileIndex desttile;
01017 FindRoadToChooseData frd;
01018 Trackdir best_track;
01019
01020 TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->u.road.compatible_roadtypes);
01021 TrackdirBits red_signals = TrackStatusToRedSignals(ts);
01022 TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
01023
01024 if (IsTileType(tile, MP_ROAD)) {
01025 if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->u.road.compatible_roadtypes) == 0)) {
01026
01027 trackdirs = TRACKDIR_BIT_NONE;
01028 }
01029 } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
01030
01031
01032 if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || RoadVehHasArticPart(v)) {
01033
01034 trackdirs = TRACKDIR_BIT_NONE;
01035 } else {
01036
01037 RoadStopType rstype = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK;
01038
01039 if (GetRoadStopType(tile) != rstype) {
01040
01041 trackdirs = TRACKDIR_BIT_NONE;
01042 } else {
01043
01044 if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) &&
01045 !GetRoadStopByTile(tile, rstype)->HasFreeBay()) {
01046
01047 trackdirs = TRACKDIR_BIT_NONE;
01048 }
01049 }
01050 }
01051 }
01052
01053
01054
01055
01056
01057
01058 trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
01059 if (trackdirs == TRACKDIR_BIT_NONE) {
01060
01061 return_track(_road_reverse_table[enterdir]);
01062 }
01063
01064 if (v->u.road.reverse_ctr != 0) {
01065 bool reverse = true;
01066 if (v->u.road.roadtype == ROADTYPE_TRAM) {
01067
01068
01069 RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM);
01070 RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
01071 reverse = ((rb & straight) == straight) ||
01072 (rb == DiagDirToRoadBits(enterdir));
01073 }
01074 if (reverse) {
01075 v->u.road.reverse_ctr = 0;
01076 if (v->tile != tile) {
01077 return_track(_road_reverse_table[enterdir]);
01078 }
01079 }
01080 }
01081
01082 desttile = v->dest_tile;
01083 if (desttile == 0) {
01084
01085 return_track(PickRandomBit(trackdirs));
01086 }
01087
01088
01089 if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) {
01090 return_track(FindFirstBit2x64(trackdirs));
01091 }
01092
01093 switch (_settings_game.pf.pathfinder_for_roadvehs) {
01094 case VPF_YAPF: {
01095 Trackdir trackdir = YapfChooseRoadTrack(v, tile, enterdir);
01096 if (trackdir != INVALID_TRACKDIR) return_track(trackdir);
01097 return_track(PickRandomBit(trackdirs));
01098 } break;
01099
01100 case VPF_NPF: {
01101 NPFFindStationOrTileData fstd;
01102
01103 NPFFillWithOrderData(&fstd, v);
01104 Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
01105
01106
01107 NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES);
01108 if (ftd.best_trackdir == INVALID_TRACKDIR) {
01109
01110
01111
01112 return_track(FindFirstBit2x64(trackdirs));
01113 } else {
01114
01115
01116
01117
01118 return_track(ftd.best_trackdir);
01119 }
01120 } break;
01121
01122 default:
01123 case VPF_OPF: {
01124 DiagDirection dir;
01125
01126 if (IsTileType(desttile, MP_ROAD)) {
01127 if (IsRoadDepot(desttile)) {
01128 dir = GetRoadDepotDirection(desttile);
01129 goto do_it;
01130 }
01131 } else if (IsTileType(desttile, MP_STATION)) {
01132
01133 if (IsStandardRoadStopTile(desttile)) {
01134 dir = GetRoadStopDir(desttile);
01135 do_it:;
01136
01137
01138
01139 desttile += TileOffsByDiagDir(dir);
01140 if (desttile == tile && trackdirs & _road_exit_dir_to_incoming_trackdirs[dir]) {
01141
01142
01143
01144 return_track(FindFirstBit2x64(trackdirs & _road_exit_dir_to_incoming_trackdirs[dir]));
01145 }
01146 }
01147 }
01148
01149 frd.dest = desttile;
01150
01151 best_track = INVALID_TRACKDIR;
01152 uint best_dist = UINT_MAX;
01153 uint best_maxlen = UINT_MAX;
01154 uint bitmask = (uint)trackdirs;
01155 uint i;
01156 FOR_EACH_SET_BIT(i, bitmask) {
01157 if (best_track == INVALID_TRACKDIR) best_track = (Trackdir)i;
01158 frd.maxtracklen = UINT_MAX;
01159 frd.mindist = UINT_MAX;
01160 FollowTrack(tile, PATHFIND_FLAGS_NONE, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, _road_pf_directions[i], EnumRoadTrackFindDist, NULL, &frd);
01161
01162 if (frd.mindist < best_dist || (frd.mindist == best_dist && frd.maxtracklen < best_maxlen)) {
01163 best_dist = frd.mindist;
01164 best_maxlen = frd.maxtracklen;
01165 best_track = (Trackdir)i;
01166 }
01167 }
01168 } break;
01169 }
01170
01171 found_best_track:;
01172
01173 if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR;
01174
01175 return best_track;
01176 }
01177
01178 static uint RoadFindPathToStop(const Vehicle *v, TileIndex tile)
01179 {
01180 if (_settings_game.pf.pathfinder_for_roadvehs == VPF_YAPF) {
01181
01182 return YapfRoadVehDistanceToTile(v, tile);
01183 }
01184
01185
01186 Trackdir trackdir = GetVehicleTrackdir(v);
01187 assert(trackdir != INVALID_TRACKDIR);
01188
01189 NPFFindStationOrTileData fstd;
01190 fstd.dest_coords = tile;
01191 fstd.station_index = INVALID_STATION;
01192
01193 uint dist = NPFRouteToStationOrTile(v->tile, trackdir, false, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES).best_path_dist;
01194
01195 if (dist != UINT_MAX) dist = (dist + NPF_TILE_LENGTH - 1) / NPF_TILE_LENGTH;
01196
01197 return dist;
01198 }
01199
01200 struct RoadDriveEntry {
01201 byte x, y;
01202 };
01203
01204 #include "table/roadveh_movement.h"
01205
01206 static const byte _road_veh_data_1[] = {
01207 20, 20, 16, 16, 0, 0, 0, 0,
01208 19, 19, 15, 15, 0, 0, 0, 0,
01209 16, 16, 12, 12, 0, 0, 0, 0,
01210 15, 15, 11, 11
01211 };
01212
01213 static bool RoadVehLeaveDepot(Vehicle *v, bool first)
01214 {
01215
01216 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01217 if (u->u.road.state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
01218 }
01219
01220 DiagDirection dir = GetRoadDepotDirection(v->tile);
01221 v->direction = DiagDirToDir(dir);
01222
01223 Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
01224 const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
01225
01226 int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
01227 int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
01228
01229 if (first) {
01230 if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
01231
01232 VehicleServiceInDepot(v);
01233
01234 StartRoadVehSound(v);
01235
01236
01237 v->cur_speed = 0;
01238 }
01239
01240 v->vehstatus &= ~VS_HIDDEN;
01241 v->u.road.state = tdir;
01242 v->u.road.frame = RVC_DEPOT_START_FRAME;
01243
01244 SetRoadVehPosition(v, x, y, true);
01245
01246 InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01247
01248 return true;
01249 }
01250
01251 static Trackdir FollowPreviousRoadVehicle(const Vehicle *v, const Vehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
01252 {
01253 if (prev->tile == v->tile && !already_reversed) {
01254
01255
01256 return _road_reverse_table[entry_dir];
01257 }
01258
01259 byte prev_state = prev->u.road.state;
01260 Trackdir dir;
01261
01262 if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
01263 DiagDirection diag_dir = INVALID_DIAGDIR;
01264
01265 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01266 diag_dir = GetTunnelBridgeDirection(tile);
01267 } else if (IsRoadDepotTile(tile)) {
01268 diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
01269 }
01270
01271 if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
01272 dir = DiagDirToDiagTrackdir(diag_dir);
01273 } else {
01274 if (already_reversed && prev->tile != tile) {
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290 Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01291 { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N, TRACKDIR_UPPER_E },
01292 { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S }};
01293 dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01294 } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01295 dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01296 } else if (prev_state < TRACKDIR_END) {
01297 dir = (Trackdir)prev_state;
01298 } else {
01299 return INVALID_TRACKDIR;
01300 }
01301 }
01302
01303
01304 static const RoadBits required_roadbits[] = {
01305 ROAD_X, ROAD_Y, ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01306 ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X, ROAD_Y
01307 };
01308 RoadBits required = required_roadbits[dir & 0x07];
01309
01310 if ((required & GetAnyRoadBits(tile, v->u.road.roadtype, true)) == ROAD_NONE) {
01311 dir = INVALID_TRACKDIR;
01312 }
01313
01314 return dir;
01315 }
01316
01324 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01325 {
01326
01327 CompanyID original_company = _current_company;
01328 _current_company = c;
01329
01330 CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01331
01332 _current_company = original_company;
01333 return CmdSucceeded(ret);
01334 }
01335
01336 static bool IndividualRoadVehicleController(Vehicle *v, const Vehicle *prev)
01337 {
01338 if (v->u.road.overtaking != 0) {
01339 if (IsTileType(v->tile, MP_STATION)) {
01340
01341 v->u.road.overtaking = 0;
01342 } else if (++v->u.road.overtaking_ctr >= 35) {
01343
01344
01345
01346 if (v->u.road.state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->u.road.state)) {
01347 v->u.road.overtaking = 0;
01348 }
01349 }
01350 }
01351
01352
01353
01354
01355 if (v->IsInDepot()) return true;
01356
01357 if (v->u.road.state == RVSB_WORMHOLE) {
01358
01359 GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01360
01361 if (IsRoadVehFront(v)) {
01362 const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01363 if (u != NULL) {
01364 v->cur_speed = u->First()->cur_speed;
01365 return false;
01366 }
01367 }
01368
01369 if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01370
01371 SetRoadVehPosition(v, gp.x, gp.y, true);
01372 return true;
01373 }
01374
01375 v->x_pos = gp.x;
01376 v->y_pos = gp.y;
01377 VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01378 return true;
01379 }
01380
01381
01382
01383
01384 RoadDriveEntry rd = _road_drive_data[v->u.road.roadtype][(
01385 (HasBit(v->u.road.state, RVS_IN_DT_ROAD_STOP) ? v->u.road.state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->u.road.state) +
01386 (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking][v->u.road.frame + 1];
01387
01388 if (rd.x & RDE_NEXT_TILE) {
01389 TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01390 Trackdir dir;
01391
01392 if (IsRoadVehFront(v)) {
01393
01394 dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01395 } else {
01396 dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01397 }
01398
01399 if (dir == INVALID_TRACKDIR) {
01400 if (!IsRoadVehFront(v)) error("Disconnecting road vehicle.");
01401 v->cur_speed = 0;
01402 return false;
01403 }
01404
01405 again:
01406 uint start_frame = RVC_DEFAULT_START_FRAME;
01407 if (IsReversingRoadTrackdir(dir)) {
01408
01409 if (v->u.road.roadtype == ROADTYPE_TRAM) {
01410
01411
01412 RoadBits needed;
01413 switch (dir) {
01414 default: NOT_REACHED();
01415 case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01416 case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01417 case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01418 case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01419 }
01420 if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01421 (IsRoadVehFront(v) && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01422 (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 } else if (!IsRoadVehFront(v) || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445 tile = v->tile;
01446 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01447 } else {
01448
01449 v->cur_speed = 0;
01450 return false;
01451 }
01452 } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01453 v->cur_speed = 0;
01454 return false;
01455 } else {
01456 tile = v->tile;
01457 }
01458 }
01459
01460
01461 const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->u.road.overtaking];
01462
01463 int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01464 int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01465
01466 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01467 if (IsRoadVehFront(v)) {
01468 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01469 if (u != NULL) {
01470 v->cur_speed = u->First()->cur_speed;
01471 return false;
01472 }
01473 }
01474
01475 uint32 r = VehicleEnterTile(v, tile, x, y);
01476 if (HasBit(r, VETS_CANNOT_ENTER)) {
01477 if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01478 v->cur_speed = 0;
01479 return false;
01480 }
01481
01482 dir = _road_reverse_table[rd.x & 3];
01483 goto again;
01484 }
01485
01486 if (IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01487 if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01488
01489
01490 v->cur_speed = 0;
01491 return false;
01492 }
01493 if (IsRoadStop(v->tile)) {
01494 RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
01495
01496
01497
01498 if (IsStandardRoadStopTile(v->tile) || HasBit(v->u.road.state, RVS_IS_STOPPING)) {
01499 rs->FreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY));
01500 ClrBit(v->u.road.state, RVS_IS_STOPPING);
01501 }
01502 if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(false);
01503 }
01504 }
01505
01506 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01507 v->tile = tile;
01508 v->u.road.state = (byte)dir;
01509 v->u.road.frame = start_frame;
01510 }
01511 if (new_dir != v->direction) {
01512 v->direction = new_dir;
01513 v->cur_speed -= v->cur_speed >> 2;
01514 }
01515
01516 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01517 return true;
01518 }
01519
01520 if (rd.x & RDE_TURNED) {
01521
01522 Trackdir dir;
01523 uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01524
01525 RoadBits tram;
01526 if (v->u.road.roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && CountBits(tram = GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true)) == 1) {
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536 turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01537 switch (rd.x & 0x3) {
01538 default: NOT_REACHED();
01539 case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01540 case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01541 case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01542 case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01543 }
01544 } else {
01545 if (IsRoadVehFront(v)) {
01546
01547 dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01548 } else {
01549 dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01550 }
01551 }
01552
01553 if (dir == INVALID_TRACKDIR) {
01554 v->cur_speed = 0;
01555 return false;
01556 }
01557
01558 const RoadDriveEntry *rdp = _road_drive_data[v->u.road.roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01559
01560 int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01561 int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01562
01563 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01564 if (IsRoadVehFront(v) && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01565
01566 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01567 if (HasBit(r, VETS_CANNOT_ENTER)) {
01568 v->cur_speed = 0;
01569 return false;
01570 }
01571
01572 v->u.road.state = dir;
01573 v->u.road.frame = turn_around_start_frame;
01574
01575 if (new_dir != v->direction) {
01576 v->direction = new_dir;
01577 v->cur_speed -= v->cur_speed >> 2;
01578 }
01579
01580 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01581 return true;
01582 }
01583
01584
01585
01586
01587 if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01588 if (v->u.road.frame == v->u.road.cached_veh_length + RVC_DEPOT_START_FRAME) {
01589 RoadVehLeaveDepot(v->Next(), false);
01590 }
01591 }
01592
01593
01594 int x = (v->x_pos & ~15) + (rd.x & 15);
01595 int y = (v->y_pos & ~15) + (rd.y & 15);
01596
01597 Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01598
01599 if (IsRoadVehFront(v) && !IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01600
01601
01602 Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01603
01604 if (u != NULL) {
01605 u = u->First();
01606
01607 if (v->u.road.overtaking == 0) RoadVehCheckOvertake(v, u);
01608 if (v->u.road.overtaking == 0) v->cur_speed = u->cur_speed;
01609 return false;
01610 }
01611 }
01612
01613 Direction old_dir = v->direction;
01614 if (new_dir != old_dir) {
01615 v->direction = new_dir;
01616 v->cur_speed -= (v->cur_speed >> 2);
01617 if (old_dir != v->u.road.state) {
01618
01619 SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
01620
01621
01622
01623 return true;
01624 }
01625 }
01626
01627
01628
01629
01630
01631
01632 if (IsRoadVehFront(v) && ((IsInsideMM(v->u.road.state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01633 _road_veh_data_1[v->u.road.state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->u.road.frame) ||
01634 (IsInsideMM(v->u.road.state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01635 v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01636 v->owner == GetTileOwner(v->tile) &&
01637 GetRoadStopType(v->tile) == (IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01638 v->u.road.frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01639
01640 RoadStop *rs = GetRoadStopByTile(v->tile, GetRoadStopType(v->tile));
01641 Station *st = GetStationByTile(v->tile);
01642
01643
01644
01645
01646 if (!v->current_order.IsType(OT_LEAVESTATION)) {
01647
01648
01649 if (IsDriveThroughStopTile(v->tile)) {
01650 TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01651 RoadStopType type = IsCargoInClass(v->cargo_type, CC_PASSENGERS) ? ROADSTOP_BUS : ROADSTOP_TRUCK;
01652
01653
01654 if (IsDriveThroughStopTile(next_tile) && (GetRoadStopType(next_tile) == type) && GetStationIndex(v->tile) == GetStationIndex(next_tile)) {
01655 RoadStop *rs_n = GetRoadStopByTile(next_tile, type);
01656
01657 if (rs_n->IsFreeBay(HasBit(v->u.road.state, RVS_USING_SECOND_BAY)) && rs_n->num_vehicles < RoadStop::MAX_VEHICLES) {
01658
01659 ClearSlot(v);
01660 rs_n->num_vehicles++;
01661 v->u.road.slot = rs_n;
01662 v->dest_tile = rs_n->xy;
01663 v->u.road.slot_age = 14;
01664
01665 v->u.road.frame++;
01666 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false));
01667 return true;
01668 }
01669 }
01670 }
01671
01672 rs->SetEntranceBusy(false);
01673
01674 v->last_station_visited = st->index;
01675
01676 if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01677 RoadVehArrivesAt(v, st);
01678 v->BeginLoading();
01679 return false;
01680 }
01681 } else {
01682
01683 if (rs->IsEntranceBusy()) {
01684
01685 v->cur_speed = 0;
01686 return false;
01687 }
01688 v->current_order.Free();
01689 ClearSlot(v);
01690 }
01691
01692 if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01693
01694 if (rs == v->u.road.slot) {
01695
01696 ClearSlot(v);
01697 } else if (v->u.road.slot != NULL) {
01698
01699
01700
01701 DEBUG(ms, 0, "Vehicle %d (index %d) arrived at wrong stop", v->unitnumber, v->index);
01702 if (v->tile != v->dest_tile) {
01703 DEBUG(ms, 2, " current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
01704 }
01705 if (v->dest_tile != v->u.road.slot->xy) {
01706 DEBUG(ms, 2, " stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->u.road.slot->xy, v->dest_tile);
01707 }
01708 if (!v->current_order.IsType(OT_GOTO_STATION)) {
01709 DEBUG(ms, 2, " current order type (%d) is not OT_GOTO_STATION", v->current_order.GetType());
01710 } else {
01711 if (v->current_order.GetDestination() != st->index)
01712 DEBUG(ms, 2, " current station %d is not target station in current_order.station (%d)",
01713 st->index, v->current_order.GetDestination());
01714 }
01715
01716 DEBUG(ms, 2, " force a slot clearing");
01717 ClearSlot(v);
01718 }
01719
01720 StartRoadVehSound(v);
01721 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01722 }
01723
01724
01725
01726 uint32 r = VehicleEnterTile(v, v->tile, x, y);
01727 if (HasBit(r, VETS_CANNOT_ENTER)) {
01728 v->cur_speed = 0;
01729 return false;
01730 }
01731
01732 if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01733 v->current_order.Free();
01734 ClearSlot(v);
01735 }
01736
01737
01738
01739 if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->u.road.frame++;
01740
01741 RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01742 return true;
01743 }
01744
01745 static void RoadVehController(Vehicle *v)
01746 {
01747
01748 v->tick_counter++;
01749 v->current_order_time++;
01750 if (v->u.road.reverse_ctr != 0) v->u.road.reverse_ctr--;
01751
01752
01753 if (v->vehstatus & VS_CRASHED) {
01754 RoadVehIsCrashed(v);
01755 return;
01756 }
01757
01758 RoadVehCheckTrainCrash(v);
01759
01760
01761 if (v->breakdown_ctr != 0) {
01762 if (v->breakdown_ctr <= 2) {
01763 HandleBrokenRoadVeh(v);
01764 return;
01765 }
01766 if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
01767 }
01768
01769 if (v->vehstatus & VS_STOPPED) return;
01770
01771 ProcessOrders(v);
01772 v->HandleLoading();
01773
01774 if (v->current_order.IsType(OT_LOADING)) return;
01775
01776 if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return;
01777
01778
01779 int j = RoadVehAccelerate(v);
01780
01781 int adv_spd = (v->direction & 1) ? 192 : 256;
01782 while (j >= adv_spd) {
01783 j -= adv_spd;
01784
01785 Vehicle *u = v;
01786 for (Vehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01787 if (!IndividualRoadVehicleController(u, prev)) break;
01788 }
01789
01790
01791 adv_spd = (v->direction & 1) ? 192 : 256;
01792
01793
01794 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01795 }
01796
01797 for (Vehicle *u = v; u != NULL; u = u->Next()) {
01798 if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01799
01800 u->UpdateViewport(false, false);
01801 }
01802
01803 if (v->progress == 0) v->progress = j;
01804 }
01805
01806 static void AgeRoadVehCargo(Vehicle *v)
01807 {
01808 if (_age_cargo_skip_counter != 0) return;
01809 v->cargo.AgeCargo();
01810 }
01811
01812 void RoadVehicle::Tick()
01813 {
01814 AgeRoadVehCargo(this);
01815
01816 if (IsRoadVehFront(this)) {
01817 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01818 RoadVehController(this);
01819 }
01820 }
01821
01822 static void CheckIfRoadVehNeedsService(Vehicle *v)
01823 {
01824
01825 if (v->u.road.slot != NULL || _settings_game.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01826 if (v->IsInDepot()) {
01827 VehicleServiceInDepot(v);
01828 return;
01829 }
01830
01831
01832 const Depot *depot = FindClosestRoadDepot(v);
01833
01834 if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
01835 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01836 v->current_order.MakeDummy();
01837 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01838 }
01839 return;
01840 }
01841
01842 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01843 v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01844 !Chance16(1, 20)) {
01845 return;
01846 }
01847
01848 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01849 ClearSlot(v);
01850
01851 v->current_order.MakeGoToDepot(depot->index, ODTFB_SERVICE);
01852 v->dest_tile = depot->xy;
01853 InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01854 }
01855
01856 void RoadVehicle::OnNewDay()
01857 {
01858 if (!IsRoadVehFront(this)) return;
01859
01860 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01861 if (this->u.road.blocked_ctr == 0) CheckVehicleBreakdown(this);
01862
01863 AgeVehicle(this);
01864 CheckIfRoadVehNeedsService(this);
01865
01866 CheckOrders(this);
01867
01868
01869 if (this->current_order.IsType(OT_GOTO_STATION) && this->u.road.slot != NULL && this->u.road.slot_age-- == 0) {
01870 DEBUG(ms, 3, "Slot expired for vehicle %d (index %d) at stop 0x%X",
01871 this->unitnumber, this->index, this->u.road.slot->xy);
01872 ClearSlot(this);
01873 }
01874
01875
01876 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)) {
01877 Station *st = GetStation(this->current_order.GetDestination());
01878 RoadStop *rs = st->GetPrimaryRoadStop(this);
01879 RoadStop *best = NULL;
01880
01881 if (rs != NULL) {
01882
01883
01884
01885
01886
01887
01888 if (DistanceManhattan(this->tile, rs->xy) < 16 || st->rect.PtInExtendedRect(TileX(this->tile), TileY(this->tile), 2)) {
01889 uint dist, badness;
01890 uint minbadness = UINT_MAX;
01891
01892 DEBUG(ms, 2, "Attempting to obtain a slot for vehicle %d (index %d) at station %d (0x%X)",
01893 this->unitnumber, this->index, st->index, st->xy
01894 );
01895
01896 for (; rs != NULL; rs = rs->GetNextRoadStop(this)) {
01897 if (rs->num_vehicles >= RoadStop::MAX_VEHICLES) {
01898 DEBUG(ms, 4, " stop 0x%X's queue is full, not treating further", rs->xy);
01899 continue;
01900 }
01901 dist = RoadFindPathToStop(this, rs->xy);
01902 if (dist == UINT_MAX) {
01903 DEBUG(ms, 4, " stop 0x%X is unreachable, not treating further", rs->xy);
01904 continue;
01905 }
01906 badness = (rs->num_vehicles + 1) * (rs->num_vehicles + 1) + dist;
01907
01908 DEBUG(ms, 4, " stop 0x%X has %d vehicle%s waiting", rs->xy, rs->num_vehicles, rs->num_vehicles == 1 ? "":"s");
01909 DEBUG(ms, 4, " distance is %u", dist);
01910 DEBUG(ms, 4, " badness %u", badness);
01911
01912 if (badness < minbadness) {
01913 best = rs;
01914 minbadness = badness;
01915 }
01916 }
01917
01918 if (best != NULL) {
01919 best->num_vehicles++;
01920 DEBUG(ms, 3, "Assigned to stop 0x%X", best->xy);
01921
01922 this->u.road.slot = best;
01923 this->dest_tile = best->xy;
01924 this->u.road.slot_age = 14;
01925 } else {
01926 DEBUG(ms, 3, "Could not find a suitable stop");
01927 }
01928 } else {
01929 DEBUG(ms, 5, "Distance from station too far. Postponing slotting for vehicle %d (index %d) at station %d, (0x%X)",
01930 this->unitnumber, this->index, st->index, st->xy);
01931 }
01932 } else {
01933 DEBUG(ms, 4, "No road stop for vehicle %d (index %d) at station %d (0x%X)",
01934 this->unitnumber, this->index, st->index, st->xy);
01935 }
01936 }
01937
01938 if (this->running_ticks == 0) return;
01939
01940 CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01941
01942 this->profit_this_year -= cost.GetCost();
01943 this->running_ticks = 0;
01944
01945 SubtractMoneyFromCompanyFract(this->owner, cost);
01946
01947 InvalidateWindow(WC_VEHICLE_DETAILS, this->index);
01948 InvalidateWindowClasses(WC_ROADVEH_LIST);
01949 }
01950
01961 CommandCost CmdRefitRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01962 {
01963 Vehicle *v;
01964 CommandCost cost(EXPENSES_ROADVEH_RUN);
01965 CargoID new_cid = GB(p2, 0, 8);
01966 byte new_subtype = GB(p2, 8, 8);
01967 bool only_this = HasBit(p2, 16);
01968 uint16 capacity = CALLBACK_FAILED;
01969 uint total_capacity = 0;
01970
01971 if (!IsValidVehicleID(p1)) return CMD_ERROR;
01972
01973 v = GetVehicle(p1);
01974
01975 if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR;
01976 if (!v->IsStoppedInDepot()) return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE);
01977 if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_CAN_T_REFIT_DESTROYED_VEHICLE);
01978
01979 if (new_cid >= NUM_CARGO) return CMD_ERROR;
01980
01981 for (; v != NULL; v = (only_this ? NULL : v->Next())) {
01982
01983
01984
01985 if (!CanRefitTo(v->engine_type, new_cid)) continue;
01986
01987 const Engine *e = GetEngine(v->engine_type);
01988 if (!e->CanCarryCargo()) continue;
01989
01990 if (HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_REFIT_CAPACITY)) {
01991
01992 CargoID temp_cid = v->cargo_type;
01993 byte temp_subtype = v->cargo_subtype;
01994 v->cargo_type = new_cid;
01995 v->cargo_subtype = new_subtype;
01996
01997
01998 capacity = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, v->engine_type, v);
01999
02000
02001 v->cargo_type = temp_cid;
02002 v->cargo_subtype = temp_subtype;
02003 }
02004
02005 if (capacity == CALLBACK_FAILED) {
02006
02007
02008 CargoID old_cid = e->GetDefaultCargoType();
02009
02010
02011
02012
02013 capacity = GetVehicleProperty(v, 0x0F, e->u.road.capacity);
02014 switch (old_cid) {
02015 case CT_PASSENGERS: break;
02016 case CT_MAIL:
02017 case CT_GOODS: capacity *= 2; break;
02018 default: capacity *= 4; break;
02019 }
02020 switch (new_cid) {
02021 case CT_PASSENGERS: break;
02022 case CT_MAIL:
02023 case CT_GOODS: capacity /= 2; break;
02024 default: capacity /= 4; break;
02025 }
02026 }
02027
02028 total_capacity += capacity;
02029
02030 if (new_cid != v->cargo_type) {
02031 cost.AddCost(GetRefitCost(v->engine_type));
02032 }
02033
02034 if (flags & DC_EXEC) {
02035 v->cargo_cap = capacity;
02036 v->cargo.Truncate((v->cargo_type == new_cid) ? capacity : 0);
02037 v->cargo_type = new_cid;
02038 v->cargo_subtype = new_subtype;
02039 InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
02040 InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
02041 InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
02042 }
02043 }
02044
02045 if (flags & DC_EXEC) RoadVehUpdateCache(GetVehicle(p1)->First());
02046
02047 _returned_refit_capacity = total_capacity;
02048
02049 return cost;
02050 }