Changeset - r27769:ebc238ecee04
[Not reviewed]
master
0 11 0
Tyler Trahan - 15 months ago 2023-08-06 16:57:10
tyler@tylertrahan.com
Fix #10334: Store separate newgrf-safe version of date_of_last_service. (#11124)

This value is not changed when the date cheat is used, which caused issues with changing properties based on service date.

Co-authored-by: Peter Nelson <peter1138@openttd.org>
11 files changed with 24 insertions and 3 deletions:
0 comments (0 inline, 0 general)
src/aircraft_cmd.cpp
Show inline comments
 
@@ -336,12 +336,13 @@ CommandCost CmdBuildAircraft(DoCommandFl
 
		v->targetairport = GetStationIndex(tile);
 
		v->SetNext(u);
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft);
 

	
 
		v->date_of_last_service = TimerGameCalendar::date;
 
		v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
		v->build_year = u->build_year = TimerGameCalendar::year;
 

	
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 

	
 
		v->random_bits = Random();
 
@@ -1554,12 +1555,13 @@ static void AircraftEventHandler_AtTermi
 
		/* on an airport with helipads, a helicopter will always land there
 
		 * and get serviced at the same time - setting */
 
		if (_settings_game.order.serviceathelipad) {
 
			if (v->subtype == AIR_HELICOPTER && apc->num_helipads > 0) {
 
				/* an excerpt of ServiceAircraft, without the invisibility stuff */
 
				v->date_of_last_service = TimerGameCalendar::date;
 
				v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
				v->breakdowns_since_last_service = 0;
 
				v->reliability = v->GetEngine()->reliability;
 
				SetWindowDirty(WC_VEHICLE_DETAILS, v->index);
 
			}
 
		}
 
		return;
src/articulated_vehicles.cpp
Show inline comments
 
@@ -395,12 +395,13 @@ void AddArticulatedParts(Vehicle *first)
 
		v->owner = first->owner;
 
		v->tile = first->tile;
 
		v->x_pos = first->x_pos;
 
		v->y_pos = first->y_pos;
 
		v->z_pos = first->z_pos;
 
		v->date_of_last_service = first->date_of_last_service;
 
		v->date_of_last_service_newgrf = first->date_of_last_service_newgrf;
 
		v->build_year = first->build_year;
 
		v->vehstatus = first->vehstatus & ~VS_STOPPED;
 

	
 
		v->cargo_subtype = 0;
 
		v->max_age = 0;
 
		v->engine_type = engine_type;
src/newgrf_engine.cpp
Show inline comments
 
@@ -594,13 +594,13 @@ static uint32_t VehicleGetVariable(Vehic
 

	
 
				default:
 
					return 0;
 
			}
 

	
 
		case 0x4B: // Long date of last service
 
			return v->date_of_last_service;
 
			return v->date_of_last_service_newgrf;
 

	
 
		case 0x4C: // Current maximum speed in NewGRF units
 
			if (!v->IsPrimaryVehicle()) return 0;
 
			return v->GetCurrentMaxSpeed();
 

	
 
		case 0x4D: // Position within articulated vehicle
 
