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