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