# roadveh_cmd.cpp

Go to the documentation of this file.

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