roadveh_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: roadveh_cmd.cpp 17598 2009-09-21 15:41:58Z 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)
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 (++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) != 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 }

Generated on Thu Oct 1 11:03:16 2009 for OpenTTD by  doxygen 1.5.6