From 0748d540e8a981c7b9ff94fc950f7798711721e3 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 11 Sep 2021 23:50:04 +0100 Subject: [PATCH] Implement improved breakdown speed reductions for ships --- src/saveload/extended_ver_sl.cpp | 2 +- src/saveload/vehicle_sl.cpp | 1 + src/ship.h | 5 ++++- src/ship_cmd.cpp | 16 +++++++++++++++- src/ship_gui.cpp | 6 ++++++ src/vehicle.cpp | 9 ++++++++- src/vehicle_gui.cpp | 2 +- 7 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index 9892b347bf..941a2fbb8f 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -86,7 +86,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_TIMETABLES_START_TICKS, XSCF_NULL, 2, 2, "timetable_start_ticks", nullptr, nullptr, nullptr }, { XSLFI_TOWN_CARGO_ADJ, XSCF_IGNORABLE_UNKNOWN, 2, 2, "town_cargo_adj", nullptr, nullptr, nullptr }, { XSLFI_SIG_TUNNEL_BRIDGE, XSCF_NULL, 9, 9, "signal_tunnel_bridge", nullptr, nullptr, "XBSS" }, - { XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 7, 7, "improved_breakdowns", nullptr, nullptr, nullptr }, + { XSLFI_IMPROVED_BREAKDOWNS, XSCF_NULL, 8, 8, "improved_breakdowns", nullptr, nullptr, nullptr }, { XSLFI_CONSIST_BREAKDOWN_FLAG, XSCF_NULL, 1, 1, "consist_breakdown_flag", nullptr, nullptr, nullptr }, { XSLFI_TT_WAIT_IN_DEPOT, XSCF_NULL, 1, 1, "tt_wait_in_depot", nullptr, nullptr, nullptr }, { XSLFI_AUTO_TIMETABLE, XSCF_NULL, 5, 5, "auto_timetables", nullptr, nullptr, nullptr }, diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index c9d348bbef..6a28f5fae9 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -844,6 +844,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDDEQUE(Ship, path, SLE_UINT8, SLV_SHIP_PATH_CACHE, SL_MAX_VERSION), SLE_CONDVAR(Ship, rotation, SLE_UINT8, SLV_SHIP_ROTATION, SL_MAX_VERSION), SLE_CONDVAR_X(Ship, lost_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SHIP_LOST_COUNTER)), + SLE_CONDVAR_X(Ship, critical_breakdown_count, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_IMPROVED_BREAKDOWNS, 8)), SLE_CONDNULL(16, SLV_2, SLV_144), // old reserved space diff --git a/src/ship.h b/src/ship.h index e7bb2b312f..2993898bf9 100644 --- a/src/ship.h +++ b/src/ship.h @@ -32,6 +32,7 @@ struct Ship FINAL : public SpecializedVehicle { int16 rotation_x_pos; ///< NOSAVE: X Position before rotation. int16 rotation_y_pos; ///< NOSAVE: Y Position before rotation. uint8 lost_count; ///< Count of number of failed pathfinder attempts + byte critical_breakdown_count; ///< Counter for the number of critical breakdowns since last service /** We don't want GCC to zero our struct! It already is zeroed and has an index! */ Ship() : SpecializedVehicleBase() {} @@ -47,7 +48,9 @@ struct Ship FINAL : public SpecializedVehicle { Direction GetMapImageDirection() const { return this->rotation; } int GetDisplaySpeed() const { return this->cur_speed / 2; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; } - int GetCurrentMaxSpeed() const { return std::min(this->vcache.cached_max_speed, this->current_order.GetMaxSpeed() * 2); } + int GetEffectiveMaxSpeed() const; + int GetDisplayEffectiveMaxSpeed() const { return this->GetEffectiveMaxSpeed() / 2; } + int GetCurrentMaxSpeed() const { return std::min(this->GetEffectiveMaxSpeed(), this->current_order.GetMaxSpeed() * 2); } Money GetRunningCost() const; bool IsInDepot() const { return this->state == TRACK_BIT_DEPOT; } bool Tick(); diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 5e27654a7c..95e9cd7351 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -339,6 +339,20 @@ void Ship::UpdateDeltaXY() } } +int Ship::GetEffectiveMaxSpeed() const +{ + int max_speed = this->vcache.cached_max_speed; + + if (this->critical_breakdown_count == 0) return max_speed; + + for (uint i = 0; i < this->critical_breakdown_count; i++) { + max_speed = std::min(max_speed - (max_speed / 3) + 1, max_speed); + } + + /* clamp speed to be no less than lower of 5mph and 1/8 of base speed */ + return std::max(max_speed, std::min(10, (this->vcache.cached_max_speed + 7) >> 3)); +} + /** * Test-procedure for HasVehicleOnPos to check for any ships which are visible and not stopped by the player. */ @@ -439,7 +453,7 @@ static bool ShipAccelerate(Vehicle *v) uint spd; byte t; - spd = std::min(v->cur_speed + 1, v->vcache.cached_max_speed); + spd = std::min(v->cur_speed + 1, Ship::From(v)->GetEffectiveMaxSpeed()); spd = std::min(spd, v->current_order.GetMaxSpeed() * 2); if (v->breakdown_ctr == 1 && v->breakdown_type == BREAKDOWN_LOW_POWER && v->cur_speed > (v->breakdown_severity * ShipVehInfo(v->engine_type)->max_speed) >> 8) { diff --git a/src/ship_gui.cpp b/src/ship_gui.cpp index 2a061821ff..04b22a455e 100644 --- a/src/ship_gui.cpp +++ b/src/ship_gui.cpp @@ -16,6 +16,7 @@ #include "vehicle_func.h" #include "spritecache.h" #include "zoom_func.h" +#include "ship.h" #include "table/strings.h" @@ -84,4 +85,9 @@ void DrawShipDetails(const Vehicle *v, int left, int right, int y) /* Draw Transfer credits text */ SetDParam(0, v->cargo.FeederShare()); DrawString(left, right, y + 3 * FONT_HEIGHT_NORMAL + 3, STR_VEHICLE_INFO_FEEDER_CARGO_VALUE); + + if (Ship::From(v)->critical_breakdown_count > 0) { + SetDParam(0, Ship::From(v)->GetDisplayEffectiveMaxSpeed()); + DrawString(left, right, y + 4 * FONT_HEIGHT_NORMAL + 4, STR_NEED_REPAIR); + } } diff --git a/src/vehicle.cpp b/src/vehicle.cpp index db44f004bd..d9ffb0a0df 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -194,6 +194,8 @@ void VehicleServiceInDepot(Vehicle *v) } } else if (v->type == VEH_ROAD) { RoadVehicle::From(v)->critical_breakdown_count = 0; + } else if (v->type == VEH_SHIP) { + Ship::From(v)->critical_breakdown_count = 0; } v->vehstatus &= ~VS_AIRCRAFT_BROKEN; SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated @@ -231,7 +233,8 @@ bool Vehicle::NeedsServicing() const (this->reliability >= this->GetEngine()->reliability * (100 - this->service_interval) / 100) : (this->date_of_last_service + this->service_interval >= _date)) && !(this->type == VEH_TRAIN && HasBit(Train::From(this)->flags, VRF_NEED_REPAIR)) - && !(this->type == VEH_ROAD && RoadVehicle::From(this)->critical_breakdown_count > 0)) { + && !(this->type == VEH_ROAD && RoadVehicle::From(this)->critical_breakdown_count > 0) + && !(this->type == VEH_SHIP && Ship::From(this)->critical_breakdown_count > 0)) { return false; } @@ -2205,6 +2208,10 @@ bool Vehicle::HandleBreakdown() if (RoadVehicle::From(this)->critical_breakdown_count != 255) { RoadVehicle::From(this)->critical_breakdown_count++; } + } else if (this->type == VEH_SHIP) { + if (Ship::From(this)->critical_breakdown_count != 255) { + Ship::From(this)->critical_breakdown_count++; + } } } /* FALL THROUGH */ diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 2a727a394d..bd3337acdf 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2823,7 +2823,7 @@ struct VehicleDetailsWindow : Window { break; case VEH_SHIP: - size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM; + size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + 4 + WD_FRAMERECT_BOTTOM; break; case VEH_AIRCRAFT: