00001
00002
00003
00004
00005
00006
00007
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,
00073 TRACKDIR_BIT_LEFT_S | TRACKDIR_BIT_UPPER_E | TRACKDIR_BIT_Y_SE,
00074 TRACKDIR_BIT_UPPER_W | TRACKDIR_BIT_X_SW | TRACKDIR_BIT_RIGHT_S,
00075 TRACKDIR_BIT_RIGHT_N | TRACKDIR_BIT_LOWER_W | TRACKDIR_BIT_Y_NW
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
00179 assert(u->First() == v);
00180
00181
00182 u->rcache.first_engine = (v == u) ? INVALID_ENGINE : v->engine_type;
00183
00184
00185 u->rcache.cached_veh_length = GetRoadVehLength(u);
00186 v->rcache.cached_total_length += u->rcache.cached_veh_length;
00187
00188
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
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
00214
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
00223 if (!Vehicle::CanAllocateItem(num_vehicles)) {
00224 return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
00225 }
00226
00227
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;
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
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);
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
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->current_order.IsType(OT_LOADING)) {
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
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
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;
00535
00536
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;
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
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
00698
00699
00700
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
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
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
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
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
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);
00830 TrackBits trackbits = TrackdirBitsToTrackBits(trackdirbits);
00831
00832
00833 if (!HasBit(trackdirbits, od->trackdir) || (trackbits & ~TRACK_BIT_CROSS) || (red_signals != TRACKDIR_BIT_NONE)) return true;
00834
00835
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
00853 if (v->roadtype == ROADTYPE_TRAM) return;
00854
00855
00856 if (IsTileType(v->tile, MP_STATION) || IsTileType(u->tile, MP_STATION)) return;
00857
00858
00859 if (v->HasArticulatedPart()) return;
00860
00861
00862 if (v->direction != u->direction || !(v->direction & 1)) return;
00863
00864
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
00870
00871
00872
00873
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
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;
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);
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
00934 trackdirs = TRACKDIR_BIT_NONE;
00935 }
00936 } else if (IsTileType(tile, MP_STATION) && IsStandardRoadStopTile(tile)) {
00937
00938
00939 if (!IsTileOwner(tile, v->owner) || GetRoadStopDir(tile) == enterdir || v->HasArticulatedPart()) {
00940
00941 trackdirs = TRACKDIR_BIT_NONE;
00942 } else {
00943
00944 RoadStopType rstype = v->IsBus() ? ROADSTOP_BUS : ROADSTOP_TRUCK;
00945
00946 if (GetRoadStopType(tile) != rstype) {
00947
00948 trackdirs = TRACKDIR_BIT_NONE;
00949 } else {
00950
00951 if (!_settings_game.pf.roadveh_queue && IsStandardRoadStopTile(tile) &&
00952 !RoadStop::GetByTile(tile, rstype)->HasFreeBay()) {
00953
00954 trackdirs = TRACKDIR_BIT_NONE;
00955 }
00956 }
00957 }
00958 }
00959
00960
00961
00962
00963
00964
00965 trackdirs &= _road_enter_dir_to_reachable_trackdirs[enterdir];
00966 if (trackdirs == TRACKDIR_BIT_NONE) {
00967
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
00975
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
00992 return_track(PickRandomBit(trackdirs));
00993 }
00994
00995
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
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
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
01069
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
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
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
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
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
01155 v->overtaking = 0;
01156 } else if (++v->overtaking_ctr >= 35) {
01157
01158
01159
01160 if (v->state < RVSB_IN_ROAD_STOP && IsStraightRoadTrackdir((Trackdir)v->state)) {
01161 v->overtaking = 0;
01162 }
01163 }
01164 }
01165
01166
01167
01168
01169 if (v->IsInDepot()) return true;
01170
01171 if (v->state == RVSB_WORMHOLE) {
01172
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
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
01196
01197
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
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
01223 if (v->roadtype == ROADTYPE_TRAM) {
01224
01225
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
01239
01240
01241
01242
01243
01244
01245
01246
01247 } else if (!v->IsRoadVehFront() || !CanBuildTramTrackOnTile(v->owner, tile, needed) || ((~needed & GetAnyRoadBits(v->tile, ROADTYPE_TRAM, false)) == ROAD_NONE)) {
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259 tile = v->tile;
01260 start_frame = RVC_TURN_AROUND_START_FRAME_SHORT_TRAM;
01261 } else {
01262
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
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
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
01303
01304 v->cur_speed = 0;
01305 return false;
01306 }
01307
01308
01309
01310
01311
01312
01313
01314
01315 if (IsDriveThroughStopTile(v->tile) &&
01316 RoadStop::IsDriveThroughRoadStopContinuation(v->tile, tile) &&
01317 v->tile != tile) {
01318
01319 dir = (Trackdir)v->state;
01320 } else if (IsRoadStop(v->tile)) {
01321
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
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
01349
01350
01351
01352
01353
01354
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
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
01405
01406
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
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
01421
01422 RoadVehicle *u = RoadVehFindCloseTo(v, x, y, new_dir);
01423
01424 if (u != NULL) {
01425 u = u->First();
01426
01427 if (v->overtaking == 0) RoadVehCheckOvertake(v, u);
01428 if (v->overtaking == 0) v->cur_speed = u->cur_speed;
01429
01430
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
01450 SetRoadVehPosition(v, v->x_pos, v->y_pos, true);
01451
01452
01453
01454 return true;
01455 }
01456 }
01457
01458
01459
01460
01461
01462
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
01475
01476
01477 if (!v->current_order.IsType(OT_LEAVESTATION)) {
01478
01479
01480 if (IsDriveThroughStopTile(v->tile)) {
01481 TileIndex next_tile = TILE_ADD(v->tile, TileOffsByDir(v->direction));
01482
01483
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
01502 if (rs->IsEntranceBusy()) {
01503
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
01517
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
01529
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
01539 v->tick_counter++;
01540 v->current_order_time++;
01541 if (v->reverse_ctr != 0) v->reverse_ctr--;
01542
01543
01544 if (v->vehstatus & VS_CRASHED || RoadVehCheckTrainCrash(v)) {
01545 return RoadVehIsCrashed(v);
01546 }
01547
01548
01549 if (v->breakdown_ctr != 0) {
01550 if (v->breakdown_ctr <= 2) {
01551 HandleBrokenRoadVeh(v);
01552 return true;
01553 }
01554 if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--;
01555 }
01556
01557 if (v->vehstatus & VS_STOPPED) return true;
01558
01559 ProcessOrders(v);
01560 v->HandleLoading();
01561
01562 if (v->current_order.IsType(OT_LOADING)) return true;
01563
01564 if (v->IsInDepot() && RoadVehLeaveDepot(v, true)) return true;
01565
01566
01567 int j = RoadVehAccelerate(v);
01568
01569 int adv_spd = (v->direction & 1) ? 192 : 256;
01570 bool blocked = false;
01571 while (j >= adv_spd) {
01572 j -= adv_spd;
01573
01574 RoadVehicle *u = v;
01575 for (RoadVehicle *prev = NULL; u != NULL; prev = u, u = u->Next()) {
01576 if (!IndividualRoadVehicleController(u, prev)) {
01577 blocked = true;
01578 break;
01579 }
01580 }
01581 if (blocked) break;
01582
01583
01584 adv_spd = (v->direction & 1) ? 192 : 256;
01585
01586
01587 if (j >= adv_spd && RoadVehCheckTrainCrash(v)) break;
01588 }
01589
01590 for (RoadVehicle *u = v; u != NULL; u = u->Next()) {
01591 if ((u->vehstatus & VS_HIDDEN) != 0) continue;
01592
01593 u->UpdateViewport(false, false);
01594 }
01595
01596
01597
01598
01599 if (v->progress == 0) v->progress = blocked ? adv_spd - 1 : j;
01600
01601 return true;
01602 }
01603
01604 Money RoadVehicle::GetRunningCost() const
01605 {
01606 const Engine *e = Engine::Get(this->engine_type);
01607 if (e->u.road.running_cost_class == INVALID_PRICE) return 0;
01608
01609 uint cost_factor = GetVehicleProperty(this, PROP_ROADVEH_RUNNING_COST_FACTOR, e->u.road.running_cost);
01610 if (cost_factor == 0) return 0;
01611
01612 return GetPrice(e->u.road.running_cost_class, cost_factor, e->grffile);
01613 }
01614
01615 bool RoadVehicle::Tick()
01616 {
01617 if (this->IsRoadVehFront()) {
01618 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
01619 return RoadVehController(this);
01620 }
01621
01622 return true;
01623 }
01624
01625 static void CheckIfRoadVehNeedsService(RoadVehicle *v)
01626 {
01627
01628 if (Company::Get(v->owner)->settings.vehicle.servint_roadveh == 0 || !v->NeedsAutomaticServicing()) return;
01629 if (v->IsInDepot()) {
01630 VehicleServiceInDepot(v);
01631 return;
01632 }
01633
01634 uint max_penalty;
01635 switch (_settings_game.pf.pathfinder_for_roadvehs) {
01636 case VPF_NPF: max_penalty = _settings_game.pf.npf.maximum_go_to_depot_penalty; break;
01637 case VPF_YAPF: max_penalty = _settings_game.pf.yapf.maximum_go_to_depot_penalty; break;
01638 default: NOT_REACHED();
01639 }
01640
01641 FindDepotData rfdd = FindClosestRoadDepot(v, max_penalty);
01642
01643 if (rfdd.best_length == UINT_MAX || rfdd.best_length > max_penalty) {
01644 if (v->current_order.IsType(OT_GOTO_DEPOT)) {
01645
01646
01647
01648 v->current_order.MakeDummy();
01649 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01650 }
01651 return;
01652 }
01653
01654 DepotID depot = GetDepotIndex(rfdd.tile);
01655
01656 if (v->current_order.IsType(OT_GOTO_DEPOT) &&
01657 v->current_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS &&
01658 !Chance16(1, 20)) {
01659 return;
01660 }
01661
01662 if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
01663
01664 v->current_order.MakeGoToDepot(depot, ODTFB_SERVICE);
01665 v->dest_tile = rfdd.tile;
01666 SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
01667 }
01668
01669 void RoadVehicle::OnNewDay()
01670 {
01671 if (!this->IsRoadVehFront()) return;
01672
01673 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
01674 if (this->blocked_ctr == 0) CheckVehicleBreakdown(this);
01675
01676 AgeVehicle(this);
01677 CheckIfRoadVehNeedsService(this);
01678
01679 CheckOrders(this);
01680
01681 if (this->running_ticks == 0) return;
01682
01683 CommandCost cost(EXPENSES_ROADVEH_RUN, this->GetRunningCost() * this->running_ticks / (DAYS_IN_YEAR * DAY_TICKS));
01684
01685 this->profit_this_year -= cost.GetCost();
01686 this->running_ticks = 0;
01687
01688 SubtractMoneyFromCompanyFract(this->owner, cost);
01689
01690 SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
01691 SetWindowClassesDirty(WC_ROADVEH_LIST);
01692 }
01693
01694 Trackdir RoadVehicle::GetVehicleTrackdir() const
01695 {
01696 if (this->vehstatus & VS_CRASHED) return INVALID_TRACKDIR;
01697
01698 if (this->IsInDepot()) {
01699
01700 return DiagDirToDiagTrackdir(GetRoadDepotDirection(this->tile));
01701 }
01702
01703 if (IsStandardRoadStopTile(this->tile)) {
01704
01705 return DiagDirToDiagTrackdir(GetRoadStopDir(this->tile));
01706 }
01707
01708
01709 if (this->state > RVSB_TRACKDIR_MASK) return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
01710
01711
01712
01713 return (Trackdir)((IsReversingRoadTrackdir((Trackdir)this->state)) ? (this->state - 6) : this->state);
01714 }
01715
01716
01728 CommandCost CmdRefitRoadVeh(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
01729 {
01730 CargoID new_cid = GB(p2, 0, 8);
01731 byte new_subtype = GB(p2, 8, 8);
01732 bool only_this = HasBit(p2, 16);
01733
01734 RoadVehicle *v = RoadVehicle::GetIfValid(p1);
01735
01736 if (v == NULL || !CheckOwnership(v->owner)) return CMD_ERROR;
01737 if (!v->IsStoppedInDepot()) return_cmd_error(STR_ERROR_ROAD_VEHICLE_MUST_BE_STOPPED_INSIDE_DEPOT);
01738 if (v->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_CAN_T_REFIT_DESTROYED_VEHICLE);
01739
01740 if (new_cid >= NUM_CARGO) return CMD_ERROR;
01741
01742 CommandCost cost = RefitVehicle(v, only_this, new_cid, new_subtype, flags);
01743
01744 if (flags & DC_EXEC) {
01745 RoadVehicle *front = v->First();
01746 RoadVehUpdateCache(front);
01747 InvalidateWindowData(WC_VEHICLE_DETAILS, front->index);
01748 SetWindowDirty(WC_VEHICLE_DEPOT, front->tile);
01749 InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
01750 } else {
01751 v->InvalidateNewGRFCacheOfChain();
01752 }
01753
01754 return cost;
01755 }