roadveh_cmd.cpp

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

Generated on Wed Dec 30 20:40:05 2009 for OpenTTD by  doxygen 1.5.6