# roadveh_cmd.cpp

Go to the documentation of this file.

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