roadveh_cmd.cpp

Go to the documentation of this file.
00001 /* $Id: roadveh_cmd.cpp 19091 2010-02-10 21:28:26Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "landscape.h"
00014 #include "roadveh.h"
00015 #include "command_func.h"
00016 #include "news_func.h"
00017 #include "pathfinder/npf/npf_func.h"
00018 #include "station_base.h"
00019 #include "company_func.h"
00020 #include "vehicle_gui.h"
00021 #include "articulated_vehicles.h"
00022 #include "newgrf_engine.h"
00023 #include "newgrf_sound.h"
00024 #include "pathfinder/yapf/yapf.h"
00025 #include "strings_func.h"
00026 #include "tunnelbridge_map.h"
00027 #include "functions.h"
00028 #include "window_func.h"
00029 #include "date_func.h"
00030 #include "vehicle_func.h"
00031 #include "sound_func.h"
00032 #include "autoreplace_gui.h"
00033 #include "ai/ai.hpp"
00034 #include "depot_map.h"
00035 #include "effectvehicle_func.h"
00036 #include "effectvehicle_base.h"
00037 #include "roadstop_base.h"
00038 #include "cargotype.h"
00039 #include "spritecache.h"
00040 #include "core/random_func.hpp"
00041 #include "engine_base.h"
00042 #include "company_base.h"
00043 #include "engine_func.h"
00044 
00045 #include "table/strings.h"
00046 #include "table/sprites.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 
00083 static const Trackdir _roadveh_depot_exit_trackdir[DIAGDIR_END] = {
00084   TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW
00085 };
00086 
00087 
00092 bool RoadVehicle::IsBus() const
00093 {
00094   assert(this->IsRoadVehFront());
00095   return IsCargoInClass(this->cargo_type, CC_PASSENGERS);
00096 }
00097 
00103 int RoadVehicle::GetDisplayImageWidth(Point *offset) const
00104 {
00105   int reference_width = ROADVEHINFO_DEFAULT_VEHICLE_WIDTH;
00106 
00107   if (offset != NULL) {
00108     offset->x = reference_width / 2;
00109     offset->y = 0;
00110   }
00111   return this->rcache.cached_veh_length * reference_width / 8;
00112 }
00113 
00114 static SpriteID GetRoadVehIcon(EngineID engine)
00115 {
00116   const Engine *e = Engine::Get(engine);
00117   uint8 spritenum = e->u.road.image_index;
00118 
00119   if (is_custom_sprite(spritenum)) {
00120     SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W);
00121     if (sprite != 0) return sprite;
00122 
00123     spritenum = e->original_image_index;
00124   }
00125 
00126   return DIR_W + _roadveh_images[spritenum];
00127 }
00128 
00129 SpriteID RoadVehicle::GetImage(Direction direction) const
00130 {
00131   uint8 spritenum = this->spritenum;
00132   SpriteID sprite;
00133 
00134   if (is_custom_sprite(spritenum)) {
00135     sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)));
00136     if (sprite != 0) return sprite;
00137 
00138     spritenum = Engine::Get(this->engine_type)->original_image_index;
00139   }
00140 
00141   sprite = direction + _roadveh_images[spritenum];
00142 
00143   if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum];
00144 
00145   return sprite;
00146 }
00147 
00148 void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal)
00149 {
00150   SpriteID sprite = GetRoadVehIcon(engine);
00151   const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
00152   preferred_x = Clamp(preferred_x, left - real_sprite->x_offs, right - real_sprite->width - real_sprite->x_offs);
00153   DrawSprite(sprite, pal, preferred_x, y);
00154 }
00155 
00156 static uint GetRoadVehLength(const RoadVehicle *v)
00157 {
00158   uint length = 8;
00159 
00160   uint16 veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, v->engine_type, v);
00161   if (veh_len != CALLBACK_FAILED) {
00162     length -= Clamp(veh_len, 0, 7);
00163   }
00164 
00165   return length;
00166 }
00167 
00168 void RoadVehUpdateCache(RoadVehicle *v)
00169 {
00170   assert(v->type == VEH_ROAD);
00171   assert(v->IsRoadVehFront());
00172 
00173   v->InvalidateNewGRFCacheOfChain();
00174 
00175   v->rcache.cached_total_length = 0;
00176 
00177   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00178     /* Check the v->first cache. */
00179     assert(u->First() == v);
00180 
00181     /* Update the 'first engine' */
00182     u->rcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
00183 
00184     /* Update the length of the vehicle. */
00185     u->rcache.cached_veh_length = GetRoadVehLength(u);
00186     v->rcache.cached_total_length += u->rcache.cached_veh_length;
00187 
00188     /* Invalidate the vehicle colour map */
00189     u->colourmap = PAL_NONE;
00190   }
00191 }
00192 
00201 CommandCost CmdBuildRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00202 {
00203   if (!IsEngineBuildable(p1, VEH_ROAD, _current_company)) return_cmd_error(STR_ERROR_ROAD_VEHICLE_NOT_AVAILABLE);
00204 
00205   const Engine *e = Engine::Get(p1);
00206   /* Engines without valid cargo should not be available */
00207   if (e->GetDefaultCargoType() == CT_INVALID) return CMD_ERROR;
00208 
00209   CommandCost cost(EXPENSES_NEW_VEHICLES, e->GetCost());
00210   if (flags & DC_QUERY_COST) return cost;
00211 
00212   /* The ai_new queries the vehicle cost before building the route,
00213    * so we must check against cheaters no sooner than now. --pasky */
00214   if (!IsRoadDepotTile(tile)) return CMD_ERROR;
00215   if (!IsTileOwner(tile, _current_company)) return CMD_ERROR;
00216 
00217   if (HasTileRoadType(tile, ROADTYPE_TRAM) != HasBit(e->info.misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_ERROR_DEPOT_WRONG_DEPOT_TYPE);
00218 
00219   uint num_vehicles = 1 + CountArticulatedParts(p1, false);
00220 
00221   /* Allow for the front and the articulated parts */
00222   if (!Vehicle::CanAllocateItem(num_vehicles)) {
00223     return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
00224   }
00225 
00226   /* find the first free roadveh id */
00227   UnitID unit_num = (flags & DC_AUTOREPLACE) ? 0 : GetFreeUnitNumber(VEH_ROAD);
00228   if (unit_num > _settings_game.vehicle.max_roadveh) {
00229     return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
00230   }
00231 
00232   if (flags & DC_EXEC) {
00233     const RoadVehicleInfo *rvi = &e->u.road;
00234 
00235     RoadVehicle *v = new RoadVehicle();
00236     v->unitnumber = unit_num;
00237     v->direction = DiagDirToDir(GetRoadDepotDirection(tile));
00238     v->owner = _current_company;
00239 
00240     v->tile = tile;
00241     int x = TileX(tile) * TILE_SIZE + TILE_SIZE / 2;
00242     int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2;
00243     v->x_pos = x;
00244     v->y_pos = y;
00245     v->z_pos = GetSlopeZ(x, y);
00246 
00247     v->state = RVSB_IN_DEPOT;
00248     v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
00249 
00250     v->spritenum = rvi->image_index;
00251     v->cargo_type = e->GetDefaultCargoType();
00252     v->cargo_cap = rvi->capacity;
00253     v->value = cost.GetCost();
00254 
00255     v->last_station_visited = INVALID_STATION;
00256     v->max_speed = rvi->max_speed;
00257     v->engine_type = (EngineID)p1;
00258     v->rcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
00259 
00260     v->reliability = e->reliability;
00261     v->reliability_spd_dec = e->reliability_spd_dec;
00262     v->max_age = e->GetLifeLengthInDays();
00263     _new_vehicle_id = v->index;
00264 
00265     v->service_interval = Company::Get(v->owner)->settings.vehicle.servint_roadveh;
00266 
00267     v->date_of_last_service = _date;
00268     v->build_year = _cur_year;
00269 
00270     v->cur_image = SPR_IMG_QUERY;
00271     v->random_bits = VehicleRandomBits();
00272     v->SetRoadVehFront();
00273 
00274     v->roadtype = HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD;
00275     v->compatible_roadtypes = RoadTypeToRoadTypes(v->roadtype);
00276     v->rcache.cached_veh_length = 8;
00277 
00278     if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
00279 
00280     AddArticulatedParts(v);
00281     v->InvalidateNewGRFCacheOfChain();
00282 
00283     /* Call various callbacks after the whole consist has been constructed */
00284     for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00285       u->cargo_cap = GetVehicleCapacity(u);
00286       v->InvalidateNewGRFCache();
00287       u->InvalidateNewGRFCache();
00288     }
00289     RoadVehUpdateCache(v);
00290 
00291     VehicleMove(v, false);
00292 
00293     InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
00294     InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
00295     SetWindowDirty(WC_COMPANY, v->owner);
00296     if (IsLocalCompany()) {
00297       InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Road window
00298     }
00299 
00300     Company::Get(_current_company)->num_engines[p1]++;
00301 
00302     CheckConsistencyOfArticulatedVehicle(v);
00303   }
00304 
00305   return cost;
00306 }
00307 
00308 bool RoadVehicle::IsStoppedInDepot() const
00309 {
00310   TileIndex tile = this->tile;
00311 
00312   if (!IsRoadDepotTile(tile)) return false;
00313   if (this->IsRoadVehFront() && !(this->vehstatus & VS_STOPPED)) return false;
00314 
00315   for (const RoadVehicle *v = this; v != NULL; v = v->Next()) {
00316     if (v->state != RVSB_IN_DEPOT || v->tile != tile) return false;
00317   }
00318   return true;
00319 }
00320 
00329 CommandCost CmdSellRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00330 {
00331   RoadVehicle *v = RoadVehicle::GetIfValid(p1);
00332   if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00333 
00334   if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_SELL_DESTROYED_VEHICLE);
00335 
00336   if (!v->IsStoppedInDepot()) {
00337     return_cmd_error(STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT);
00338   }
00339 
00340   CommandCost ret(EXPENSES_NEW_VEHICLES, -v->value);
00341 
00342   if (flags & DC_EXEC) {
00343     delete v;
00344   }
00345 
00346   return ret;
00347 }
00348 
00349 static FindDepotData FindClosestRoadDepot(const RoadVehicle *v, int max_distance)
00350 {
00351   if (IsRoadDepotTile(v->tile)) return FindDepotData(v->tile, 0);
00352 
00353   switch (_settings_game.pf.pathfinder_for_roadvehs) {
00354     case VPF_NPF: return NPFRoadVehicleFindNearestDepot(v, max_distance);
00355     case VPF_YAPF: return YapfRoadVehicleFindNearestDepot(v, max_distance);
00356 
00357     default: NOT_REACHED();
00358   }
00359 }
00360 
00361 bool RoadVehicle::FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse)
00362 {
00363   FindDepotData rfdd = FindClosestRoadDepot(this, 0);
00364   if (rfdd.best_length == UINT_MAX) return false;
00365 
00366   if (location    != NULL) *location    = rfdd.tile;
00367   if (destination != NULL) *destination = GetDepotIndex(rfdd.tile);
00368 
00369   return true;
00370 }
00371 
00382 CommandCost CmdSendRoadVehToDepot(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00383 {
00384   if (p2 & DEPOT_MASS_SEND) {
00385     /* Mass goto depot requested */
00386     if (!ValidVLWFlags(p2 & VLW_MASK)) return CMD_ERROR;
00387     return SendAllVehiclesToDepot(VEH_ROAD, flags, p2 & DEPOT_SERVICE, _current_company, (p2 & VLW_MASK), p1);
00388   }
00389 
00390   RoadVehicle *v = RoadVehicle::GetIfValid(p1);
00391   if (v == NULL) return CMD_ERROR;
00392 
00393   return v->SendToDepot(flags, (DepotCommand)(p2 & DEPOT_COMMAND_MASK));
00394 }
00395 
00404 CommandCost CmdTurnRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00405 {
00406   RoadVehicle *v = RoadVehicle::GetIfValid(p1);
00407   if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
00408 
00409   if ((v->vehstatus & VS_STOPPED) ||
00410       (v->vehstatus & VS_CRASHED) ||
00411       v->breakdown_ctr != 0 ||
00412       v->overtaking != 0 ||
00413       v->state == RVSB_WORMHOLE ||
00414       v->IsInDepot() ||
00415       v->cur_speed < 5) {
00416     return CMD_ERROR;
00417   }
00418 
00419   if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) return CMD_ERROR;
00420 
00421   if (IsTileType(v->tile, MP_TUNNELBRIDGE) && DirToDiagDir(v->direction) == GetTunnelBridgeDirection(v->tile)) return CMD_ERROR;
00422 
00423   if (flags & DC_EXEC) v->reverse_ctr = 180;
00424 
00425   return CommandCost();
00426 }
00427 
00428 
00429 void RoadVehicle::MarkDirty()
00430 {
00431   for (Vehicle *v = this; v != NULL; v = v->Next()) {
00432     v->UpdateViewport(false, false);
00433   }
00434 }
00435 
00436 void RoadVehicle::UpdateDeltaXY(Direction direction)
00437 {
00438 #define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
00439   static const uint32 _delta_xy_table[8] = {
00440     MKIT(3, 3, -1, -1),
00441     MKIT(3, 7, -1, -3),
00442     MKIT(3, 3, -1, -1),
00443     MKIT(7, 3, -3, -1),
00444     MKIT(3, 3, -1, -1),
00445     MKIT(3, 7, -1, -3),
00446     MKIT(3, 3, -1, -1),
00447     MKIT(7, 3, -3, -1),
00448   };
00449 #undef MKIT
00450 
00451   uint32 x = _delta_xy_table[direction];
00452   this->x_offs        = GB(x,  0, 8);
00453   this->y_offs        = GB(x,  8, 8);
00454   this->x_extent      = GB(x, 16, 8);
00455   this->y_extent      = GB(x, 24, 8);
00456   this->z_extent      = 6;
00457 }
00458 
00459 static void DeleteLastRoadVeh(RoadVehicle *v)
00460 {
00461   Vehicle *u = v;
00462   for (; v->Next() != NULL; v = v->Next()) u = v;
00463   u->SetNext(NULL);
00464 
00465   /* Only leave the road stop when we're really gone. */
00466   if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
00467 
00468   delete v;
00469 }
00470 
00471 static byte SetRoadVehPosition(RoadVehicle *v, int x, int y, bool turned)
00472 {
00473   byte new_z, old_z;
00474 
00475   /* need this hint so it returns the right z coordinate on bridges. */
00476   v->x_pos = x;
00477   v->y_pos = y;
00478   new_z = GetSlopeZ(x, y);
00479 
00480   old_z = v->z_pos;
00481   v->z_pos = new_z;
00482 
00483   v->UpdateViewport(true, turned);
00484   return old_z;
00485 }
00486 
00487 static void RoadVehSetRandomDirection(RoadVehicle *v)
00488 {
00489   static const DirDiff delta[] = {
00490     DIRDIFF_45LEFT, DIRDIFF_SAME, DIRDIFF_SAME, DIRDIFF_45RIGHT
00491   };
00492 
00493   do {
00494     uint32 r = Random();
00495 
00496     v->direction = ChangeDir(v->direction, delta[r & 3]);
00497     SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
00498   } while ((v = v->Next()) != NULL);
00499 }
00500 
00501 static bool RoadVehIsCrashed(RoadVehicle *v)
00502 {
00503   v->crashed_ctr++;
00504   if (v->crashed_ctr == 2) {
00505     CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
00506   } else if (v->crashed_ctr <= 45) {
00507     if ((v->tick_counter & 7) == 0) RoadVehSetRandomDirection(v);
00508   } else if (v->crashed_ctr >= 2220 && !(v->tick_counter & 0x1F)) {
00509     bool ret = v->Next() != NULL;
00510     DeleteLastRoadVeh(v);
00511     return ret;
00512   }
00513 
00514   return true;
00515 }
00516 
00517 static Vehicle *EnumCheckRoadVehCrashTrain(Vehicle *v, void *data)
00518 {
00519   const Vehicle *u = (Vehicle*)data;
00520 
00521   return
00522     v->type == VEH_TRAIN &&
00523     abs(v->z_pos - u->z_pos) <= 6 &&
00524     abs(v->x_pos - u->x_pos) <= 4 &&
00525     abs(v->y_pos - u->y_pos) <= 4 ?
00526       v : NULL;
00527 }
00528 
00529 uint RoadVehicle::Crash(bool flooded)
00530 {
00531   uint pass = Vehicle::Crash(flooded);
00532   if (this->IsRoadVehFront()) {
00533     pass += 1; // driver
00534 
00535     /* If we're in a drive through road stop we ought to leave it */
00536     if (IsInsideMM(this->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END)) {
00537       RoadStop::GetByTile(this->tile, GetRoadStopType(this->tile))->Leave(this);
00538     }
00539   }
00540   this->crashed_ctr = flooded ? 2000 : 1; // max 2220, disappear pretty fast when flooded
00541   return pass;
00542 }
00543 
00544 static void RoadVehCrash(RoadVehicle *v)
00545 {
00546   uint pass = v->Crash();
00547 
00548   AI::NewEvent(v->owner, new AIEventVehicleCrashed(v->index, v->tile, AIEventVehicleCrashed::CRASH_RV_LEVEL_CROSSING));
00549 
00550   SetDParam(0, pass);
00551   AddVehicleNewsItem(
00552     (pass == 1) ?
00553       STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER : STR_NEWS_ROAD_VEHICLE_CRASH,
00554     NS_ACCIDENT,
00555     v->index
00556   );
00557 
00558   ModifyStationRatingAround(v->tile, v->owner, -160, 22);
00559   SndPlayVehicleFx(SND_12_EXPLOSION, v);
00560 }
00561 
00562 static bool RoadVehCheckTrainCrash(RoadVehicle *v)
00563 {
00564   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
00565     if (u->state == RVSB_WORMHOLE) continue;
00566 
00567     TileIndex tile = u->tile;
00568 
00569     if (!IsLevelCrossingTile(tile)) continue;
00570 
00571     if (HasVehicleOnPosXY(v->x_pos, v->y_pos, u, EnumCheckRoadVehCrashTrain)) {
00572       RoadVehCrash(v);
00573       return true;
00574     }
00575   }
00576 
00577   return false;
00578 }
00579 
00580 static void HandleBrokenRoadVeh(RoadVehicle *v)
00581 {
00582   if (v->breakdown_ctr != 1) {
00583     v->breakdown_ctr = 1;
00584     v->cur_speed = 0;
00585 
00586     if (v->breakdowns_since_last_service != 255)
00587       v->breakdowns_since_last_service++;
00588 
00589     v->MarkDirty();
00590     SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00591     SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
00592 
00593     if (!PlayVehicleSound(v, VSE_BREAKDOWN)) {
00594       SndPlayVehicleFx((_settings_game.game_creation.landscape != LT_TOYLAND) ?
00595         SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN, v);
00596     }
00597 
00598     if (!(v->vehstatus & VS_HIDDEN)) {
00599       EffectVehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE);
00600       if (u != NULL) u->animation_state = v->breakdown_delay * 2;
00601     }
00602   }
00603 
00604   if ((v->tick_counter & 1) == 0) {
00605     if (--v->breakdown_delay == 0) {
00606       v->breakdown_ctr = 0;
00607       v->MarkDirty();
00608       SetWindowDirty(WC_VEHICLE_VIEW, v->index);
00609     }
00610   }
00611 }
00612 
00613 TileIndex RoadVehicle::GetOrderStationLocation(StationID station)
00614 {
00615   if (station == this->last_station_visited) this->last_station_visited = INVALID_STATION;
00616 
00617   const Station *st = Station::Get(station);
00618   if (!CanVehicleUseStation(this, st)) {
00619     /* There is no stop left at the station, so don't even TRY to go there */
00620     this->IncrementOrderIndex();
00621     return 0;
00622   }
00623 
00624   return st->xy;
00625 }
00626 
00627 static void StartRoadVehSound(const RoadVehicle *v)
00628 {
00629   if (!PlayVehicleSound(v, VSE_START)) {
00630     SoundID s = RoadVehInfo(v->engine_type)->sfx;
00631     if (s == SND_19_BUS_START_PULL_AWAY && (v->tick_counter & 3) == 0)
00632       s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN;
00633     SndPlayVehicleFx(s, v);
00634   }
00635 }
00636 
00637 struct RoadVehFindData {
00638   int x;
00639   int y;
00640   const Vehicle *veh;
00641   Vehicle *best;
00642   uint best_diff;
00643   Direction dir;
00644 };
00645 
00646 static Vehicle *EnumCheckRoadVehClose(Vehicle *v, void *data)
00647 {
00648   static const int8 dist_x[] = { -4, -8, -4, -1, 4, 8, 4, 1 };
00649   static const int8 dist_y[] = { -4, -1, 4, 8, 4, 1, -4, -8 };
00650 
00651   RoadVehFindData *rvf = (RoadVehFindData*)data;
00652 
00653   short x_diff = v->x_pos - rvf->x;
00654   short y_diff = v->y_pos - rvf->y;
00655 
00656   if (v->type == VEH_ROAD &&
00657       !v->IsInDepot() &&
00658       abs(v->z_pos - rvf->veh->z_pos) < 6 &&
00659       v->direction == rvf->dir &&
00660       rvf->veh->First() != v->First() &&
00661       (dist_x[v->direction] >= 0 || (x_diff > dist_x[v->direction] && x_diff <= 0)) &&
00662       (dist_x[v->direction] <= 0 || (x_diff < dist_x[v->direction] && x_diff >= 0)) &&
00663       (dist_y[v->direction] >= 0 || (y_diff > dist_y[v->direction] && y_diff <= 0)) &&
00664       (dist_y[v->direction] <= 0 || (y_diff < dist_y[v->direction] && y_diff >= 0))) {
00665     uint diff = abs(x_diff) + abs(y_diff);
00666 
00667     if (diff < rvf->best_diff || (diff == rvf->best_diff && v->index < rvf->best->index)) {
00668       rvf->best = v;
00669       rvf->best_diff = diff;
00670     }
00671   }
00672 
00673   return NULL;
00674 }
00675 
00676 static RoadVehicle *RoadVehFindCloseTo(RoadVehicle *v, int x, int y, Direction dir, bool update_blocked_ctr = true)
00677 {
00678   RoadVehFindData rvf;
00679   RoadVehicle *front = v->First();
00680 
00681   if (front->reverse_ctr != 0) return NULL;
00682 
00683   rvf.x = x;
00684   rvf.y = y;
00685   rvf.dir = dir;
00686   rvf.veh = v;
00687   rvf.best_diff = UINT_MAX;
00688 
00689   if (front->state == RVSB_WORMHOLE) {
00690     FindVehicleOnPos(v->tile, &rvf, EnumCheckRoadVehClose);
00691     FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &rvf, EnumCheckRoadVehClose);
00692   } else {
00693     FindVehicleOnPosXY(x, y, &rvf, EnumCheckRoadVehClose);
00694   }
00695 
00696   /* This code protects a roadvehicle from being blocked for ever
00697    * If more than 1480 / 74 days a road vehicle is blocked, it will
00698    * drive just through it. The ultimate backup-code of TTD.
00699    * It can be disabled. */
00700   if (rvf.best_diff == UINT_MAX) {
00701     front->blocked_ctr = 0;
00702     return NULL;
00703   }
00704 
00705   if (update_blocked_ctr && ++front->blocked_ctr > 1480) return NULL;
00706 
00707   return RoadVehicle::From(rvf.best);
00708 }
00709 
00710 static void RoadVehArrivesAt(const RoadVehicle *v, Station *st)
00711 {
00712   if (v->IsBus()) {
00713     /* Check if station was ever visited before */
00714     if (!(st->had_vehicle_of_type & HVOT_BUS)) {
00715       st->had_vehicle_of_type |= HVOT_BUS;
00716       SetDParam(0, st->index);
00717       AddVehicleNewsItem(
00718         v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_BUS_ARRIVAL : STR_NEWS_FIRST_PASSENGER_TRAM_ARRIVAL,
00719         (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00720         v->index,
00721         st->index
00722       );
00723       AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00724     }
00725   } else {
00726     /* Check if station was ever visited before */
00727     if (!(st->had_vehicle_of_type & HVOT_TRUCK)) {
00728       st->had_vehicle_of_type |= HVOT_TRUCK;
00729       SetDParam(0, st->index);
00730       AddVehicleNewsItem(
00731         v->roadtype == ROADTYPE_ROAD ? STR_NEWS_FIRST_TRUCK_ARRIVAL : STR_NEWS_FIRST_CARGO_TRAM_ARRIVAL,
00732         (v->owner == _local_company) ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
00733         v->index,
00734         st->index
00735       );
00736       AI::NewEvent(v->owner, new AIEventStationFirstVehicle(st->index, v->index));
00737     }
00738   }
00739 }
00740 
00741 static int RoadVehAccelerate(RoadVehicle *v)
00742 {
00743   uint oldspeed = v->cur_speed;
00744   uint accel = 256 + (v->overtaking != 0 ? 256 : 0);
00745   uint spd = v->subspeed + accel;
00746 
00747   v->subspeed = (uint8)spd;
00748 
00749   int tempmax = v->max_speed;
00750   if (v->cur_speed > v->max_speed) {
00751     tempmax = v->cur_speed - (v->cur_speed / 10) - 1;
00752   }
00753 
00754   v->cur_speed = spd = Clamp(v->cur_speed + ((int)spd >> 8), 0, tempmax);
00755 
00756   /* Apply bridge speed limit */
00757   if (v->state == RVSB_WORMHOLE && !(v->vehstatus & VS_HIDDEN)) {
00758     v->cur_speed = min(v->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed * 2);
00759   }
00760 
00761   /* Update statusbar only if speed has changed to save CPU time */
00762   if (oldspeed != v->cur_speed) {
00763     if (_settings_client.gui.vehicle_speed) {
00764       SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
00765     }
00766   }
00767 
00768   /* Speed is scaled in the same manner as for trains. @see train_cmd.cpp */
00769   int scaled_spd = spd * 3 >> 2;
00770 
00771   scaled_spd += v->progress;
00772   v->progress = 0;
00773   return scaled_spd;
00774 }
00775 
00776 static Direction RoadVehGetNewDirection(const RoadVehicle *v, int x, int y)
00777 {
00778   static const Direction _roadveh_new_dir[] = {
00779     DIR_N , DIR_NW, DIR_W , INVALID_DIR,
00780     DIR_NE, DIR_N , DIR_SW, INVALID_DIR,
00781     DIR_E , DIR_SE, DIR_S
00782   };
00783 
00784   x = x - v->x_pos + 1;
00785   y = y - v->y_pos + 1;
00786 
00787   if ((uint)x > 2 || (uint)y > 2) return v->direction;
00788   return _roadveh_new_dir[y * 4 + x];
00789 }
00790 
00791 static Direction RoadVehGetSlidingDirection(const RoadVehicle *v, int x, int y)
00792 {
00793   Direction new_dir = RoadVehGetNewDirection(v, x, y);
00794   Direction old_dir = v->direction;
00795   DirDiff delta;
00796 
00797   if (new_dir == old_dir) return old_dir;
00798   delta = (DirDifference(new_dir, old_dir) > DIRDIFF_REVERSE ? DIRDIFF_45LEFT : DIRDIFF_45RIGHT);
00799   return ChangeDir(old_dir, delta);
00800 }
00801 
00802 struct OvertakeData {
00803   const RoadVehicle *u;
00804   const RoadVehicle *v;
00805   TileIndex tile;
00806   Trackdir trackdir;
00807 };
00808 
00809 static Vehicle *EnumFindVehBlockingOvertake(Vehicle *v, void *data)
00810 {
00811   const OvertakeData *od = (OvertakeData*)data;
00812 
00813   return
00814     v->type == VEH_ROAD && v->First() == v && v != od->u && v != od->v ?
00815       v : NULL;
00816 }
00817 
00824 static bool CheckRoadBlockedForOvertaking(OvertakeData *od)
00825 {
00826   TrackStatus ts = GetTileTrackStatus(od->tile, TRANSPORT_ROAD, od->v->compatible_roadtypes);
00827   TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts);
00828   TrackdirBits red_signals = TrackStatusToRedSignals(ts); // barred level crossing
00829   TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00830 
00831   /* Track does not continue along overtaking direction || track has junction || levelcrossing is barred */
00832   if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00833 
00834   /* Are there more vehicles on the tile except the two vehicles involved in overtaking */
00835   return HasVehicleOnPos(od->tile, od, EnumFindVehBlockingOvertake);
00836 }
00837 
00838 static void RoadVehCheckOvertake(RoadVehicle *v, RoadVehicle *u)
00839 {
00840   OvertakeData od;
00841 
00842   od.v = v;
00843   od.u = u;
00844 
00845   if (u->max_speed >= v->max_speed &&
00846       !(u->vehstatus & VS_STOPPED) &&
00847       u->cur_speed != 0) {
00848     return;
00849   }
00850 
00851   /* Trams can't overtake other trams */
00852   if (v->roadtype == ROADTYPE_TRAM) return;
00853 
00854   /* Don't overtake in stations */
00855   if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
00856 
00857   /* For now, articulated road vehicles can't overtake anything. */
00858   if (v->HasArticulatedPart()) return;
00859 
00860   /* Vehicles are not driving in same direction || direction is not a diagonal direction */
00861   if (v->direction != u->direction || !(v->direction & 1)) return;
00862 
00863   /* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
00864   if (v->state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->state & RVSB_TRACKDIR_MASK))) return;
00865 
00866   od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
00867 
00868   /* Are the current and the next tile suitable for overtaking?
00869    *  - Does the track continue along od.trackdir
00870    *  - No junctions
00871    *  - No barred levelcrossing
00872    *  - No other vehicles in the way
00873    */
00874   od.tile = v->tile;
00875   if (CheckRoadBlockedForOvertaking(&od)) return;
00876 
00877   od.tile = v->tile + TileOffsByDiagDir(DirToDiagDir(v->direction));
00878   if (CheckRoadBlockedForOvertaking(&od)) return;
00879 
00880   if (od.u->cur_speed == 0 || (od.u->vehstatus & VS_STOPPED)) {
00881     v->overtaking_ctr = 0x11;
00882     v->overtaking = 0x10;
00883   } else {
00884 //    if (CheckRoadBlockedForOvertaking(&od)) return;
00885     v->overtaking_ctr = 0;
00886     v->overtaking = 0x10;
00887   }
00888 }
00889 
00890 static void RoadZPosAffectSpeed(RoadVehicle *v, byte old_z)
00891 {
00892   if (old_z == v->z_pos) return;
00893 
00894   if (old_z < v->z_pos) {
00895     v->cur_speed = v->cur_speed * 232 / 256; // slow down by ~10%
00896   } else {
00897     uint16 spd = v->cur_speed + 2;
00898     if (spd <= v->max_speed) v->cur_speed = spd;
00899   }
00900 }
00901 
00902 static int PickRandomBit(uint bits)
00903 {
00904   uint i;
00905   uint num = RandomRange(CountBits(bits));
00906 
00907   for (i = 0; !(bits & 1) || (int)--num >= 0; bits >>= 1, i++) {}
00908   return i;
00909 }
00910 
00919 static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection enterdir)
00920 {
00921 #define return_track(x) { best_track = (Trackdir)x; goto found_best_track; }
00922 
00923   TileIndex desttile;
00924   Trackdir best_track;
00925 
00926   TrackStatus ts = GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes);
00927   TrackdirBits red_signals = TrackStatusToRedSignals(ts); // crossing
00928   TrackdirBits trackdirs = TrackStatusToTrackdirBits(ts);
00929 
00930   if (IsTileType(tile, MP_ROAD)) {
00931     if (IsRoadDepot(tile) && (!IsTileOwner(tile, v->owner) || GetRoadDepotDirection(tile) == enterdir || (GetRoadTypes(tile) & v->compatible_roadtypes) == 0)) {
00932       /* Road depot owned by another company or with the wrong orientation */
00933       trackdirs = TRACKDIR_BIT_NONE;
00934     }
00935   } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
00936     /* Standard road stop (drive-through stops are treated as normal road) */
00937 
00938     if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
00939       /* different station owner or wrong orientation or the vehicle has articulated parts */
00940       trackdirs = TRACKDIR_BIT_NONE;
00941     } else {
00942       /* Our station */
00943       RoadStopType rstype = v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK;
00944 
00945       if (GetRoadStopType(tile) != rstype) {
00946         /* Wrong station type */
00947         trackdirs = TRACKDIR_BIT_NONE;
00948       } else {
00949         /* Proper station type, check if there is free loading bay */
00950         if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) &&
00951             !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) {
00952           /* Station is full and RV queuing is off */
00953           trackdirs = TRACKDIR_BIT_NONE;
00954         }
00955       }
00956     }
00957   }
00958   /* The above lookups should be moved to GetTileTrackStatus in the
00959    * future, but that requires more changes to the pathfinder and other
00960    * stuff, probably even more arguments to GTTS.
00961    */
00962 
00963   /* Remove tracks unreachable from the enter dir */
00964   trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
00965   if (trackdirs == TRACKDIR_BIT_NONE) {
00966     /* No reachable tracks, so we'll reverse */
00967     return_track(_road_reverse_table[enterdir]);
00968   }
00969 
00970   if (v->reverse_ctr != 0) {
00971     bool reverse = true;
00972     if (v->roadtype == ROADTYPE_TRAM) {
00973       /* Trams may only reverse on a tile if it contains at least the straight
00974        * trackbits or when it is a valid turning tile (i.e. one roadbit) */
00975       RoadBits rb = GetAnyRoadBits(tile, ROADTYPE_TRAM);
00976       RoadBits straight = AxisToRoadBits(DiagDirToAxis(enterdir));
00977       reverse = ((rb & straight) == straight) ||
00978                 (rb == DiagDirToRoadBits(enterdir));
00979     }
00980     if (reverse) {
00981       v->reverse_ctr = 0;
00982       if (v->tile != tile) {
00983         return_track(_road_reverse_table[enterdir]);
00984       }
00985     }
00986   }
00987 
00988   desttile = v->dest_tile;
00989   if (desttile == 0) {
00990     /* We've got no destination, pick a random track */
00991     return_track(PickRandomBit(trackdirs));
00992   }
00993 
00994   /* Only one track to choose between? */
00995   if (KillFirstBit(trackdirs) == TRACKDIR_BIT_NONE) {
00996     return_track(FindFirstBit2x64(trackdirs));
00997   }
00998 
00999   switch (_settings_game.pf.pathfinder_for_roadvehs) {
01000     case VPF_NPF: return_track(NPFRoadVehicleChooseTrack(v, tile, enterdir, trackdirs));
01001     case VPF_YAPF: return_track(YapfRoadVehicleChooseTrack(v, tile, enterdir, trackdirs));
01002 
01003     default: NOT_REACHED();
01004   }
01005 
01006 found_best_track:;
01007 
01008   if (HasBit(red_signals, best_track)) return INVALID_TRACKDIR;
01009 
01010   return best_track;
01011 }
01012 
01013 struct RoadDriveEntry {
01014   byte x, y;
01015 };
01016 
01017 #include "table/roadveh_movement.h"
01018 
01019 static const byte _road_veh_data_1[] = {
01020   20, 20, 16, 16, 0, 0, 0, 0,
01021   19, 19, 15, 15, 0, 0, 0, 0,
01022   16, 16, 12, 12, 0, 0, 0, 0,
01023   15, 15, 11, 11
01024 };
01025 
01026 static bool RoadVehLeaveDepot(RoadVehicle *v, bool first)
01027 {
01028   /* Don't leave if not all the wagons are in the depot. */
01029   for (const RoadVehicle *u = v; u != NULL; u = u->Next()) {
01030     if (u->state != RVSB_IN_DEPOT || u->tile != v->tile) return false;
01031   }
01032 
01033   DiagDirection dir = GetRoadDepotDirection(v->tile);
01034   v->direction = DiagDirToDir(dir);
01035 
01036   Trackdir tdir = _roadveh_depot_exit_trackdir[dir];
01037   const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + tdir];
01038 
01039   int x = TileX(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].x & 0xF);
01040   int y = TileY(v->tile) * TILE_SIZE + (rdp[RVC_DEPOT_START_FRAME].y & 0xF);
01041 
01042   if (first) {
01043     if (RoadVehFindCloseTo(v, x, y, v->direction, false) != NULL) return true;
01044 
01045     VehicleServiceInDepot(v);
01046 
01047     StartRoadVehSound(v);
01048 
01049     /* Vehicle is about to leave a depot */
01050     v->cur_speed = 0;
01051   }
01052 
01053   v->vehstatus &= ~VS_HIDDEN;
01054   v->state = tdir;
01055   v->frame = RVC_DEPOT_START_FRAME;
01056 
01057   SetRoadVehPosition(v, x, y, true);
01058 
01059   InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
01060 
01061   return true;
01062 }
01063 
01064 static Trackdir FollowPreviousRoadVehicle(const RoadVehicle *v, const RoadVehicle *prev, TileIndex tile, DiagDirection entry_dir, bool already_reversed)
01065 {
01066   if (prev->tile == v->tile && !already_reversed) {
01067     /* If the previous vehicle is on the same tile as this vehicle is
01068      * then it must have reversed. */
01069     return _road_reverse_table[entry_dir];
01070   }
01071 
01072   byte prev_state = prev->state;
01073   Trackdir dir;
01074 
01075   if (prev_state == RVSB_WORMHOLE || prev_state == RVSB_IN_DEPOT) {
01076     DiagDirection diag_dir = INVALID_DIAGDIR;
01077 
01078     if (IsTileType(tile, MP_TUNNELBRIDGE)) {
01079       diag_dir = GetTunnelBridgeDirection(tile);
01080     } else if (IsRoadDepotTile(tile)) {
01081       diag_dir = ReverseDiagDir(GetRoadDepotDirection(tile));
01082     }
01083 
01084     if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
01085     dir = DiagDirToDiagTrackdir(diag_dir);
01086   } else {
01087     if (already_reversed && prev->tile != tile) {
01088       /*
01089        * The vehicle has reversed, but did not go straight back.
01090        * It immediatelly turn onto another tile. This means that
01091        * the roadstate of the previous vehicle cannot be used
01092        * as the direction we have to go with this vehicle.
01093        *
01094        * Next table is build in the following way:
01095        *  - first row for when the vehicle in front went to the northern or
01096        *    western tile, second for southern and eastern.
01097        *  - columns represent the entry direction.
01098        *  - cell values are determined by the Trackdir one has to take from
01099        *    the entry dir (column) to the tile in north or south by only
01100        *    going over the trackdirs used for turning 90 degrees, i.e.
01101        *    TRACKDIR_{UPPER,RIGHT,LOWER,LEFT}_{N,E,S,W}.
01102        */
01103       static const Trackdir reversed_turn_lookup[2][DIAGDIR_END] = {
01104         { TRACKDIR_UPPER_W, TRACKDIR_RIGHT_N, TRACKDIR_LEFT_N,  TRACKDIR_UPPER_E },
01105         { TRACKDIR_RIGHT_S, TRACKDIR_LOWER_W, TRACKDIR_LOWER_E, TRACKDIR_LEFT_S  }};
01106       dir = reversed_turn_lookup[prev->tile < tile ? 0 : 1][ReverseDiagDir(entry_dir)];
01107     } else if (HasBit(prev_state, RVS_IN_DT_ROAD_STOP)) {
01108       dir = (Trackdir)(prev_state & RVSB_ROAD_STOP_TRACKDIR_MASK);
01109     } else if (prev_state < TRACKDIR_END) {
01110       dir = (Trackdir)prev_state;
01111     } else {
01112       return INVALID_TRACKDIR;
01113     }
01114   }
01115 
01116   /* Do some sanity checking. */
01117   static const RoadBits required_roadbits[] = {
01118     ROAD_X,            ROAD_Y,            ROAD_NW | ROAD_NE, ROAD_SW | ROAD_SE,
01119     ROAD_NW | ROAD_SW, ROAD_NE | ROAD_SE, ROAD_X,            ROAD_Y
01120   };
01121   RoadBits required = required_roadbits[dir & 0x07];
01122 
01123   if ((required & GetAnyRoadBits(tile, v->roadtype, true)) == ROAD_NONE) {
01124     dir = INVALID_TRACKDIR;
01125   }
01126 
01127   return dir;
01128 }
01129 
01137 static bool CanBuildTramTrackOnTile(CompanyID c, TileIndex t, RoadBits r)
01138 {
01139   /* The 'current' company is not necessarily the owner of the vehicle. */
01140   CompanyID original_company = _current_company;
01141   _current_company = c;
01142 
01143   CommandCost ret = DoCommand(t, ROADTYPE_TRAM << 4 | r, 0, DC_NONE, CMD_BUILD_ROAD);
01144 
01145   _current_company = original_company;
01146   return ret.Succeeded();
01147 }
01148 
01149 static bool IndividualRoadVehicleController(RoadVehicle *v, const RoadVehicle *prev)
01150 {
01151   if (v->overtaking != 0)  {
01152     if (IsTileType(v->tile, MP_STATION)) {
01153       /* Force us to be not overtaking! */
01154       v->overtaking = 0;
01155     } else if (++v->overtaking_ctr >= 35) {
01156       /* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
01157        *  if the vehicle started a corner. To protect that, only allow an abort of
01158        *  overtake if we are on straight roads */
01159       if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01160         v->overtaking = 0;
01161       }
01162     }
01163   }
01164 
01165   /* If this vehicle is in a depot and we've reached this point it must be
01166    * one of the articulated parts. It will stay in the depot until activated
01167    * by the previous vehicle in the chain when it gets to the right place. */
01168   if (v->IsInDepot()) return true;
01169 
01170   if (v->state == RVSB_WORMHOLE) {
01171     /* Vehicle is entering a depot or is on a bridge or in a tunnel */
01172     GetNewVehiclePosResult gp = GetNewVehiclePos(v);
01173 
01174     if (v->IsRoadVehFront()) {
01175       const Vehicle *u = RoadVehFindCloseTo(v, gp.x, gp.y, v->direction);
01176       if (u != NULL) {
01177         v->cur_speed = u->First()->cur_speed;
01178         return false;
01179       }
01180     }
01181 
01182     if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
01183       /* Vehicle has just entered a bridge or tunnel */
01184       SetRoadVehPosition(v, gp.x, gp.y, true);
01185       return true;
01186     }
01187 
01188     v->x_pos = gp.x;
01189     v->y_pos = gp.y;
01190     VehicleMove(v, !(v->vehstatus & VS_HIDDEN));
01191     return true;
01192   }
01193 
01194   /* Get move position data for next frame.
01195    * For a drive-through road stop use 'straight road' move data.
01196    * In this case v->state is masked to give the road stop entry direction. */
01197   RoadDriveEntry rd = _road_drive_data[v->roadtype][(
01198     (HasBit(v->state, RVS_IN_DT_ROAD_STOP) ? v->state & RVSB_ROAD_STOP_TRACKDIR_MASK : v->state) +
01199     (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking][v->frame + 1];
01200 
01201   if (rd.x & RDE_NEXT_TILE) {
01202     TileIndex tile = v->tile + TileOffsByDiagDir((DiagDirection)(rd.x & 3));
01203     Trackdir dir;
01204 
01205     if (v->IsRoadVehFront()) {
01206       /* If this is the front engine, look for the right path. */
01207       dir = RoadFindPathToDest(v, tile, (DiagDirection)(rd.x & 3));
01208     } else {
01209       dir = FollowPreviousRoadVehicle(v, prev, tile, (DiagDirection)(rd.x & 3), false);
01210     }
01211 
01212     if (dir == INVALID_TRACKDIR) {
01213       if (!v->IsRoadVehFront()) error("Disconnecting road vehicle.");
01214       v->cur_speed = 0;
01215       return false;
01216     }
01217 
01218 again:
01219     uint start_frame = RVC_DEFAULT_START_FRAME;
01220     if (IsReversingRoadTrackdir(dir)) {
01221       /* Turning around */
01222       if (v->roadtype == ROADTYPE_TRAM) {
01223         /* Determine the road bits the tram needs to be able to turn around
01224          * using the 'big' corner loop. */
01225         RoadBits needed;
01226         switch (dir) {
01227           default: NOT_REACHED();
01228           case TRACKDIR_RVREV_NE: needed = ROAD_SW; break;
01229           case TRACKDIR_RVREV_SE: needed = ROAD_NW; break;
01230           case TRACKDIR_RVREV_SW: needed = ROAD_NE; break;
01231           case TRACKDIR_RVREV_NW: needed = ROAD_SE; break;
01232         }
01233         if ((v->Previous() != NULL && v->Previous()->tile == tile) ||
01234             (v->IsRoadVehFront() && IsNormalRoadTile(tile) && !HasRoadWorks(tile) &&
01235               (needed & GetRoadBits(tile, ROADTYPE_TRAM)) != ROAD_NONE)) {
01236           /*
01237            * Taking the 'big' corner for trams only happens when:
01238            * - The previous vehicle in this (articulated) tram chain is
01239            *   already on the 'next' tile, we just follow them regardless of
01240            *   anything. When it is NOT on the 'next' tile, the tram started
01241            *   doing a reversing turn when the piece of tram track on the next
01242            *   tile did not exist yet. Do not use the big tram loop as that is
01243            *   going to cause the tram to split up.
01244            * - Or the front of the tram can drive over the next tile.
01245            */
01246         } else if (!v->IsRoadVehFront() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01247           /*
01248            * Taking the 'small' corner for trams only happens when:
01249            * - We are not the from vehicle of an articulated tram.
01250            * - Or when the company cannot build on the next tile.
01251            *
01252            * The 'small' corner means that the vehicle is on the end of a
01253            * tram track and needs to start turning there. To do this properly
01254            * the tram needs to start at an offset in the tram turning 'code'
01255            * for 'big' corners. It furthermore does not go to the next tile,
01256            * so that needs to be fixed too.
01257            */
01258           tile = v->tile;
01259           start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01260         } else {
01261           /* The company can build on the next tile, so wait till (s)he does. */
01262           v->cur_speed = 0;
01263           return false;
01264         }
01265       } else if (IsNormalRoadTile(v->tile) && GetDisallowedRoadDirections(v->tile) != DRD_NONE) {
01266         v->cur_speed = 0;
01267         return false;
01268       } else {
01269         tile = v->tile;
01270       }
01271     }
01272 
01273     /* Get position data for first frame on the new tile */
01274     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(dir + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)) ^ v->overtaking];
01275 
01276     int x = TileX(tile) * TILE_SIZE + rdp[start_frame].x;
01277     int y = TileY(tile) * TILE_SIZE + rdp[start_frame].y;
01278 
01279     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01280     if (v->IsRoadVehFront()) {
01281       Vehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01282       if (u != NULL) {
01283         v->cur_speed = u->First()->cur_speed;
01284         return false;
01285       }
01286     }
01287 
01288     uint32 r = VehicleEnterTile(v, tile, x, y);
01289     if (HasBit(r, VETS_CANNOT_ENTER)) {
01290       if (!IsTileType(tile, MP_TUNNELBRIDGE)) {
01291         v->cur_speed = 0;
01292         return false;
01293       }
01294       /* Try an about turn to re-enter the previous tile */
01295       dir = _road_reverse_table[rd.x & 3];
01296       goto again;
01297     }
01298 
01299     if (IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) && IsTileType(v->tile, MP_STATION)) {
01300       if (IsReversingRoadTrackdir(dir) && IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01301         /* New direction is trying to turn vehicle around.
01302          * We can't turn at the exit of a road stop so wait.*/
01303         v->cur_speed = 0;
01304         return false;
01305       }
01306 
01307       /* If we are a drive through road stop and the next tile is of
01308        * the same road stop and the next tile isn't this one (i.e. we
01309        * are not reversing), then keep the reservation and state.
01310        * This way we will not be shortly unregister from the road
01311        * stop. It also makes it possible to load when on the edge of
01312        * two road stops; otherwise you could get vehicles that should
01313        * be loading but are not actually loading. */
01314       if (IsDriveThroughStopTile(v->tile) &&
01315           RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01316           v->tile != tile) {
01317         /* So, keep 'our' state */
01318         dir = (Trackdir)v->state;
01319       } else if (IsRoadStop(v->tile)) {
01320         /* We're not continuing our drive through road stop, so leave. */
01321         RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
01322       }
01323     }
01324 
01325     if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
01326       v->tile = tile;
01327       v->state = (byte)dir;
01328       v->frame = start_frame;
01329     }
01330     if (new_dir != v->direction) {
01331       v->direction = new_dir;
01332       v->cur_speed -= v->cur_speed >> 2;
01333     }
01334 
01335     RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01336     return true;
01337   }
01338 
01339   if (rd.x & RDE_TURNED) {
01340     /* Vehicle has finished turning around, it will now head back onto the same tile */
01341     Trackdir dir;
01342     uint turn_around_start_frame = RVC_TURN_AROUND_START_FRAME;
01343 
01344     RoadBits tram;
01345     if (v->roadtype == ROADTYPE_TRAM && !IsRoadDepotTile(v->tile) && HasExactlyOneBit(tram = GetAnyRoadBits(v->tile, ROADTYPE_TRAM, true))) {
01346       /*
01347        * The tram is turning around with one tram 'roadbit'. This means that
01348        * it is using the 'big' corner 'drive data'. However, to support the
01349        * trams to take a small corner, there is a 'turned' marker in the middle
01350        * of the turning 'drive data'. When the tram took the long corner, we
01351        * will still use the 'big' corner drive data, but we advance it one
01352        * frame. We furthermore set the driving direction so the turning is
01353        * going to be properly shown.
01354        */
01355       turn_around_start_frame = RVC_START_FRAME_AFTER_LONG_TRAM;
01356       switch (rd.x & 0x3) {
01357         default: NOT_REACHED();
01358         case DIAGDIR_NW: dir = TRACKDIR_RVREV_SE; break;
01359         case DIAGDIR_NE: dir = TRACKDIR_RVREV_SW; break;
01360         case DIAGDIR_SE: dir = TRACKDIR_RVREV_NW; break;
01361         case DIAGDIR_SW: dir = TRACKDIR_RVREV_NE; break;
01362       }
01363     } else {
01364       if (v->IsRoadVehFront()) {
01365         /* If this is the front engine, look for the right path. */
01366         dir = RoadFindPathToDest(v, v->tile, (DiagDirection)(rd.x & 3));
01367       } else {
01368         dir = FollowPreviousRoadVehicle(v, prev, v->tile, (DiagDirection)(rd.x & 3), true);
01369       }
01370     }
01371 
01372     if (dir == INVALID_TRACKDIR) {
01373       v->cur_speed = 0;
01374       return false;
01375     }
01376 
01377     const RoadDriveEntry *rdp = _road_drive_data[v->roadtype][(_settings_game.vehicle.road_side << RVS_DRIVE_SIDE) + dir];
01378 
01379     int x = TileX(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].x;
01380     int y = TileY(v->tile) * TILE_SIZE + rdp[turn_around_start_frame].y;
01381 
01382     Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01383     if (v->IsRoadVehFront() && RoadVehFindCloseTo(v, x, y, new_dir) != NULL) return false;
01384 
01385     uint32 r = VehicleEnterTile(v, v->tile, x, y);
01386     if (HasBit(r, VETS_CANNOT_ENTER)) {
01387       v->cur_speed = 0;
01388       return false;
01389     }
01390 
01391     v->state = dir;
01392     v->frame = turn_around_start_frame;
01393 
01394     if (new_dir != v->direction) {
01395       v->direction = new_dir;
01396       v->cur_speed -= v->cur_speed >> 2;
01397     }
01398 
01399     RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01400     return true;
01401   }
01402 
01403   /* This vehicle is not in a wormhole and it hasn't entered a new tile. If
01404    * it's on a depot tile, check if it's time to activate the next vehicle in
01405    * the chain yet. */
01406   if (v->Next() != NULL && IsRoadDepotTile(v->tile)) {
01407     if (v->frame == v->rcache.cached_veh_length + RVC_DEPOT_START_FRAME) {
01408       RoadVehLeaveDepot(v->Next(), false);
01409     }
01410   }
01411 
01412   /* Calculate new position for the vehicle */
01413   int x = (v->x_pos & ~15) + (rd.x & 15);
01414   int y = (v->y_pos & ~15) + (rd.y & 15);
01415 
01416   Direction new_dir = RoadVehGetSlidingDirection(v, x, y);
01417 
01418   if (v->IsRoadVehFront() && !IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END)) {
01419     /* Vehicle is not in a road stop.
01420      * Check for another vehicle to overtake */
01421     RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01422 
01423     if (u != NULL) {
01424       u = u->First();
01425       /* There is a vehicle in front overtake it if possible */
01426       if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01427       if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01428 
01429       /* In case an RV is stopped in a road stop, why not try to load? */
01430       if (v->cur_speed == 0 && IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01431           v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01432           v->owner == GetTileOwner(v->tile) && !v->current_order.IsType(OT_LEAVESTATION) &&
01433           GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK)) {
01434         Station *st = Station::GetByTile(v->tile);
01435         v->last_station_visited = st->index;
01436         RoadVehArrivesAt(v, st);
01437         v->BeginLoading();
01438       }
01439       return false;
01440     }
01441   }
01442 
01443   Direction old_dir = v->direction;
01444   if (new_dir != old_dir) {
01445     v->direction = new_dir;
01446     v->cur_speed -= (v->cur_speed >> 2);
01447     if (old_dir != v->state) {
01448       /* The vehicle is in a road stop */
01449       SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
01450       /* Note, return here means that the frame counter is not incremented
01451        * for vehicles changing direction in a road stop. This causes frames to
01452        * be repeated. (XXX) Is this intended? */
01453       return true;
01454     }
01455   }
01456 
01457   /* If the vehicle is in a normal road stop and the frame equals the stop frame OR
01458    * if the vehicle is in a drive-through road stop and this is the destination station
01459    * and it's the correct type of stop (bus or truck) and the frame equals the stop frame...
01460    * (the station test and stop type test ensure that other vehicles, using the road stop as
01461    * a through route, do not stop) */
01462   if (v->IsRoadVehFront() && ((IsInsideMM(v->state, RVSB_IN_ROAD_STOP, RVSB_IN_ROAD_STOP_END) &&
01463       _road_veh_data_1[v->state - RVSB_IN_ROAD_STOP + (_settings_game.vehicle.road_side << RVS_DRIVE_SIDE)] == v->frame) ||
01464       (IsInsideMM(v->state, RVSB_IN_DT_ROAD_STOP, RVSB_IN_DT_ROAD_STOP_END) &&
01465       v->current_order.ShouldStopAtStation(v, GetStationIndex(v->tile)) &&
01466       v->owner == GetTileOwner(v->tile) &&
01467       GetRoadStopType(v->tile) == (v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK) &&
01468       v->frame == RVC_DRIVE_THROUGH_STOP_FRAME))) {
01469 
01470     RoadStop *rs = RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile));
01471     Station *st = Station::GetByTile(v->tile);
01472 
01473     /* Vehicle is at the stop position (at a bay) in a road stop.
01474      * Note, if vehicle is loading/unloading it has already been handled,
01475      * so if we get here the vehicle has just arrived or is just ready to leave. */
01476     if (!v->current_order.IsType(OT_LEAVESTATION)) {
01477       /* Vehicle has arrived at a bay in a road stop */
01478 
01479       if (IsDriveThroughStopTile(v->tile)) {
01480         TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01481 
01482         /* Check if next inline bay is free and has compatible road. */
01483         if (RoadStop::IsDriveThroughRoadStopContinuation(v->tile, next_tile) && (GetRoadTypes(next_tile) & v->compatible_roadtypes) != 0) {
01484           v->frame++;
01485           RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, false));
01486           return true;
01487         }
01488       }
01489 
01490       rs->SetEntranceBusy(false);
01491 
01492       v->last_station_visited = st->index;
01493 
01494       if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) {
01495         RoadVehArrivesAt(v, st);
01496         v->BeginLoading();
01497         return false;
01498       }
01499     } else {
01500       /* Vehicle is ready to leave a bay in a road stop */
01501       if (rs->IsEntranceBusy()) {
01502         /* Road stop entrance is busy, so wait as there is nowhere else to go */
01503         v->cur_speed = 0;
01504         return false;
01505       }
01506       v->current_order.Free();
01507     }
01508 
01509     if (IsStandardRoadStopTile(v->tile)) rs->SetEntranceBusy(true);
01510 
01511     StartRoadVehSound(v);
01512     SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01513   }
01514 
01515   /* Check tile position conditions - i.e. stop position in depot,
01516    * entry onto bridge or into tunnel */
01517   uint32 r = VehicleEnterTile(v, v->tile, x, y);
01518   if (HasBit(r, VETS_CANNOT_ENTER)) {
01519     v->cur_speed = 0;
01520     return false;
01521   }
01522 
01523   if (v->current_order.IsType(OT_LEAVESTATION) && IsDriveThroughStopTile(v->tile)) {
01524     v->current_order.Free();
01525   }
01526 
01527   /* Move to next frame unless vehicle arrived at a stop position
01528    * in a depot or entered a tunnel/bridge */
01529   if (!HasBit(r, VETS_ENTERED_WORMHOLE)) v->frame++;
01530 
01531   RoadZPosAffectSpeed(v, SetRoadVehPosition(v, x, y, true));
01532   return true;
01533 }
01534 
01535 static bool RoadVehController(RoadVehicle *v)
01536 {
01537   /* decrease counters */
01538   v->tick_counter++;
01539   v->current_order_time++;
01540   if (v->reverse_ctr != 0) v->reverse_ctr--;
01541 
01542   /* handle crashed */
01543   if (v->vehstatus & VS_CRASHED) {
01544     return RoadVehIsCrashed(v);
01545   }
01546 
01547   RoadVehCheckTrainCrash(v);
01548 
01549   /* road vehicle has broken down? */
01550   if (v->breakdown_ctr != 0) {
01551     if (v->breakdown_ctr <= 2) {
01552       HandleBrokenRoadVeh(v);
01553       return true;
01554     }
01555     if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
01556   }
01557 
01558   if (v->vehstatus & VS_STOPPED) return true;
01559 
01560   ProcessOrders(v);
01561   v->HandleLoading();
01562 
01563   if (v->current_order.IsType(OT_LOADING)) return true;
01564 
01565   if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01566 
01567   /* Check how far the vehicle needs to proceed */
01568   int j = RoadVehAccelerate(v);
01569 
01570   int adv_spd = (v->direction & 1) ? 192 : 256;
01571   while (j >= adv_spd) {
01572     j -= adv_spd;
01573 
01574     RoadVehicle *u = v;
01575     for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01576       if (!IndividualRoadVehicleController(u, prev)) break;
01577     }
01578 
01579     /* 192 spd used for going straight, 256 for going diagonally. */
01580     adv_spd = (v->direction & 1) ? 192 : 256;
01581 
01582     /* Test for a collision, but only if another movement will occur. */
01583     if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01584   }
01585 
01586   for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01587     if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01588 
01589     u->UpdateViewport(false, false);
01590   }
01591 
01592   if (v->progress == 0) v->progress = j;
01593 
01594   return true;
01595 }
01596 
01597 Money RoadVehicle::GetRunningCost() const
01598 {
01599   const Engine *e = Engine::Get(this->engine_type);
01600   if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01601 
01602   uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01603   if (cost_factor == 0) return 0;
01604 
01605   return GetPrice(e->u.road.running_cost_class, cost_factor, e->grffile);
01606 }
01607 
01608 bool RoadVehicle::Tick()
01609 {
01610   if (this->IsRoadVehFront()) {
01611     if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01612     return RoadVehController(this);
01613   }
01614 
01615   return true;
01616 }
01617 
01618 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01619 {
01620   /* If we already got a slot at a stop, use that FIRST, and go to a depot later */
01621   if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01622   if (v->IsInDepot()) {
01623     VehicleServiceInDepot(v);
01624     return;
01625   }
01626 
01627   uint max_penalty;
01628   switch (_settings_game.pf.pathfinder_for_roadvehs) {
01629     case VPF_NPF:  max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty;  break;
01630     case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01631     default: NOT_REACHED();
01632   }
01633 
01634   FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01635   /* Only go to the depot if it is not too far out of our way. */
01636   if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01637     if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01638       /* If we were already heading for a depot but it has
01639        * suddenly moved farther away, we continue our normal
01640        * schedule? */
01641       v->current_order.MakeDummy();
01642       SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01643     }
01644     return;
01645   }
01646 
01647   DepotID depot = GetDepotIndex(rfdd.tile);
01648 
01649   if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01650       v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01651       !Chance16(1, 20)) {
01652     return;
01653   }
01654 
01655   if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01656 
01657   v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01658   v->dest_tile = rfdd.tile;
01659   SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01660 }
01661 
01662 void RoadVehicle::OnNewDay()
01663 {
01664   if (!this->IsRoadVehFront()) return;
01665 
01666   if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01667   if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01668 
01669   AgeVehicle(this);
01670   CheckIfRoadVehNeedsService(this);
01671 
01672   CheckOrders(this);
01673 
01674   if (this->running_ticks == 0) return;
01675 
01676   CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01677 
01678   this->profit_this_year -= cost.GetCost();
01679   this->running_ticks = 0;
01680 
01681   SubtractMoneyFromCompanyFract(this->owner, cost);
01682 
01683   SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01684   SetWindowClassesDirty(WC_ROADVEH_LIST);
01685 }
01686 
01687 Trackdir RoadVehicle::GetVehicleTrackdir() const
01688 {
01689   if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01690 
01691   if (this->IsInDepot()) {
01692     /* We'll assume the road vehicle is facing outwards */
01693     return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01694   }
01695 
01696   if (IsStandardRoadStopTile(this->tile)) {
01697     /* We'll assume the road vehicle is facing outwards */
01698     return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile)); // Road vehicle in a station
01699   }
01700 
01701   /* Drive through road stops / wormholes (tunnels) */
01702   if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01703 
01704   /* If vehicle's state is a valid track direction (vehicle is not turning around) return it,
01705    * otherwise transform it into a valid track direction */
01706   return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01707 }
01708 
01709 
01721 CommandCost CmdRefitRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01722 {
01723   CargoID new_cid = GB(p2, 0, 8);
01724   byte new_subtype = GB(p2, 8, 8);
01725   bool only_this = HasBit(p2, 16);
01726 
01727   RoadVehicle *v = RoadVehicle::GetIfValid(p1);
01728 
01729   if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
01730   if (!v->IsStoppedInDepot()) return_cmd_error(STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT);
01731   if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_REFIT_DESTROYED_VEHICLE);
01732 
01733   if (new_cid >= NUM_CARGO) return CMD_ERROR;
01734 
01735   CommandCost cost = RefitVehicle(v, only_this, new_cid, new_subtype, flags);
01736 
01737   if (flags & DC_EXEC) {
01738     RoadVehicle *front = v->First();
01739     RoadVehUpdateCache(front);
01740     SetWindowDirty(WC_VEHICLE_DETAILS, front->index);
01741     SetWindowDirty(WC_VEHICLE_DEPOT, front->tile);
01742     InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
01743   } else {
01744     v->InvalidateNewGRFCacheOfChain(); // always invalidate; querycost might have filled it
01745   }
01746 
01747   return cost;
01748 }

Generated on Wed Mar 17 23:50:15 2010 for OpenTTD by  doxygen 1.6.1