roadveh_cmd.cpp

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

Generated on Sat Apr 17 23:24:52 2010 for OpenTTD by  doxygen 1.6.1