@@ -764,14 +764,14 @@ static uint32_t VehicleGetVariable(Vehic
 
					case VEH_AIRCRAFT: ticks = Aircraft::From(v)->turn_counter; break;
 
					default:           ticks = 0; break;
 
				}
 
			}
 
			return (variable - 0x80) == 0x10 ? ticks : GB(ticks, 8, 8);
 
		}
 
		case 0x12: return ClampTo<uint16_t>(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR);
 
		case 0x13: return GB(ClampTo<uint16_t>(v->date_of_last_service - DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
 
		case 0x12: return ClampTo<uint16_t>(v->date_of_last_service_newgrf - DAYS_TILL_ORIGINAL_BASE_YEAR);
 
		case 0x13: return GB(ClampTo<uint16_t>(v->date_of_last_service_newgrf - DAYS_TILL_ORIGINAL_BASE_YEAR), 8, 8);
 
		case 0x14: return v->GetServiceInterval();
 
		case 0x15: return GB(v->GetServiceInterval(), 8, 8);
 
		case 0x16: return v->last_station_visited;
 
		case 0x17: return v->tick_counter;
 
		case 0x18:
 
		case 0x19: {
src/roadveh_cmd.cpp
Show inline comments
 
@@ -297,12 +297,13 @@ CommandCost CmdBuildRoadVehicle(DoComman
 
		v->reliability_spd_dec = e->reliability_spd_dec;
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->SetServiceInterval(Company::Get(v->owner)->settings.vehicle.servint_roadveh);
 

	
 
		v->date_of_last_service = TimerGameCalendar::date;
 
		v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
		v->build_year = TimerGameCalendar::year;
 

	
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = Random();
 
		v->SetFrontEngine();
 

	
src/saveload/afterload.cpp
Show inline comments
 
@@ -3231,12 +3231,19 @@ bool AfterLoadGame()
 
		/* We did load the "period" of the timer, but not the fired/elapsed. We can deduce that here. */
 
		extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
 
		_new_competitor_timeout.storage.elapsed = 0;
 
		_new_competitor_timeout.fired = _new_competitor_timeout.period == 0;
 
	}
 

	
 
	if (IsSavegameVersionBefore(SLV_NEWGRF_LAST_SERVICE)) {
 
		/* Set service date provided to NewGRF. */
 
		for (Vehicle *v : Vehicle::Iterate()) {
 
			v->date_of_last_service_newgrf = v->date_of_last_service;
 
		}
 
	}
 

	
 
	AfterLoadLabelMaps();
 
	AfterLoadCompanyStats();
 
	AfterLoadStoryBook();
 

	
 
	_gamelog.PrintDebug(1);
 

	
src/saveload/saveload.h
Show inline comments
 
@@ -355,12 +355,13 @@ enum SaveLoadVersion : uint16_t {
 
	SLV_DISASTER_VEH_STATE,                 ///< 312  PR#10798 Explicit storage of disaster vehicle state.
 
	SLV_SAVEGAME_ID,                        ///< 313  PR#10719 Add an unique ID to every savegame (used to deduplicate surveys).
 
	SLV_STRING_GAMELOG,                     ///< 314  PR#10801 Use std::string in gamelog.
 

	
 
	SLV_INDUSTRY_CARGO_REORGANISE,          ///< 315  PR#10853 Industry accepts/produced data reorganised.
 
	SLV_PERIODS_IN_TRANSIT_RENAME,          ///< 316  PR#11112 Rename days in transit to (cargo) periods in transit.
 
	SLV_NEWGRF_LAST_SERVICE,                ///< 317  PR#11124 Added stable date_of_last_service to avoid NewGRF trouble.
 

	
 
	SL_MAX_VERSION,                         ///< Highest possible saveload version
 
};
 

	
 
/** Save or load result codes. */
 
enum SaveOrLoadResult {
src/saveload/vehicle_sl.cpp
Show inline comments
 
@@ -672,12 +672,13 @@ public:
 
		SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
 
		SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   SLV_31, SL_MAX_VERSION),
 
		SLE_CONDVAR(Vehicle, max_age,               SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
 
		SLE_CONDVAR(Vehicle, max_age,               SLE_INT32,                   SLV_31, SL_MAX_VERSION),
 
		SLE_CONDVAR(Vehicle, date_of_last_service,  SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
 
		SLE_CONDVAR(Vehicle, date_of_last_service,  SLE_INT32,                   SLV_31, SL_MAX_VERSION),
 
		SLE_CONDVAR(Vehicle, date_of_last_service_newgrf, SLE_INT32,             SLV_NEWGRF_LAST_SERVICE, SL_MAX_VERSION),
 
		SLE_CONDVAR(Vehicle, service_interval,      SLE_UINT16,                   SL_MIN_VERSION,  SLV_31),
 
		SLE_CONDVAR(Vehicle, service_interval,      SLE_FILE_U32 | SLE_VAR_U16,  SLV_31, SLV_180),
 
		SLE_CONDVAR(Vehicle, service_interval,      SLE_UINT16,                 SLV_180, SL_MAX_VERSION),
 
		    SLE_VAR(Vehicle, reliability,           SLE_UINT16),
 
		    SLE_VAR(Vehicle, reliability_spd_dec,   SLE_UINT16),
 
		    SLE_VAR(Vehicle, breakdown_ctr,         SLE_UINT8),
src/ship_cmd.cpp
Show inline comments
 
@@ -900,12 +900,13 @@ CommandCost CmdBuildShip(DoCommandFlag f
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->state = TRACK_BIT_DEPOT;
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_ships);
 
		v->date_of_last_service = TimerGameCalendar::date;
 
		v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
		v->build_year = TimerGameCalendar::year;
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = Random();
 

	
 
		v->UpdateCache();
 

	
src/train_cmd.cpp
Show inline comments
 
@@ -651,12 +651,13 @@ static CommandCost CmdBuildRailWagon(DoC
 
		v->cargo_cap = rvi->capacity;
 
		v->refit_cap = 0;
 

	
 
		v->railtype = rvi->railtype;
 

	
 
		v->date_of_last_service = TimerGameCalendar::date;
 
		v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
		v->build_year = TimerGameCalendar::year;
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = Random();
 

	
 
		v->group_id = DEFAULT_GROUP;
 

	
 
@@ -716,12 +717,13 @@ static void AddRearEngineToMultiheadedTr
 
	u->cargo_subtype = v->cargo_subtype;
 
	u->cargo_cap = v->cargo_cap;
 
	u->refit_cap = v->refit_cap;
 
	u->railtype = v->railtype;
 
	u->engine_type = v->engine_type;
 
	u->date_of_last_service = v->date_of_last_service;
 
	u->date_of_last_service_newgrf = v->date_of_last_service_newgrf;
 
	u->build_year = v->build_year;
 
	u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
	u->random_bits = Random();
 
	v->SetMultiheaded();
 
	u->SetMultiheaded();
 
	v->SetNext(u);
 
@@ -780,12 +782,13 @@ CommandCost CmdBuildRailVehicle(DoComman
 
		v->max_age = e->GetLifeLengthInDays();
 

	
 
		v->railtype = rvi->railtype;
 

	
 
		v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
 
		v->date_of_last_service = TimerGameCalendar::date;
 
		v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
		v->build_year = TimerGameCalendar::year;
 
		v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
 
		v->random_bits = Random();
 

	
 
		if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
 
		v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
src/vehicle.cpp
Show inline comments
 
@@ -167,12 +167,13 @@ void VehicleServiceInDepot(Vehicle *v)
 
{
 
	assert(v != nullptr);
 
	SetWindowDirty(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
 

	
 
	do {
 
		v->date_of_last_service = TimerGameCalendar::date;
 
		v->date_of_last_service_newgrf = TimerGameCalendar::date;
 
		v->breakdowns_since_last_service = 0;
 
		v->reliability = v->GetEngine()->reliability;
 
		/* Prevent vehicles from breaking down directly after exiting the depot. */
 
		v->breakdown_chance /= 4;
 
		if (_settings_game.difficulty.vehicle_breakdowns == 1) v->breakdown_chance = 0; // on reduced breakdown
 
		v = v->Next();
 
@@ -758,12 +759,14 @@ uint32_t Vehicle::GetGRFID() const
 
 * This is useful if the date has been modified with the cheat menu.
 
 * @param interval Number of days to be added or substracted.
 
 */
 
void Vehicle::ShiftDates(int interval)
 
{
 
	this->date_of_last_service = std::max(this->date_of_last_service + interval, 0);
 
	/* date_of_last_service_newgrf is not updated here as it must stay stable
 
	 * for vehicles outside of a depot. */
 
}
 

	
 
/**
 
 * Handle the pathfinding result, especially the lost status.
 
 * If the vehicle is now lost and wasn't previously fire an
 
 * event to the AIs and a news message to the user. If the
src/vehicle_base.h
Show inline comments
 
@@ -285,12 +285,13 @@ public:
 

	
 
	/* Related to age and service time */
 
	TimerGameCalendar::Year build_year;           ///< Year the vehicle has been built.
 
	TimerGameCalendar::Date age;                  ///< Age in days
 
	TimerGameCalendar::Date max_age;              ///< Maximum age
 
	TimerGameCalendar::Date date_of_last_service; ///< Last date the vehicle had a service at a depot.
 
	TimerGameCalendar::Date date_of_last_service_newgrf; ///< Last date the vehicle had a service at a depot, unchanged by the date cheat to protect against unsafe NewGRF behavior.
 
	uint16_t reliability;                 ///< Reliability.
 
	uint16_t reliability_spd_dec;         ///< Reliability decrease speed.
 
	byte breakdown_ctr;                 ///< Counter for managing breakdown events. @see Vehicle::HandleBreakdown
 
	byte breakdown_delay;               ///< Counter for managing breakdown length.
 
	byte breakdowns_since_last_service; ///< Counter for the amount of breakdowns.
 
	byte breakdown_chance;              ///< Current chance of breakdowns.
0 comments (0 inline, 0 general)