# roadveh_cmd.cpp

Go to the documentation of this file.

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