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