roadveh_cmd.cpp

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

Generated on Mon May 11 15:48:06 2009 for OpenTTD by  doxygen 1.5.6